Pushing up initial version of Rest.Net.

This commit is contained in:
MattMo 2022-02-06 19:22:24 -08:00
parent 7bac946ea3
commit dd82897982
68 changed files with 97993 additions and 0 deletions

View File

@ -0,0 +1,11 @@
{
"Version": 1,
"ProjectMap": {
"d476199d-526a-4831-866f-790676f8bc37": {
"ProjectGuid": "d476199d-526a-4831-866f-790676f8bc37",
"DisplayName": "Rest.Net.Example",
"ColorIndex": 0
}
},
"NextColorIndex": 1
}

Binary file not shown.

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rest.Net.Example", "Rest.Net.Example\Rest.Net.Example.csproj", "{D476199D-526A-4831-866F-790676F8BC37}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D476199D-526A-4831-866F-790676F8BC37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D476199D-526A-4831-866F-790676F8BC37}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D476199D-526A-4831-866F-790676F8BC37}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D476199D-526A-4831-866F-790676F8BC37}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {15F2CFE4-AA3C-4D24-BD82-FA12BDA760E6}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using Rest.Net;
namespace Rest.Net.Example
{
public class Program
{
public class User
{
public string Name = null;
public User(string name)
{
this.Name = name;
}
public static explicit operator User(string input)
{
return new User(input.ToString());
}
}
public static void Main(string[] args)
{
var listener = new RouteListener(8080,
new Route(HttpRequestMethod.Get, "/status", Status),
new Route<double, double>(HttpRequestMethod.Post, "/add/{a}/{b}", Add),
new Route<User>(HttpRequestMethod.Post, "/signup/{username}", Signup)
);
listener.Start();
Console.WriteLine($"Rest api server running at http://localhost:{listener.Port}");
listener.Block();
}
public static HttpListenerResponse Status(HttpListenerRequest request, HttpListenerResponse response)
{
return response.WithStatus(HttpStatusCode.OK).WithText("Everything is operational.");
}
public static HttpListenerResponse Add(HttpListenerRequest request, HttpListenerResponse response, double a, double b)
{
return response.WithStatus(HttpStatusCode.OK).WithText((a + b).ToString());
}
public static HttpListenerResponse Signup(HttpListenerRequest request, HttpListenerResponse response, User user)
{
return response.WithStatus(HttpStatusCode.OK).WithText("User:" + user.Name);
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Rest.Net.Example")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Rest.Net.Example")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d476199d-526a-4831-866f-790676f8bc37")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D476199D-526A-4831-866F-790676F8BC37}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Rest.Net.Example</RootNamespace>
<AssemblyName>Rest.Net.Example</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Rest.Net">
<HintPath>..\..\Rest.Net\Rest.Net\bin\Debug\Rest.Net.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Rest.Net</name>
</assembly>
<members>
<member name="T:Rest.Net.HttpRequestMethod">
<summary>
An enum containing the available http request methods.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
</summary>
</member>
<!-- Badly formed XML comment ignored for member "M:Rest.Net.RouteMatcher.Matches(System.String,System.String,System.String[]@)" -->
</members>
</doc>

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]

View File

@ -0,0 +1 @@
d0276b4748a99240167b771cb4684c9f3cd78e60

View File

@ -0,0 +1,14 @@
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Rest.Net.Example.exe.config
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Rest.Net.Example.exe
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Rest.Net.Example.pdb
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Rest.Net.dll
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Newtonsoft.Json.dll
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Rest.Net.pdb
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Rest.Net.xml
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\bin\Debug\Newtonsoft.Json.xml
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\obj\Debug\Rest.Net.Example.csproj.AssemblyReference.cache
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\obj\Debug\Rest.Net.Example.csproj.SuggestedBindingRedirects.cache
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\obj\Debug\Rest.Net.Example.csproj.CoreCompileInputs.cache
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\obj\Debug\Rest.Net.Example.csproj.CopyComplete
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\obj\Debug\Rest.Net.Example.exe
C:\Users\Matt\Desktop\Rest.Net\Rest.Net.Example\Rest.Net.Example\obj\Debug\Rest.Net.Example.pdb

View File

@ -0,0 +1,11 @@
{
"Version": 1,
"ProjectMap": {
"c885e940-05c8-43bb-b80b-02f6aaf1ae09": {
"ProjectGuid": "c885e940-05c8-43bb-b80b-02f6aaf1ae09",
"DisplayName": "Rest.Net",
"ColorIndex": 0
}
},
"NextColorIndex": 1
}

Binary file not shown.

25
Rest.Net/Rest.Net.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rest.Net", "Rest.Net\Rest.Net.csproj", "{C885E940-05C8-43BB-B80B-02F6AAF1AE09}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C885E940-05C8-43BB-B80B-02F6AAF1AE09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C885E940-05C8-43BB-B80B-02F6AAF1AE09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C885E940-05C8-43BB-B80B-02F6AAF1AE09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C885E940-05C8-43BB-B80B-02F6AAF1AE09}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D951ABAA-266B-4E0D-9E11-E6ABD08C8BAB}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Rest.Net
{
public static class HttpListenerRequestExtensions
{
public static string ReadAsString(this HttpListenerRequest request)
{
try
{
using (var input = request.InputStream)
using (var stream = new StreamReader(input))
return stream.ReadToEnd();
}
catch
{
return "";
}
}
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft.Json;
namespace Rest.Net
{
public static class HttpListenerResponseExtensions
{
public static HttpListenerResponse WithText(this HttpListenerResponse response, string text)
{
response.ContentType = "text/plain";
var bytes = Encoding.UTF8.GetBytes(text);
response.OutputStream.Write(bytes, 0, bytes.Length);
return response;
}
public static HttpListenerResponse WithJson(this HttpListenerResponse response, object obj)
{
response.ContentType = "application/json";
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj));
response.OutputStream.Write(bytes, 0, bytes.Length);
return response;
}
public static HttpListenerResponse WithFile(this HttpListenerResponse response, string filePath)
{
response.ContentType = "application/octet-stream";
response.Headers.Add("Content-Deposition", $@"attachment; filename=""{Path.GetFileName(filePath)}""");
response.SendChunked = true;
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var responseStream = response.OutputStream)
fileStream.CopyTo(responseStream);
return response;
}
public static HttpListenerResponse WithStatus(this HttpListenerResponse response, HttpStatusCode status)
{
try
{
response.StatusCode = (int)status;
return response;
}
catch
{
return response;
}
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rest.Net
{
internal static class StringExtensions
{
public static int Count(this string input, char c)
{
int count = 0;
int len = input.Length;
for (int i = 0; i < len; i++)
if (input[i] == c)
count++;
return count;
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rest.Net
{
/// <summary>
/// An enum containing the available http request methods.
///
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
/// </summary>
public enum HttpRequestMethod
{
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace,
Patch
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Rest.Net")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Rest.Net")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c885e940-05c8-43bb-b80b-02f6aaf1ae09")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C885E940-05C8-43BB-B80B-02F6AAF1AE09}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Rest.Net</RootNamespace>
<AssemblyName>Rest.Net</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>bin\Debug\Rest.Net.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions\HttpListenerRequestExtensions.cs" />
<Compile Include="Extensions\HttpListenerResponseExtensions.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="HttpRequestMethod.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Route.cs" />
<Compile Include="RouteArgumentConverter.cs" />
<Compile Include="RouteListener.cs" />
<Compile Include="RouteMatcher.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

262
Rest.Net/Rest.Net/Route.cs Normal file
View File

@ -0,0 +1,262 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
namespace Rest.Net
{
public class Route
{
public string Method;
public string Syntax;
private Func<HttpListenerRequest, HttpListenerResponse, HttpListenerResponse> Target;
public bool CloseResponse = true;
internal Route() { }
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public virtual void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.Invoke(request, response);
}
}
public class Route<T1> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(request, response, RouteArgumentConverter.Convert<T1>(arguments[0]));
}
}
public class Route<T1, T2> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1])
); ;
}
}
public class Route<T1, T2, T3> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1]),
RouteArgumentConverter.Convert<T3>(arguments[2])
);
}
}
public class Route<T1, T2, T3, T4> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1]),
RouteArgumentConverter.Convert<T3>(arguments[2]),
RouteArgumentConverter.Convert<T4>(arguments[3])
);
}
}
public class Route<T1, T2, T3, T4, T5> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1]),
RouteArgumentConverter.Convert<T3>(arguments[2]),
RouteArgumentConverter.Convert<T4>(arguments[3]),
RouteArgumentConverter.Convert<T4>(arguments[4])
);
}
}
public class Route<T1, T2, T3, T4, T5, T6> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1]),
RouteArgumentConverter.Convert<T3>(arguments[2]),
RouteArgumentConverter.Convert<T4>(arguments[3]),
RouteArgumentConverter.Convert<T4>(arguments[4]),
RouteArgumentConverter.Convert<T4>(arguments[5])
);
}
}
public class Route<T1, T2, T3, T4, T5, T6, T7> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, T7, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, T7, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, T7, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1]),
RouteArgumentConverter.Convert<T3>(arguments[2]),
RouteArgumentConverter.Convert<T4>(arguments[3]),
RouteArgumentConverter.Convert<T4>(arguments[4]),
RouteArgumentConverter.Convert<T4>(arguments[5]),
RouteArgumentConverter.Convert<T4>(arguments[6])
);
}
}
public class Route<T1, T2, T3, T4, T5, T6, T7, T8> : Route
{
private Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, T7, T8, HttpListenerResponse> Target;
public Route(string method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, T7, T8, HttpListenerResponse> target, bool closeResponse = true)
{
this.Method = method;
this.Syntax = syntax;
this.Target = target;
this.CloseResponse = closeResponse;
}
public Route(HttpRequestMethod method, string syntax, Func<HttpListenerRequest, HttpListenerResponse, T1, T2, T3, T4, T5, T6, T7, T8, HttpListenerResponse> target, bool closeResponse = true)
: this(method.ToString(), syntax, target, closeResponse) { }
public override void Invoke(HttpListenerRequest request, HttpListenerResponse response, params string[] arguments)
{
this.Target.DynamicInvoke(
request,
response,
RouteArgumentConverter.Convert<T1>(arguments[0]),
RouteArgumentConverter.Convert<T2>(arguments[1]),
RouteArgumentConverter.Convert<T3>(arguments[2]),
RouteArgumentConverter.Convert<T4>(arguments[3]),
RouteArgumentConverter.Convert<T4>(arguments[4]),
RouteArgumentConverter.Convert<T4>(arguments[5]),
RouteArgumentConverter.Convert<T4>(arguments[6]),
RouteArgumentConverter.Convert<T4>(arguments[7])
);
}
}
}

View File

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rest.Net
{
public class RouteArgumentConverter
{
public static T Convert<T>(string input)
{
var typeCode = Type.GetTypeCode(typeof(T));
if (typeCode == TypeCode.String)
{
return (dynamic)input;
}
else if (typeCode == TypeCode.Object)
{
var castOperator = typeof(T).GetMethod("op_Explicit", new[] { typeof(string) });
if (castOperator == null)
return default(T);
return (T)castOperator.Invoke(null, new[] { input });
}
else if (typeCode == TypeCode.Double)
{
double.TryParse(input, out double result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Single)
{
float.TryParse(input, out float result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Decimal)
{
decimal.TryParse(input, out decimal result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Int64)
{
long.TryParse(input, out long result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Int32)
{
int.TryParse(input, out int result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Int16)
{
short.TryParse(input, out short result);
return (dynamic)result;
}
else if (typeCode == TypeCode.SByte)
{
sbyte.TryParse(input, out sbyte result);
return (dynamic)result;
}
else if (typeCode == TypeCode.UInt64)
{
ulong.TryParse(input, out ulong result);
return (dynamic)result;
}
else if (typeCode == TypeCode.UInt32)
{
uint.TryParse(input, out uint result);
return (dynamic)result;
}
else if (typeCode == TypeCode.UInt16)
{
ushort.TryParse(input, out ushort result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Byte)
{
byte.TryParse(input, out byte result);
return (dynamic)result;
}
else if (typeCode == TypeCode.Boolean)
{
if (input == "f" || input == "0" || input == "F")
return (dynamic)false;
bool.TryParse(input, out bool result);
return ((dynamic)result);
}
else if (typeCode == TypeCode.DateTime)
{
DateTime.TryParse(input, out DateTime result);
return ((dynamic)result);
}
else if (typeCode == TypeCode.Char)
{
char.TryParse(input, out char result);
return ((dynamic)result);
}
return default(T);
}
}
}

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;
namespace Rest.Net
{
public class RouteListener
{
private HttpListener HttpListener = null;
public List<Route> Routes = new List<Route>();
public ushort Port = 8081;
public RouteListener()
{
}
public RouteListener(params Route[] routes)
{
this.Routes = routes.ToList();
}
public RouteListener(ushort port, params Route[] routes)
{
this.Routes = routes.ToList();
this.Port = port;
}
public void Start()
{
if (this.HttpListener == null)
{
this.HttpListener = new HttpListener();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
this.HttpListener.Prefixes.Add($"http://localhost:{this.Port}/");
this.HttpListener.Prefixes.Add($"http://127.0.0.1:{this.Port}/");
}
else
{
this.HttpListener.Prefixes.Add($"http://*:{this.Port}/");
}
this.HttpListener.Start();
this.Listen();
}
}
private void Listen()
{
ThreadPool.QueueUserWorkItem((o) =>
{
try
{
while (this.HttpListener.IsListening)
{
ThreadPool.QueueUserWorkItem((item) =>
{
var ctx = item as HttpListenerContext;
try
{
bool handled = false;
bool close = true;
string[] arguments = null;
for (int i = 0; i < this.Routes.Count; i++)
{
if (this.Routes[i].Method.ToUpper() == ctx.Request.HttpMethod.ToUpper() && RouteMatcher.Matches(ctx.Request.Url.AbsolutePath, this.Routes[i].Syntax, out arguments))
{
handled = true;
close = this.Routes[i].CloseResponse;
this.Routes[i].Invoke(ctx.Request, ctx.Response, arguments);
break;
}
}
if (!handled)
ctx.Response.WithStatus(HttpStatusCode.BadRequest);
if (close)
ctx.Response.Close();
}
catch (Exception ex)
{
ctx.Response.WithStatus(HttpStatusCode.InternalServerError);
ctx.Response.Close();
}
}, this.HttpListener.GetContext());
}
}
catch { }
});
}
public void Stop()
{
if (this.HttpListener != null)
{
this.HttpListener.Stop();
this.HttpListener = null;
}
}
public void Block()
{
while (this.HttpListener != null)
if (!Thread.Yield())
Thread.Sleep(1000);
}
}
}

View File

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Rest.Net
{
public class RouteMatcher
{
/// <summary>
/// Check to see if a url matches a given route syntax.
/// * = any path segment will match
/// ** = anything from this point forward is accepted
/// {} = route parameter
/// ! = must not match
/// || = logical or
/// && = logical and
///
/// Note:
/// If route parameter doesn't end with /, then the parameter will be the rest of the url.
/// Example:
/// </summary>
/// <param name="url"></param>
/// <param name="syntax"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static bool Matches(string url, string syntax, out string[] arguments)
{
//Set the arguments to null, initially.
arguments = null;
//Trim the url and the syntax.
url = url.Trim();
syntax = syntax.Trim();
//Split the url and the syntax into path segments
var urlSegments = url.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray();
var syntaxSegments = syntax.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray();
//If we have no syntax segments this is not a match.
if (syntaxSegments.Length == 0)
return false;
//If we have segments and the url does not then this may not be a match.
if (urlSegments.Length == 0 && syntaxSegments[0] == "**")
return true;
else if (urlSegments.Length == 0 && syntaxSegments.Length == 1 && syntaxSegments[0] == "*")
return true;
//Count the number of arguments in the syntax and set it.
arguments = new string[syntax.Count('{')];
int argumentIndex = 0;
//Check each segment against the url.
var max = Math.Min(urlSegments.Length, syntaxSegments.Length);
for (int i = 0; i < max; i++)
{
var syntaxSegment = syntaxSegments[i];
if (syntaxSegment == "**")
{
return true;
}
else if (syntaxSegment.StartsWith("{") && syntaxSegment.EndsWith("}") && i + 1 >= syntaxSegments.Length && syntax.EndsWith("/") == false)
{
//Special case, syntax ends with a parameter, so recombine the rest of the url and add it as a parameter.
var key = syntaxSegment.Substring(1, syntaxSegment.Length - 2);
var builder = new StringBuilder();
for (int i2 = i; i2 < urlSegments.Length; i2++)
builder.Append(urlSegments[i2]).Append(i2 + 1 < urlSegments.Length ? "/" : "");
arguments[argumentIndex++] = builder.ToString();
return true;
}
else if (SegmentMatches(urlSegments[i], syntaxSegment, arguments, ref argumentIndex) == false)
{
return false;
}
}
if (urlSegments.Length > syntaxSegments.Length)
return false;
else if (syntaxSegments.Length > urlSegments.Length)
return false;
else
return true;
}
private static bool SegmentMatches(string segment, string syntax, string[] arguments, ref int argumentIndex)
{
//Split the syntax into conditions
string[] conditions = syntax.Split(' ').Where(condition => condition.Length > 0).ToArray();
//Based off the matches, see if the segment matches.
bool match = false;
for (int i = 0; i < conditions.Length; i++)
{
var condition = conditions[i];
if (condition == "*")
{
match = true;
}
else if (condition == "**")
{
return true;
}
else if (condition.StartsWith("!"))
{
if (condition.Substring(1) == segment)
match = false;
else
match = true;
}
else if (condition.StartsWith("{") && condition.EndsWith("}"))
{
var key = condition.Substring(1, condition.Length - 2);
arguments[argumentIndex++] = segment;
match = true;
}
else if (condition == "&&")
{
if (match == false)
return false;
}
else if (condition == "||")
{
if (match)
return true;
}
else if (condition == segment)
{
return true;
}
}
return match;
}
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Rest.Net</name>
</assembly>
<members>
<member name="T:Rest.Net.HttpRequestMethod">
<summary>
An enum containing the available http request methods.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
</summary>
</member>
<!-- Badly formed XML comment ignored for member "M:Rest.Net.RouteMatcher.Matches(System.String,System.String,System.String[]@)" -->
</members>
</doc>

View File

@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]

View File

@ -0,0 +1 @@
5c49a708737996c207a7baff54b853b9eb847481

View File

@ -0,0 +1,9 @@
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\obj\Debug\Rest.Net.csproj.CoreCompileInputs.cache
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\bin\Debug\Rest.Net.dll
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\bin\Debug\Rest.Net.pdb
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\bin\Debug\Newtonsoft.Json.dll
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\bin\Debug\Newtonsoft.Json.xml
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\obj\Debug\Rest.Net.csproj.CopyComplete
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\obj\Debug\Rest.Net.dll
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\obj\Debug\Rest.Net.pdb
C:\Users\Matt\Desktop\Rest.Net\Rest.Net\Rest.Net\bin\Debug\Rest.Net.xml

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
</packages>

Binary file not shown.

View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2007 James Newton-King
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB