Compare commits
28 Commits
8467251a17
...
master
Author | SHA1 | Date | |
---|---|---|---|
3da97d4fff | |||
d0d64ef570 | |||
f116be9908 | |||
2c2b498223 | |||
bc82aeb8c2 | |||
670605ce91 | |||
a698e71e4b | |||
51b8ba073c | |||
b8e8e1dd86 | |||
cc83f99612 | |||
8747b5fb3e | |||
50861d5381 | |||
5f83b30cb2 | |||
38ef135b8a | |||
9633e211a1 | |||
b9260dbdb1 | |||
4c64f1c134 | |||
2f71c18b65 | |||
69a1d9c3a8 | |||
8c44d56ab4 | |||
4b05b1b6b9 | |||
7934f807ef | |||
36872164c5 | |||
dc1abd516b | |||
4617f861fc | |||
46aab308fa | |||
c2f60ff19f | |||
d96c44e542 |
@ -1,18 +1,16 @@
|
||||
//Generated using MontoyaTech.Rest.Net
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
//Generated using MontoyaTech.Rest.Net - 2/18/2024
|
||||
|
||||
public class Client
|
||||
{
|
||||
public string BaseUrl;
|
||||
|
||||
public CookieContainer CookieContainer;
|
||||
public System.Net.CookieContainer CookieContainer;
|
||||
|
||||
public HttpMessageHandler MessageHandler;
|
||||
public System.Net.Http.HttpMessageHandler MessageHandler;
|
||||
|
||||
public HttpClient HttpClient;
|
||||
public System.Net.Http.HttpClient HttpClient;
|
||||
|
||||
public System.Action<System.Net.Http.HttpRequestMessage> RequestHandler;
|
||||
|
||||
public TestApi Test;
|
||||
|
||||
@ -20,32 +18,36 @@ public class Client
|
||||
|
||||
public StreamApi Stream;
|
||||
|
||||
public Client(string baseUrl, HttpMessageHandler handler = null)
|
||||
public FormApi Form;
|
||||
|
||||
public Client(string baseUrl, System.Net.Http.HttpMessageHandler handler = null, System.Action<System.Net.Http.HttpRequestMessage> requestHandler = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||
throw new ArgumentException("baseUrl must not be null or whitespace.");
|
||||
throw new System.ArgumentException("baseUrl must not be null or whitespace.");
|
||||
|
||||
if (baseUrl.EndsWith('/'))
|
||||
baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
|
||||
|
||||
this.BaseUrl = baseUrl;
|
||||
|
||||
this.CookieContainer = new CookieContainer();
|
||||
this.CookieContainer = new System.Net.CookieContainer();
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
handler = new HttpClientHandler()
|
||||
handler = new System.Net.Http.HttpClientHandler()
|
||||
{
|
||||
AllowAutoRedirect = true,
|
||||
UseCookies = true,
|
||||
CookieContainer = this.CookieContainer,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
|
||||
};
|
||||
}
|
||||
|
||||
this.MessageHandler = handler;
|
||||
|
||||
this.HttpClient = new HttpClient(handler);
|
||||
this.RequestHandler = requestHandler;
|
||||
|
||||
this.HttpClient = new System.Net.Http.HttpClient(handler);
|
||||
|
||||
this.HttpClient.DefaultRequestHeaders.Add("Accept", "*/*");
|
||||
|
||||
@ -58,6 +60,8 @@ public class Client
|
||||
this.Auth = new AuthApi(this);
|
||||
|
||||
this.Stream = new StreamApi(this);
|
||||
|
||||
this.Form = new FormApi(this);
|
||||
}
|
||||
|
||||
public class TestApi
|
||||
@ -71,9 +75,11 @@ public class Client
|
||||
|
||||
public string Status()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/status");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/status");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -82,19 +88,21 @@ public class Client
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public string Add(double a, double b)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/add/{a}/{b}");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{this.Client.BaseUrl}/add/{a}/{b}");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -103,19 +111,21 @@ public class Client
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public string Compress()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/compress");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/compress");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -124,19 +134,21 @@ public class Client
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public string CompressFile()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/file/compress");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/file/compress");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -145,11 +157,11 @@ public class Client
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,9 +177,11 @@ public class Client
|
||||
|
||||
public bool UserExists(string name)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/auth/{name}");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/auth/{name}");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -180,27 +194,51 @@ public class Client
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public void Signup(UserDto request)
|
||||
public void Signup(UserDto request, bool compress = false)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/auth/signup");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{this.Client.BaseUrl}/auth/signup");
|
||||
|
||||
message.Content = new StringContent(JsonConvert.SerializeObject(request));
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
if (compress)
|
||||
{
|
||||
using (var uncompressedStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(request))))
|
||||
{
|
||||
using (var compressedStream = new System.IO.MemoryStream())
|
||||
{
|
||||
using (var gzipStream = new System.IO.Compression.GZipStream(compressedStream, System.IO.Compression.CompressionMode.Compress, true))
|
||||
uncompressedStream.CopyTo(gzipStream);
|
||||
|
||||
message.Content = new System.Net.Http.ByteArrayContent(compressedStream.ToArray());
|
||||
message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(System.Net.Mime.MediaTypeNames.Application.Json);
|
||||
message.Content.Headers.ContentEncoding.Add("gzip");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message.Content = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
||||
|
||||
message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(System.Net.Mime.MediaTypeNames.Application.Json);
|
||||
}
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
|
||||
public UserDto Get()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/auth");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/auth/");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -209,19 +247,44 @@ public class Client
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<UserDto>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<UserDto>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public dynamic Dynamic()
|
||||
{
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/auth/dynamic");
|
||||
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public UserRole GetRole()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/auth/role");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/auth/role");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -230,11 +293,11 @@ public class Client
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<UserRole>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<UserRole>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -248,25 +311,29 @@ public class Client
|
||||
this.Client = client;
|
||||
}
|
||||
|
||||
public void Upload(System.IO.MemoryStream request)
|
||||
public void Upload(System.IO.MemoryStream request, bool compress = false)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/upload");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{this.Client.BaseUrl}/upload");
|
||||
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
request.Seek(0, System.IO.SeekOrigin.Begin);
|
||||
|
||||
message.Content = new StreamContent(request);
|
||||
message.Content = new System.Net.Http.StreamContent(request);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
|
||||
public System.IO.MemoryStream Download()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/download");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{this.Client.BaseUrl}/download");
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -278,7 +345,40 @@ public class Client
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FormApi
|
||||
{
|
||||
public Client Client;
|
||||
|
||||
public FormApi(Client client)
|
||||
{
|
||||
this.Client = client;
|
||||
}
|
||||
|
||||
public System.Collections.Generic.Dictionary<string, string> FormTest()
|
||||
{
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{this.Client.BaseUrl}/form");
|
||||
|
||||
this.Client.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<System.Collections.Generic.Dictionary<string, string>>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,17 +8,25 @@ using System.IO;
|
||||
using MontoyaTech.Rest.Net;
|
||||
using System.Net.Mime;
|
||||
using System.Collections;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Web;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MontoyaTech.Rest.Net.Example
|
||||
{
|
||||
public class BaseUser
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id;
|
||||
|
||||
[JsonProperty("firstInitial")]
|
||||
public char FirstInitial;
|
||||
|
||||
[JsonProperty("role")]
|
||||
public UserRole Role { get; set; }
|
||||
|
||||
[JsonProperty("permissions")]
|
||||
public List<Permission> Permissions;
|
||||
|
||||
public class Permission
|
||||
@ -80,6 +88,7 @@ namespace MontoyaTech.Rest.Net.Example
|
||||
new Route<string>(HttpRequestMethod.Get, "/auth/{username}", Exists),
|
||||
new Route(HttpRequestMethod.Post, "/auth/signup", Signup),
|
||||
new Route(HttpRequestMethod.Get, "/auth/", Json),
|
||||
new Route(HttpRequestMethod.Get, "/auth/dynamic", Dynamic),
|
||||
new Route(HttpRequestMethod.Get, "/auth/role", GetRole),
|
||||
new Route(HttpRequestMethod.Post, "/upload", Upload),
|
||||
new Route(HttpRequestMethod.Get, "/download", Download),
|
||||
@ -90,11 +99,11 @@ namespace MontoyaTech.Rest.Net.Example
|
||||
|
||||
File.WriteAllText("Client.cs", listener.GenerateCSharpClient());
|
||||
|
||||
File.WriteAllText("Client.js", listener.GenerateJavascriptClient());
|
||||
File.WriteAllText("Client.js", listener.GenerateJavascriptClient(useJsonNames: true));
|
||||
|
||||
File.WriteAllText("StaticClient.cs", listener.GenerateCSharpClient("StaticClient", staticCode: true));
|
||||
|
||||
File.WriteAllText("StaticClient.js", listener.GenerateJavascriptClient("StaticClient", staticCode: true));
|
||||
File.WriteAllText("StaticClient.js", listener.GenerateJavascriptClient("StaticClient", staticCode: true, useJsonNames: true));
|
||||
|
||||
Console.WriteLine("Generated Client.cs, Client.js, StaticClient.cs, StaticClient.js");
|
||||
|
||||
@ -117,7 +126,18 @@ namespace MontoyaTech.Rest.Net.Example
|
||||
|
||||
Console.WriteLine($"Rest api server running at {listener.BaseUrl}");
|
||||
|
||||
StaticClient.Init(listener.BaseUrl);
|
||||
StaticClient.Init(listener.BaseUrl, requestHandler: (message) =>
|
||||
{
|
||||
var builder = new UriBuilder(message.RequestUri);
|
||||
|
||||
var query = HttpUtility.ParseQueryString(builder.Query);
|
||||
query.Add("authToken", "test");
|
||||
builder.Query = query.ToString();
|
||||
|
||||
message.RequestUri = builder.Uri;
|
||||
|
||||
message.Headers.Add("Auth", "Test");
|
||||
});
|
||||
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
@ -208,6 +228,13 @@ namespace MontoyaTech.Rest.Net.Example
|
||||
return context.Response.WithStatus(HttpStatusCode.OK).WithJson(new User("Rest.Net"));
|
||||
}
|
||||
|
||||
[RouteGroup("Auth")]
|
||||
[RouteResponse(Dynamic = true)]
|
||||
public static HttpListenerResponse Dynamic(HttpListenerContext context)
|
||||
{
|
||||
return context.Response.WithStatus(HttpStatusCode.OK).WithJson(777);
|
||||
}
|
||||
|
||||
[RouteGroup("Stream")]
|
||||
[RouteRequest(typeof(MemoryStream))]
|
||||
public static HttpListenerResponse Upload(HttpListenerContext context)
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<AssemblyName>MontoyaTech.Rest.Net.Example</AssemblyName>
|
||||
|
@ -1,45 +1,45 @@
|
||||
//Generated using MontoyaTech.Rest.Net
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Newtonsoft.Json;
|
||||
//Generated using MontoyaTech.Rest.Net - 2/18/2024
|
||||
|
||||
public class StaticClient
|
||||
{
|
||||
public static string BaseUrl;
|
||||
|
||||
public static CookieContainer CookieContainer;
|
||||
public static System.Net.CookieContainer CookieContainer;
|
||||
|
||||
public static HttpMessageHandler MessageHandler;
|
||||
public static System.Net.Http.HttpMessageHandler MessageHandler;
|
||||
|
||||
public static HttpClient HttpClient;
|
||||
public static System.Net.Http.HttpClient HttpClient;
|
||||
|
||||
public static void Init(string baseUrl, HttpMessageHandler handler = null)
|
||||
public static System.Action<System.Net.Http.HttpRequestMessage> RequestHandler;
|
||||
|
||||
public static void Init(string baseUrl, System.Net.Http.HttpMessageHandler handler = null, System.Action<System.Net.Http.HttpRequestMessage> requestHandler = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||
throw new ArgumentException("baseUrl must not be null or whitespace.");
|
||||
throw new System.ArgumentException("baseUrl must not be null or whitespace.");
|
||||
|
||||
if (baseUrl.EndsWith('/'))
|
||||
baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
|
||||
|
||||
StaticClient.BaseUrl = baseUrl;
|
||||
|
||||
StaticClient.CookieContainer = new CookieContainer();
|
||||
StaticClient.CookieContainer = new System.Net.CookieContainer();
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
handler = new HttpClientHandler()
|
||||
handler = new System.Net.Http.HttpClientHandler()
|
||||
{
|
||||
AllowAutoRedirect = true,
|
||||
UseCookies = true,
|
||||
CookieContainer = StaticClient.CookieContainer,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
|
||||
AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate
|
||||
};
|
||||
}
|
||||
|
||||
StaticClient.MessageHandler = handler;
|
||||
|
||||
StaticClient.HttpClient = new HttpClient(handler);
|
||||
StaticClient.RequestHandler = requestHandler;
|
||||
|
||||
StaticClient.HttpClient = new System.Net.Http.HttpClient(handler);
|
||||
|
||||
StaticClient.HttpClient.DefaultRequestHeaders.Add("Accept", "*/*");
|
||||
|
||||
@ -52,9 +52,11 @@ public class StaticClient
|
||||
{
|
||||
public static string Status()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/status");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/status");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -63,19 +65,21 @@ public class StaticClient
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Add(double a, double b)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{StaticClient.BaseUrl}/add/{a}/{b}");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{StaticClient.BaseUrl}/add/{a}/{b}");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -84,19 +88,21 @@ public class StaticClient
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Compress()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/compress");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/compress");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -105,19 +111,21 @@ public class StaticClient
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static string CompressFile()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/file/compress");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/file/compress");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -126,11 +134,11 @@ public class StaticClient
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,9 +147,11 @@ public class StaticClient
|
||||
{
|
||||
public static bool UserExists(string name)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/auth/{name}");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/auth/{name}");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -154,27 +164,51 @@ public class StaticClient
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Signup(UserDto request)
|
||||
public static void Signup(UserDto request, bool compress = false)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{StaticClient.BaseUrl}/auth/signup");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{StaticClient.BaseUrl}/auth/signup");
|
||||
|
||||
message.Content = new StringContent(JsonConvert.SerializeObject(request));
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
if (compress)
|
||||
{
|
||||
using (var uncompressedStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(request))))
|
||||
{
|
||||
using (var compressedStream = new System.IO.MemoryStream())
|
||||
{
|
||||
using (var gzipStream = new System.IO.Compression.GZipStream(compressedStream, System.IO.Compression.CompressionMode.Compress, true))
|
||||
uncompressedStream.CopyTo(gzipStream);
|
||||
|
||||
message.Content = new System.Net.Http.ByteArrayContent(compressedStream.ToArray());
|
||||
message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(System.Net.Mime.MediaTypeNames.Application.Json);
|
||||
message.Content.Headers.ContentEncoding.Add("gzip");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message.Content = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
||||
|
||||
message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(System.Net.Mime.MediaTypeNames.Application.Json);
|
||||
}
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
|
||||
public static UserDto Get()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/auth");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/auth/");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -183,19 +217,44 @@ public class StaticClient
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<UserDto>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<UserDto>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static dynamic Dynamic()
|
||||
{
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/auth/dynamic");
|
||||
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
public static UserRole GetRole()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/auth/role");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/auth/role");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -204,36 +263,40 @@ public class StaticClient
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return JsonConvert.DeserializeObject<UserRole>(content);
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<UserRole>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Stream
|
||||
{
|
||||
public static void Upload(System.IO.MemoryStream request)
|
||||
public static void Upload(System.IO.MemoryStream request, bool compress = false)
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{StaticClient.BaseUrl}/upload");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{StaticClient.BaseUrl}/upload");
|
||||
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
request.Seek(0, System.IO.SeekOrigin.Begin);
|
||||
|
||||
message.Content = new StreamContent(request);
|
||||
message.Content = new System.Net.Http.StreamContent(request);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
|
||||
public static System.IO.MemoryStream Download()
|
||||
{
|
||||
var message = new HttpRequestMessage(HttpMethod.Get, $"{StaticClient.BaseUrl}/download");
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, $"{StaticClient.BaseUrl}/download");
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@ -245,7 +308,33 @@ public class StaticClient
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Form
|
||||
{
|
||||
public static System.Collections.Generic.Dictionary<string, string> FormTest()
|
||||
{
|
||||
var message = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, $"{StaticClient.BaseUrl}/form");
|
||||
|
||||
StaticClient.RequestHandler?.Invoke(message);
|
||||
|
||||
var response = StaticClient.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
|
||||
if (string.IsNullOrEmpty(content))
|
||||
return default;
|
||||
|
||||
return Newtonsoft.Json.JsonConvert.DeserializeObject<System.Collections.Generic.Dictionary<string, string>>(content);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>disable</Nullable>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<IsPackable>false</IsPackable>
|
||||
@ -9,14 +9,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" Version="6.5.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PackageReference Include="FluentAssertions" Version="8.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
@ -8,7 +8,7 @@ using FluentAssertions;
|
||||
using MontoyaTech.Rest.Net;
|
||||
using System.Net;
|
||||
|
||||
namespace Rest.Net.Tests
|
||||
namespace MontoyaTech.Rest.Net.Tests
|
||||
{
|
||||
public class RestClientGeneratorTests
|
||||
{
|
||||
|
41
Rest.Net.Tests/RouteArgumentConverterTests.cs
Normal file
41
Rest.Net.Tests/RouteArgumentConverterTests.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using MontoyaTech.Rest.Net;
|
||||
using Xunit;
|
||||
|
||||
namespace Rest.Net.Tests
|
||||
{
|
||||
public class RouteArgumentConverterTests
|
||||
{
|
||||
public enum TestEnum : long
|
||||
{
|
||||
A = 1,
|
||||
B = 2,
|
||||
C = 3
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RouteArgumentConverter_Should_Convert_To_Enum()
|
||||
{
|
||||
var converted = RouteArgumentConverter.Convert<TestEnum>("1");
|
||||
|
||||
converted.GetType().IsEquivalentTo(typeof(TestEnum)).Should().BeTrue();
|
||||
|
||||
converted.Should().Be(TestEnum.A);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RouteArgumentConverter_Should_Convert_OutOfRange_To_Enum()
|
||||
{
|
||||
var converted = RouteArgumentConverter.Convert<TestEnum>("4");
|
||||
|
||||
converted.GetType().IsEquivalentTo(typeof(TestEnum)).Should().BeTrue();
|
||||
|
||||
((int)converted).Should().Be(4);
|
||||
}
|
||||
}
|
||||
}
|
@ -22,6 +22,12 @@ namespace MontoyaTech.Rest.Net.Tests
|
||||
RouteMatcher.Matches("http://localhost/", "/", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxWithRootNoSlashShouldMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost", "/", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxWithRootCatchAllShouldMatch()
|
||||
{
|
||||
@ -29,9 +35,33 @@ namespace MontoyaTech.Rest.Net.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxCatchAllEmptyShouldMatch()
|
||||
public void SyntaxNonSlashShouldNotMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/test1", "/test1/**", out _).Should().BeTrue();
|
||||
RouteMatcher.Matches("http://localhost/test1/", "/test1", out _).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxSlashShouldMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/test1/", "/test1/", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxSlashExtraRouteShouldNotMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/test1/test2", "/test1/", out _).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxSlashCatchAllEmptyShouldMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/test1/", "/test1/**", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SyntaxSlashCatchAllEmptyNoSlashShouldNotMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/test1", "/test1/**", out _).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -43,7 +73,7 @@ namespace MontoyaTech.Rest.Net.Tests
|
||||
[Fact]
|
||||
public void SyntaxWildCardEmptyShouldMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/test1", "/test1/*", out _).Should().BeTrue();
|
||||
RouteMatcher.Matches("http://localhost/test1/", "/test1/*", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -117,6 +147,7 @@ namespace MontoyaTech.Rest.Net.Tests
|
||||
public void SyntaxWithOrShouldMatch()
|
||||
{
|
||||
RouteMatcher.Matches("http://localhost/a/b", "/a/b|c", out _).Should().BeTrue();
|
||||
|
||||
RouteMatcher.Matches("http://localhost/a/c", "/a/b|c", out _).Should().BeTrue();
|
||||
}
|
||||
|
||||
|
178
Rest.Net.Tests/ServeFileTests.cs
Normal file
178
Rest.Net.Tests/ServeFileTests.cs
Normal file
@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using MontoyaTech.Rest.Net;
|
||||
using Xunit;
|
||||
|
||||
namespace MontoyaTech.Rest.Net.Tests
|
||||
{
|
||||
public class ServeFileTests
|
||||
{
|
||||
public string BaseDirectory = null;
|
||||
|
||||
public string TestDirectory = null;
|
||||
|
||||
public string TestFile = null;
|
||||
|
||||
public string IndexFile = null;
|
||||
|
||||
public ServeFileTests()
|
||||
{
|
||||
this.BaseDirectory = Path.Combine(Environment.CurrentDirectory, "test");
|
||||
|
||||
if (!Directory.Exists(this.BaseDirectory))
|
||||
Directory.CreateDirectory(this.BaseDirectory);
|
||||
|
||||
this.TestDirectory = Path.Combine(this.BaseDirectory, "test2");
|
||||
|
||||
if (!Directory.Exists(this.TestDirectory))
|
||||
Directory.CreateDirectory(this.TestDirectory);
|
||||
|
||||
this.TestFile = Path.Combine(this.BaseDirectory, "test.html");
|
||||
|
||||
if (!File.Exists(this.TestFile))
|
||||
File.WriteAllText(this.TestFile, "hello world");
|
||||
|
||||
this.IndexFile = Path.Combine(this.BaseDirectory, "index.html");
|
||||
|
||||
if (!File.Exists(this.IndexFile))
|
||||
File.WriteAllText(this.IndexFile, "hello world");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeMultiple_File_ShouldWork()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveMultiPagePath(this.BaseDirectory, null, "/test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeMultiple_Directory_ShouldWork()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveMultiPagePath(this.BaseDirectory, null, "/test2", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeTrue();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestDirectory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeMultiple_NavigatingUp_Should_NotWork()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveMultiPagePath(this.BaseDirectory, null, "../test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeMultiple_Correct_NavigatingUp_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveMultiPagePath(this.BaseDirectory, null, "a/b/../../test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeMultiple_NavigatingUp_Multiple_Should_NotWork()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveMultiPagePath(this.BaseDirectory, null, "test/../../test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_Empty_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.IndexFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_File_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_Directory_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/test2", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeTrue();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestDirectory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_File_Route_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/a/b/test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_Directory_Route_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/a/b/test2", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeTrue();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestDirectory);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_File_Route_Invalid_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/a/b/c", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.IndexFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_File_WithoutExtension_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/test", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_File_Route_WithoutExtension_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, null, "/a/b/c/test", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ServeSingle_File_StartPath_Should_Work()
|
||||
{
|
||||
HttpListenerResponseExtensions.ResolveSinglePagePath(this.BaseDirectory, "/test", "test/test.html", "index.html", out string resolvedPath, out bool isDirectory).Should().BeTrue();
|
||||
|
||||
isDirectory.Should().BeFalse();
|
||||
|
||||
resolvedPath.Should().BeEquivalentTo(this.TestFile);
|
||||
}
|
||||
}
|
||||
}
|
@ -406,6 +406,18 @@ namespace MontoyaTech.Rest.Net
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the last character written to the writer if there was one, otherwise it returns character 0.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public char Peek()
|
||||
{
|
||||
if (this.Builder.Length > 0)
|
||||
return this.Builder[this.Builder.Length - 1];
|
||||
else
|
||||
return (char)0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the written data from the writer.
|
||||
/// </summary>
|
||||
|
@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace MontoyaTech.Rest.Net
|
||||
{
|
||||
@ -23,9 +24,20 @@ namespace MontoyaTech.Rest.Net
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
//If the request has been compressed, automatically handle it.
|
||||
if (request.Headers["Content-Encoding"] == "gzip")
|
||||
{
|
||||
using (var inputStream = request.InputStream)
|
||||
using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress, true))
|
||||
using (var stream = new StreamReader(gzipStream))
|
||||
return stream.ReadToEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
using (var stream = new StreamReader(input))
|
||||
return stream.ReadToEnd();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -43,9 +55,20 @@ namespace MontoyaTech.Rest.Net
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
using (var stream = new StreamReader(input))
|
||||
//If the request has been compressed, automatically handle it.
|
||||
if (request.Headers["Content-Encoding"] == "gzip")
|
||||
{
|
||||
using (var inputStream = request.InputStream)
|
||||
using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress, true))
|
||||
using (var stream = new StreamReader(gzipStream))
|
||||
return JsonConvert.DeserializeObject<T>(stream.ReadToEnd());
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var inputStream = request.InputStream)
|
||||
using (var stream = new StreamReader(inputStream))
|
||||
return JsonConvert.DeserializeObject<T>(stream.ReadToEnd());
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -62,12 +85,31 @@ namespace MontoyaTech.Rest.Net
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
//If the request has been compressed, automatically handle it.
|
||||
if (request.Headers["Content-Encoding"] == "gzip")
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
using (var inputStream = request.InputStream)
|
||||
{
|
||||
input.CopyTo(stream);
|
||||
return stream.ToArray();
|
||||
using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress, true))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
gzipStream.CopyTo(memoryStream);
|
||||
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
{
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
input.CopyTo(stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,8 +129,22 @@ namespace MontoyaTech.Rest.Net
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
input.CopyTo(stream);
|
||||
//If the request has been compressed, automatically handle it.
|
||||
if (request.Headers["Content-Encoding"] == "gzip")
|
||||
{
|
||||
using (var inputStream = request.InputStream)
|
||||
{
|
||||
using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress, true))
|
||||
{
|
||||
gzipStream.CopyTo(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var input = request.InputStream)
|
||||
input.CopyTo(stream);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -49,6 +49,27 @@ namespace MontoyaTech.Rest.Net
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response content type to text encoded as utf16 and writes the given text to it.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <returns>This response.</returns>
|
||||
public static HttpListenerResponse WithText16(this HttpListenerResponse response, string text)
|
||||
{
|
||||
response.ContentType = "text/plain; charset=utf-16";
|
||||
|
||||
var bytes = Encoding.Unicode.GetBytes(text);
|
||||
|
||||
response.ContentLength64 = bytes.Length;
|
||||
|
||||
response.OutputStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
response.OutputStream.Dispose();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response content type to text and writes the given text compressed to it.
|
||||
/// </summary>
|
||||
@ -61,10 +82,10 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
response.Headers.Add("Content-Encoding", "gzip");
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(text);
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(text);
|
||||
|
||||
using (var compressedStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
|
||||
compressedStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
@ -101,6 +122,27 @@ namespace MontoyaTech.Rest.Net
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response content type to json encoded as utf16 and serializes the object as json and writes it.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns>This response.</returns>
|
||||
public static HttpListenerResponse WithJson16(this HttpListenerResponse response, object obj)
|
||||
{
|
||||
response.ContentType = "application/json; charset=utf-16";
|
||||
|
||||
var bytes = Encoding.Unicode.GetBytes(JsonConvert.SerializeObject(obj));
|
||||
|
||||
response.ContentLength64 = bytes.Length;
|
||||
|
||||
response.OutputStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
response.OutputStream.Dispose();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response content type to json and writes the given json compressed to it.
|
||||
/// </summary>
|
||||
@ -110,12 +152,13 @@ namespace MontoyaTech.Rest.Net
|
||||
public static HttpListenerResponse WithCompressedJson(this HttpListenerResponse response, object obj)
|
||||
{
|
||||
response.ContentType = "application/json; charset=utf-8";
|
||||
response.Headers.Add("Content-Encoding", "gzip");
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj));
|
||||
response.Headers.Add("Content-Encoding", "gzip");
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(obj));
|
||||
|
||||
using (var compressedStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
|
||||
compressedStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
@ -312,6 +355,56 @@ namespace MontoyaTech.Rest.Net
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response content type to html encoded in utf 16 and writes the given html to it.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="html"></param>
|
||||
/// <returns>This response.</returns>
|
||||
public static HttpListenerResponse WithHtml16(this HttpListenerResponse response, string html)
|
||||
{
|
||||
response.ContentType = "text/html; charset=utf-16";
|
||||
|
||||
var bytes = Encoding.Unicode.GetBytes(html);
|
||||
|
||||
response.ContentLength64 = bytes.Length;
|
||||
|
||||
response.OutputStream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response to include the given stream and sets the length and content type if possible.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="mimeType">If set, sets the content type to this value. If null, and no content type is set, sets it to octet-stream.</param>
|
||||
/// <returns>This response.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public static HttpListenerResponse WithStream(this HttpListenerResponse response, Stream stream, string mimeType = null)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException($"{nameof(stream)} cannot be null.");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(mimeType))
|
||||
response.ContentType = mimeType;
|
||||
else if (string.IsNullOrWhiteSpace(response.ContentType))
|
||||
response.ContentType = "application/octet-stream";
|
||||
|
||||
try
|
||||
{
|
||||
response.ContentLength64 = stream.Length;
|
||||
}
|
||||
catch { }
|
||||
|
||||
stream.CopyTo(response.OutputStream);
|
||||
|
||||
response.OutputStream.Dispose();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the status code for a given response.
|
||||
/// </summary>
|
||||
@ -501,21 +594,286 @@ namespace MontoyaTech.Rest.Net
|
||||
/// <summary>
|
||||
/// Sets the response to serve a file in the context of a multi page application.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpListenerResponse ServeMultiPage(this HttpListenerResponse response, HttpListenerRequest request)
|
||||
/// <param name="response">The response to modify</param>
|
||||
/// <param name="basePath">The base path where to serve files from</param>
|
||||
/// <param name="request">The request to serve</param>
|
||||
/// <param name="indexFile">The name of the index file, default is index.html</param>
|
||||
/// <param name="compress">Whether or not to compress files served. Default is false.</param>
|
||||
/// <param name="compressExtensions">A collection of file extensions that should be compressed, example: .jpg, default is null. If and compress is true, all files will be compressed.</param>
|
||||
/// <returns>The modified response</returns>
|
||||
public static HttpListenerResponse ServeMultiPage(this HttpListenerResponse response, string basePath, string startPath, HttpListenerRequest request, string indexFile = "index.html", bool compress = false, HashSet<string> compressExtensions = null)
|
||||
{
|
||||
if (ResolveMultiPagePath(basePath, startPath, request.Url.LocalPath, indexFile, out string resolvedPath, out bool isDirectory))
|
||||
{
|
||||
if (isDirectory)
|
||||
{
|
||||
return response.WithNoBody().WithStatus(HttpStatusCode.NoContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (request.HttpMethod.Equals("head", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return response.WithNoBody().WithStatus(HttpStatusCode.NoContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compress && (compressExtensions == null || compressExtensions.Contains(Path.GetExtension(resolvedPath))))
|
||||
return response.WithStatus(HttpStatusCode.OK).WithCompressedFile(resolvedPath);
|
||||
else
|
||||
return response.WithStatus(HttpStatusCode.OK).WithFile(resolvedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return response.WithStatus(HttpStatusCode.NotFound);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ResolveMultiPagePath(string basePath, string startPath, string requestPath, string indexFile, out string resolvedPath, out bool isDirectory)
|
||||
{
|
||||
resolvedPath = null;
|
||||
|
||||
isDirectory = false;
|
||||
|
||||
//If the requestPath is pointing to nothing change that to the index file.
|
||||
if (string.IsNullOrWhiteSpace(requestPath) || requestPath == "/" || requestPath == ".")
|
||||
requestPath = indexFile;
|
||||
|
||||
//Break the startPath into it's components
|
||||
var startComponents = startPath?.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
//Break the request path into it's components so we can enfore staying in the base path.
|
||||
var requestComponents = requestPath.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
//If we have start components, remove request components that match.
|
||||
if (startComponents != null)
|
||||
{
|
||||
for (int i = 0; i < startComponents.Count; i++)
|
||||
{
|
||||
if (requestComponents.Count > 0 && requestComponents[0].Equals(startComponents[i], StringComparison.CurrentCultureIgnoreCase))
|
||||
requestComponents.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
//Quirk, if the components is now empty, point to the indexFile
|
||||
if (requestComponents.Count == 0)
|
||||
requestComponents.Add(indexFile);
|
||||
|
||||
//Process the request components and handle directory changes
|
||||
for (int i = 0; i < requestComponents.Count; i++)
|
||||
{
|
||||
if (requestComponents[i].Trim() == "..")
|
||||
{
|
||||
requestComponents.RemoveAt(i--);
|
||||
|
||||
if (i >= 0)
|
||||
requestComponents.RemoveAt(i--);
|
||||
else
|
||||
return false; //Trying to jump outside of basePath
|
||||
}
|
||||
else if (requestComponents[i].Trim() == "...")
|
||||
{
|
||||
requestComponents.RemoveAt(i--);
|
||||
|
||||
if (i >= 0)
|
||||
requestComponents.RemoveAt(i--);
|
||||
else
|
||||
return false; //Trying to jump outside of basePath
|
||||
|
||||
if (i >= 0)
|
||||
requestComponents.RemoveAt(i--);
|
||||
else
|
||||
return false; //Trying to jump outside of basePath
|
||||
}
|
||||
else if (requestComponents[i].Trim() == ".")
|
||||
{
|
||||
requestComponents.RemoveAt(i--);
|
||||
}
|
||||
}
|
||||
|
||||
if (requestComponents.Count == 0)
|
||||
return false;
|
||||
|
||||
var absolutePath = Path.Combine(basePath, requestComponents.Separate(Path.DirectorySeparatorChar));
|
||||
|
||||
if (File.Exists(absolutePath))
|
||||
{
|
||||
resolvedPath = absolutePath;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (Directory.Exists(absolutePath))
|
||||
{
|
||||
resolvedPath = absolutePath;
|
||||
|
||||
isDirectory = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the response to serve a file in the context of a single page application.
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpListenerResponse ServeSinglePage(this HttpListenerResponse response, HttpListenerRequest request)
|
||||
/// <param name="response">The response to modify</param>
|
||||
/// <param name="basePath">The base path where to serve files from</param>
|
||||
/// <param name="startPath">The starting path that should be removed from requests, if null or empty, requests won't be affected</param>
|
||||
/// <param name="request">The request to serve</param>
|
||||
/// <param name="indexFile">The name of the index file, default is index.html</param>
|
||||
/// <param name="compress">Whether or not to compress files served. Default is false.</param>
|
||||
/// <param name="compressExtensions">A collection of file extensions that should be compressed, example: .jpg, default is null. If and compress is true, all files will be compressed.</param>
|
||||
/// <returns>The modified response</returns>
|
||||
public static HttpListenerResponse ServeSinglePage(this HttpListenerResponse response, string basePath, string startPath, HttpListenerRequest request, string indexFile = "index.html", bool compress = false, HashSet<string> compressExtensions = null)
|
||||
{
|
||||
if (ResolveSinglePagePath(basePath, startPath, request.Url.LocalPath, indexFile, out string resolvedPath, out bool isDirectory))
|
||||
{
|
||||
if (isDirectory)
|
||||
{
|
||||
return response.WithNoBody().WithStatus(HttpStatusCode.NoContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (request.HttpMethod.Equals("head", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return response.WithNoBody().WithStatus(HttpStatusCode.NoContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compress && (compressExtensions == null || compressExtensions.Contains(Path.GetExtension(resolvedPath))))
|
||||
return response.WithStatus(HttpStatusCode.OK).WithCompressedFile(resolvedPath);
|
||||
else
|
||||
return response.WithStatus(HttpStatusCode.OK).WithFile(resolvedPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return response.WithStatus(HttpStatusCode.NotFound);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ResolveSinglePagePath(string basePath, string startPath, string requestPath, string indexFile, out string resolvedPath, out bool isDirectory)
|
||||
{
|
||||
resolvedPath = null;
|
||||
|
||||
isDirectory = false;
|
||||
|
||||
//If the requestPath is pointing to nothing change that to the index file.
|
||||
if (string.IsNullOrWhiteSpace(requestPath) || requestPath == "/" || requestPath == ".")
|
||||
requestPath = indexFile;
|
||||
|
||||
//Break the startPath into it's components
|
||||
var startComponents = startPath?.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
//Break the request path into it's components so we can enfore staying in the base path.
|
||||
var requestComponents = requestPath.Split(new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
//If we have start components, remove request components that match.
|
||||
if (startComponents != null)
|
||||
{
|
||||
for (int i = 0; i < startComponents.Count; i++)
|
||||
{
|
||||
if (requestComponents.Count > 0 && requestComponents[0].Equals(startComponents[i], StringComparison.CurrentCultureIgnoreCase))
|
||||
requestComponents.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
//Process the request components and handle directory changes
|
||||
for (int i = 0; i < requestComponents.Count; i++)
|
||||
{
|
||||
if (requestComponents[i].Trim() == "..")
|
||||
{
|
||||
requestComponents.RemoveAt(i--);
|
||||
|
||||
if (i >= 0)
|
||||
requestComponents.RemoveAt(i--);
|
||||
else
|
||||
return false; //Trying to jump outside of basePath
|
||||
}
|
||||
else if (requestComponents[i].Trim() == "...")
|
||||
{
|
||||
requestComponents.RemoveAt(i--);
|
||||
|
||||
if (i >= 0)
|
||||
requestComponents.RemoveAt(i--);
|
||||
else
|
||||
return false; //Trying to jump outside of basePath
|
||||
|
||||
if (i >= 0)
|
||||
requestComponents.RemoveAt(i--);
|
||||
else
|
||||
return false; //Trying to jump outside of basePath
|
||||
}
|
||||
else if (requestComponents[i].Trim() == ".")
|
||||
{
|
||||
requestComponents.RemoveAt(i--);
|
||||
}
|
||||
}
|
||||
|
||||
//Check the components and remove any that are invalid.
|
||||
while (requestComponents.Count > 0)
|
||||
{
|
||||
string path = Path.Combine(basePath, requestComponents[0]);
|
||||
|
||||
if (File.Exists(path) || Directory.Exists(path))
|
||||
{
|
||||
break;
|
||||
}
|
||||
//If we have no more components and we are missing an extension and with .html a file exists, then use it.
|
||||
else if (requestComponents.Count == 1 && !requestComponents[0].Contains('.') && File.Exists(path + ".html"))
|
||||
{
|
||||
requestComponents[0] = requestComponents[0] + ".html";
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
requestComponents.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
//Quirk, if the components is now empty, point to the indexFile
|
||||
if (requestComponents.Count == 0)
|
||||
requestComponents.Add(indexFile);
|
||||
|
||||
//Combine the path into an absolute path
|
||||
var absolutePath = Path.Combine(basePath, requestComponents.Separate(Path.DirectorySeparatorChar));
|
||||
|
||||
//If a file exists, return true
|
||||
if (File.Exists(absolutePath))
|
||||
{
|
||||
resolvedPath = absolutePath;
|
||||
|
||||
return true;
|
||||
}
|
||||
//If a file exists with adding .html then use that
|
||||
else if (File.Exists(absolutePath + ".html"))
|
||||
{
|
||||
resolvedPath = absolutePath + ".html";
|
||||
|
||||
return true;
|
||||
}
|
||||
//If a directory exists then use that
|
||||
else if (Directory.Exists(absolutePath))
|
||||
{
|
||||
resolvedPath = absolutePath;
|
||||
|
||||
isDirectory = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
//Otherwise redirect to index.html
|
||||
else
|
||||
{
|
||||
resolvedPath = Path.Combine(basePath, indexFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>library</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
@ -17,9 +17,10 @@
|
||||
<AssemblyName>MontoyaTech.Rest.Net</AssemblyName>
|
||||
<RootNamespace>MontoyaTech.Rest.Net</RootNamespace>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<Version>1.6.2</Version>
|
||||
<Version>1.8.9</Version>
|
||||
<PackageReleaseNotes></PackageReleaseNotes>
|
||||
<PackageIcon>Logo_Symbol_Black_Outline.png</PackageIcon>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -27,10 +28,14 @@
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -33,12 +33,7 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
var writer = new CodeWriter();
|
||||
|
||||
writer.WriteLine("//Generated using MontoyaTech.Rest.Net");
|
||||
|
||||
writer.WriteLine("using System;");
|
||||
writer.WriteLine("using System.Net;");
|
||||
writer.WriteLine("using System.Net.Http;");
|
||||
writer.WriteLine("using Newtonsoft.Json;");
|
||||
writer.WriteLine($"//Generated using MontoyaTech.Rest.Net - {DateTime.Now.ToShortDateString()}");
|
||||
|
||||
writer.WriteBreak().WriteLine($"public class {this.ClientName}").WriteLine("{").Indent();
|
||||
|
||||
@ -50,21 +45,27 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
//Create the cookie container field
|
||||
if (this.StaticCode)
|
||||
writer.WriteBreak().WriteLine("public static CookieContainer CookieContainer;");
|
||||
writer.WriteBreak().WriteLine("public static System.Net.CookieContainer CookieContainer;");
|
||||
else
|
||||
writer.WriteBreak().WriteLine("public CookieContainer CookieContainer;");
|
||||
writer.WriteBreak().WriteLine("public System.Net.CookieContainer CookieContainer;");
|
||||
|
||||
//Create the client handler field
|
||||
if (this.StaticCode)
|
||||
writer.WriteBreak().WriteLine("public static HttpMessageHandler MessageHandler;");
|
||||
writer.WriteBreak().WriteLine("public static System.Net.Http.HttpMessageHandler MessageHandler;");
|
||||
else
|
||||
writer.WriteBreak().WriteLine("public HttpMessageHandler MessageHandler;");
|
||||
writer.WriteBreak().WriteLine("public System.Net.Http.HttpMessageHandler MessageHandler;");
|
||||
|
||||
//Create the http client field
|
||||
if (this.StaticCode)
|
||||
writer.WriteBreak().WriteLine("public static HttpClient HttpClient;");
|
||||
writer.WriteBreak().WriteLine("public static System.Net.Http.HttpClient HttpClient;");
|
||||
else
|
||||
writer.WriteBreak().WriteLine("public HttpClient HttpClient;");
|
||||
writer.WriteBreak().WriteLine("public System.Net.Http.HttpClient HttpClient;");
|
||||
|
||||
//Create the request handler field
|
||||
if (this.StaticCode)
|
||||
writer.WriteBreak().WriteLine("public static System.Action<System.Net.Http.HttpRequestMessage> RequestHandler;");
|
||||
else
|
||||
writer.WriteBreak().WriteLine("public System.Action<System.Net.Http.HttpRequestMessage> RequestHandler;");
|
||||
|
||||
//Create fields foreach route group so they can be accessed.
|
||||
if (!this.StaticCode)
|
||||
@ -74,11 +75,11 @@ namespace MontoyaTech.Rest.Net
|
||||
//Create the client constructor or init method
|
||||
if (this.StaticCode)
|
||||
{
|
||||
writer.WriteBreak().WriteLine("public static void Init(string baseUrl, HttpMessageHandler handler = null)").WriteLine("{").Indent();
|
||||
writer.WriteBreak().WriteLine("public static void Init(string baseUrl, System.Net.Http.HttpMessageHandler messageHandler = null, System.Action<System.Net.Http.HttpRequestMessage> requestHandler = null)").WriteLine("{").Indent();
|
||||
|
||||
//Make sure the base url isn't null or whitespace
|
||||
writer.WriteBreak().WriteLine("if (string.IsNullOrWhiteSpace(baseUrl))");
|
||||
writer.Indent().WriteLine(@"throw new ArgumentException(""baseUrl must not be null or whitespace."");").Outdent();
|
||||
writer.Indent().WriteLine(@"throw new System.ArgumentException(""baseUrl must not be null or whitespace."");").Outdent();
|
||||
|
||||
//If the baseUrl ends with a /, remove it.
|
||||
writer.WriteBreak().WriteLine("if (baseUrl.EndsWith('/'))");
|
||||
@ -88,25 +89,28 @@ namespace MontoyaTech.Rest.Net
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.BaseUrl = baseUrl;");
|
||||
|
||||
//Init the cookie container
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.CookieContainer = new CookieContainer();");
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.CookieContainer = new System.Net.CookieContainer();");
|
||||
|
||||
//Init the client handler
|
||||
writer.WriteBreak().WriteLine("if (handler == null)");
|
||||
writer.WriteBreak().WriteLine("if (messageHandler == null)");
|
||||
writer.WriteLine("{").Indent();
|
||||
writer.WriteLine($"handler = new HttpClientHandler()");
|
||||
writer.WriteLine($"messageHandler = new System.Net.Http.HttpClientHandler()");
|
||||
writer.WriteLine("{").Indent();
|
||||
writer.WriteLine("AllowAutoRedirect = true,");
|
||||
writer.WriteLine("UseCookies = true,");
|
||||
writer.WriteLine($"CookieContainer = {this.ClientName}.CookieContainer,");
|
||||
writer.WriteLine("AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate");
|
||||
writer.WriteLine("AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate");
|
||||
writer.Outdent().WriteLine("};");
|
||||
writer.Outdent().WriteLine("}");
|
||||
|
||||
//Store the message handler
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.MessageHandler = handler;");
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.MessageHandler = messageHandler;");
|
||||
|
||||
//Store the request handler
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.RequestHandler = requestHandler;");
|
||||
|
||||
//Init the http client
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.HttpClient = new HttpClient(handler);");
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.HttpClient = new System.Net.Http.HttpClient(handler);");
|
||||
writer.WriteBreak().WriteLine(@$"{this.ClientName}.HttpClient.DefaultRequestHeaders.Add(""Accept"", ""*/*"");");
|
||||
writer.WriteBreak().WriteLine(@$"{this.ClientName}.HttpClient.DefaultRequestHeaders.Add(""Connection"", ""keep-alive"");");
|
||||
writer.WriteBreak().WriteLine(@$"{this.ClientName}.HttpClient.DefaultRequestHeaders.Add(""Accept-Encoding"", ""identity"");");
|
||||
@ -115,11 +119,11 @@ namespace MontoyaTech.Rest.Net
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBreak().WriteLine("public Client(string baseUrl, HttpMessageHandler handler = null)").WriteLine("{").Indent();
|
||||
writer.WriteBreak().WriteLine($"public {this.ClientName}(string baseUrl, System.Net.Http.HttpMessageHandler messageHandler = null, System.Action<System.Net.Http.HttpRequestMessage> requestHandler = null)").WriteLine("{").Indent();
|
||||
|
||||
//Make sure the base url isn't null or whitespace
|
||||
writer.WriteBreak().WriteLine("if (string.IsNullOrWhiteSpace(baseUrl))");
|
||||
writer.Indent().WriteLine(@"throw new ArgumentException(""baseUrl must not be null or whitespace."");").Outdent();
|
||||
writer.Indent().WriteLine(@"throw new System.ArgumentException(""baseUrl must not be null or whitespace."");").Outdent();
|
||||
|
||||
//If the baseUrl ends with a /, remove it.
|
||||
writer.WriteBreak().WriteLine("if (baseUrl.EndsWith('/'))");
|
||||
@ -129,25 +133,28 @@ namespace MontoyaTech.Rest.Net
|
||||
writer.WriteBreak().WriteLine("this.BaseUrl = baseUrl;");
|
||||
|
||||
//Init the cookie container
|
||||
writer.WriteBreak().WriteLine("this.CookieContainer = new CookieContainer();");
|
||||
writer.WriteBreak().WriteLine("this.CookieContainer = new System.Net.CookieContainer();");
|
||||
|
||||
//Init the client handler
|
||||
writer.WriteBreak().WriteLine("if (handler == null)");
|
||||
writer.WriteBreak().WriteLine("if (messageHandler == null)");
|
||||
writer.WriteLine("{").Indent();
|
||||
writer.WriteLine("handler = new HttpClientHandler()");
|
||||
writer.WriteLine("messageHandler = new System.Net.Http.HttpClientHandler()");
|
||||
writer.WriteLine("{").Indent();
|
||||
writer.WriteLine("AllowAutoRedirect = true,");
|
||||
writer.WriteLine("UseCookies = true,");
|
||||
writer.WriteLine("CookieContainer = this.CookieContainer,");
|
||||
writer.WriteLine("AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate");
|
||||
writer.WriteLine("AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate");
|
||||
writer.Outdent().WriteLine("};");
|
||||
writer.Outdent().WriteLine("}");
|
||||
|
||||
//Store the message handler
|
||||
writer.WriteBreak().WriteLine("this.MessageHandler = handler;");
|
||||
writer.WriteBreak().WriteLine("this.MessageHandler = messageHandler;");
|
||||
|
||||
//Store the request handler
|
||||
writer.WriteBreak().WriteLine("this.RequestHandler = requestHandler;");
|
||||
|
||||
//Init the http client
|
||||
writer.WriteBreak().WriteLine("this.HttpClient = new HttpClient(handler);");
|
||||
writer.WriteBreak().WriteLine("this.HttpClient = new System.Net.Http.HttpClient(handler);");
|
||||
writer.WriteBreak().WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Accept"", ""*/*"");");
|
||||
writer.WriteBreak().WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Connection"", ""keep-alive"");");
|
||||
writer.WriteBreak().WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Accept-Encoding"", ""identity"");");
|
||||
@ -250,25 +257,28 @@ namespace MontoyaTech.Rest.Net
|
||||
writer.Outdent().WriteLine('}');
|
||||
|
||||
//Generate a constructor to set all the fields/properties with optional default values
|
||||
writer.WriteBreak();
|
||||
writer.Write($"public {(newName != null ? newName.Name : type.Name)}(");
|
||||
if (fields.Length > 0 || properties.Length > 0)
|
||||
{
|
||||
writer.WriteBreak();
|
||||
writer.Write($"public {(newName != null ? newName.Name : type.Name)}(");
|
||||
|
||||
foreach (var field in fields)
|
||||
writer.WriteSeparator().Write($"{this.GetTypeFullyResolvedName(field.FieldType)} {field.Name} = {this.GetTypeDefaultValue(field.FieldType)}");
|
||||
foreach (var field in fields)
|
||||
writer.WriteSeparator().Write($"{this.GetTypeFullyResolvedName(field.FieldType)} {field.Name} = {this.GetTypeDefaultValue(field.FieldType)}");
|
||||
|
||||
foreach (var property in properties)
|
||||
writer.WriteSeparator().Write($"{this.GetTypeFullyResolvedName(property.PropertyType)} {property.Name} = {this.GetTypeDefaultValue(property.PropertyType)}");
|
||||
foreach (var property in properties)
|
||||
writer.WriteSeparator().Write($"{this.GetTypeFullyResolvedName(property.PropertyType)} {property.Name} = {this.GetTypeDefaultValue(property.PropertyType)}");
|
||||
|
||||
writer.WriteLine(")");
|
||||
writer.WriteLine('{').Indent();
|
||||
writer.WriteLine(")");
|
||||
writer.WriteLine('{').Indent();
|
||||
|
||||
foreach (var field in fields)
|
||||
writer.WriteLine($"this.{field.Name} = {field.Name};");
|
||||
foreach (var field in fields)
|
||||
writer.WriteLine($"this.{field.Name} = {field.Name};");
|
||||
|
||||
foreach (var property in properties)
|
||||
writer.WriteLine($"this.{property.Name} = {property.Name};");
|
||||
foreach (var property in properties)
|
||||
writer.WriteLine($"this.{property.Name} = {property.Name};");
|
||||
|
||||
writer.Outdent().WriteLine('}');
|
||||
writer.Outdent().WriteLine('}');
|
||||
}
|
||||
}
|
||||
|
||||
//Generate C# for any types that belong to this one.
|
||||
@ -375,9 +385,9 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
//Generate the route function header
|
||||
if (this.StaticCode)
|
||||
writer.Write($"public static {(routeResponse == null ? "void" : this.GetTypeFullyResolvedName(routeResponse.ResponseType))} {(routeName == null ? methodInfo.Name : routeName.Name)}(");
|
||||
writer.Write($"public static {(routeResponse == null ? "void" : (routeResponse.Dynamic ? "dynamic" : this.GetTypeFullyResolvedName(routeResponse.ResponseType)))} {(routeName == null ? methodInfo.Name : routeName.Name)}(");
|
||||
else
|
||||
writer.Write($"public {(routeResponse == null ? "void" : this.GetTypeFullyResolvedName(routeResponse.ResponseType))} {(routeName == null ? methodInfo.Name : routeName.Name)}(");
|
||||
writer.Write($"public {(routeResponse == null ? "void" : (routeResponse.Dynamic ? "dynamic" : this.GetTypeFullyResolvedName(routeResponse.ResponseType)))} {(routeName == null ? methodInfo.Name : routeName.Name)}(");
|
||||
|
||||
//Generate the functions parameters
|
||||
var parameters = methodInfo.GetParameters();
|
||||
@ -394,45 +404,64 @@ namespace MontoyaTech.Rest.Net
|
||||
if (routeRequest != null)
|
||||
{
|
||||
writer.WriteSeparator();
|
||||
writer.Write(this.GetTypeFullyResolvedName(routeRequest.RequestType)).Write(" request");
|
||||
|
||||
if (routeRequest.Dynamic)
|
||||
writer.Write("dynamic");
|
||||
else
|
||||
writer.Write(this.GetTypeFullyResolvedName(routeRequest.RequestType));
|
||||
|
||||
writer.Write(" request");
|
||||
}
|
||||
|
||||
if (routeResponse != null && routeResponse.Parameter)
|
||||
{
|
||||
writer.WriteSeparator();
|
||||
writer.Write(this.GetTypeFullyResolvedName(routeResponse.ResponseType)).Write(" input");
|
||||
|
||||
if (routeResponse.Dynamic)
|
||||
writer.Write("dynamic");
|
||||
else
|
||||
writer.Write(this.GetTypeFullyResolvedName(routeResponse.ResponseType));
|
||||
|
||||
writer.Write(" input");
|
||||
}
|
||||
|
||||
//If JSON, add a compress parameter to control compressing the content.
|
||||
if (routeRequest != null && routeRequest.Json)
|
||||
{
|
||||
writer.WriteSeparator();
|
||||
writer.Write("bool compress = false");
|
||||
}
|
||||
|
||||
writer.WriteLine(")").WriteLine("{").Indent();
|
||||
|
||||
//Generate the message code
|
||||
writer.WriteBreak().Write($"var message = new HttpRequestMessage(");
|
||||
writer.WriteBreak().Write($"var message = new System.Net.Http.HttpRequestMessage(");
|
||||
|
||||
switch (route.Method.ToLower())
|
||||
{
|
||||
case "post":
|
||||
writer.Write("HttpMethod.Post");
|
||||
writer.Write("System.Net.Http.HttpMethod.Post");
|
||||
break;
|
||||
case "get":
|
||||
writer.Write("HttpMethod.Get");
|
||||
writer.Write("System.Net.Http.HttpMethod.Get");
|
||||
break;
|
||||
case "delete":
|
||||
writer.Write("HttpMethod.Delete");
|
||||
writer.Write("System.Net.Http.HttpMethod.Delete");
|
||||
break;
|
||||
case "put":
|
||||
writer.Write("HttpMethod.Put");
|
||||
writer.Write("System.Net.Http.HttpMethod.Put");
|
||||
break;
|
||||
case "options":
|
||||
writer.Write("HttpMethod.Options");
|
||||
writer.Write("System.Net.Http.HttpMethod.Options");
|
||||
break;
|
||||
case "patch":
|
||||
writer.Write("HttpMethod.Patch");
|
||||
writer.Write("System.Net.Http.HttpMethod.Patch");
|
||||
break;
|
||||
case "head":
|
||||
writer.Write("HttpMethod.Head");
|
||||
writer.Write("System.Net.Http.HttpMethod.Head");
|
||||
break;
|
||||
case "trace":
|
||||
writer.Write("HttpMethod.Trace");
|
||||
writer.Write("System.Net.Http.HttpMethod.Trace");
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unsupport route method:" + route.Method);
|
||||
@ -448,10 +477,11 @@ namespace MontoyaTech.Rest.Net
|
||||
int argumentIndex = 0;
|
||||
foreach (var component in components)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(component))
|
||||
{
|
||||
if (writer.Peek() != '/')
|
||||
writer.Write('/');
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(component))
|
||||
{
|
||||
if (component.StartsWith("{"))
|
||||
{
|
||||
writer.Write("{").Write(parameters[argumentIndex++ + 1].Name).Write("}");
|
||||
@ -473,6 +503,12 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
writer.Write('"').WriteLine(");");
|
||||
|
||||
//Invoke the request handler if needed.
|
||||
if (this.StaticCode)
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.RequestHandler?.Invoke(message);");
|
||||
else
|
||||
writer.WriteBreak().WriteLine($"this.Client.RequestHandler?.Invoke(message);");
|
||||
|
||||
//Add the request content if any.
|
||||
if (routeRequest != null)
|
||||
{
|
||||
@ -480,30 +516,53 @@ namespace MontoyaTech.Rest.Net
|
||||
{
|
||||
writer.WriteBreak().WriteLine("request.Seek(0, System.IO.SeekOrigin.Begin);");
|
||||
|
||||
writer.WriteBreak().WriteLine("message.Content = new StreamContent(request);");
|
||||
writer.WriteBreak().WriteLine("message.Content = new System.Net.Http.StreamContent(request);");
|
||||
}
|
||||
else if (routeRequest.Json)
|
||||
{
|
||||
writer.WriteBreak().WriteLine("message.Content = new StringContent(JsonConvert.SerializeObject(request));");
|
||||
writer.WriteBreak().WriteLine("if (compress)").WriteLine("{").Indent();
|
||||
|
||||
writer.WriteLine("using (var uncompressedStream = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(request))))");
|
||||
writer.WriteLine("{").Indent();
|
||||
writer.WriteLine("using (var compressedStream = new System.IO.MemoryStream())");
|
||||
writer.WriteLine("{").Indent();
|
||||
writer.WriteLine("using (var gzipStream = new System.IO.Compression.GZipStream(compressedStream, System.IO.Compression.CompressionMode.Compress, true))");
|
||||
writer.Indent().WriteLine("uncompressedStream.CopyTo(gzipStream);").Outdent();
|
||||
|
||||
writer.WriteBreak();
|
||||
writer.WriteLine("message.Content = new System.Net.Http.ByteArrayContent(compressedStream.ToArray());");
|
||||
writer.WriteLine("message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(System.Net.Mime.MediaTypeNames.Application.Json);");
|
||||
writer.WriteLine("message.Content.Headers.ContentEncoding.Add(\"gzip\");");
|
||||
|
||||
writer.Outdent().WriteLine("}");
|
||||
writer.Outdent().WriteLine("}");
|
||||
|
||||
writer.Outdent().WriteLine("}");
|
||||
writer.WriteLine("else").WriteLine("{").Indent();
|
||||
|
||||
writer.WriteBreak().WriteLine("message.Content = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request));");
|
||||
writer.WriteBreak().WriteLine("message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(System.Net.Mime.MediaTypeNames.Application.Json);");
|
||||
|
||||
writer.Outdent().WriteLine("}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBreak().WriteLine("message.Content = new StringContent(request.ToString());");
|
||||
writer.WriteBreak().WriteLine("message.Content = new System.Net.Http.StringContent(request.ToString());");
|
||||
}
|
||||
}
|
||||
|
||||
//Generate the response code
|
||||
if (this.StaticCode)
|
||||
writer.WriteBreak().WriteLine($"var response = {this.ClientName}.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);");
|
||||
writer.WriteBreak().WriteLine($"var response = {this.ClientName}.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);");
|
||||
else
|
||||
writer.WriteBreak().WriteLine("var response = this.Client.HttpClient.Send(message, HttpCompletionOption.ResponseHeadersRead);");
|
||||
writer.WriteBreak().WriteLine("var response = this.Client.HttpClient.Send(message, System.Net.Http.HttpCompletionOption.ResponseHeadersRead);");
|
||||
|
||||
//Handle the response
|
||||
if (routeResponse != null)
|
||||
{
|
||||
writer.WriteBreak().WriteLine("if (response.IsSuccessStatusCode)").WriteLine("{").Indent();
|
||||
|
||||
if (routeResponse.ResponseType.IsAssignableTo(typeof(Stream)))
|
||||
if (routeResponse.ResponseType != null && routeResponse.ResponseType.IsAssignableTo(typeof(Stream)))
|
||||
{
|
||||
if (routeResponse.Parameter)
|
||||
{
|
||||
@ -528,7 +587,7 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
if (routeResponse.Json)
|
||||
{
|
||||
writer.WriteBreak().WriteLine($"return JsonConvert.DeserializeObject<{this.GetTypeFullyResolvedName(routeResponse.ResponseType)}>(content);");
|
||||
writer.WriteBreak().WriteLine($"return Newtonsoft.Json.JsonConvert.DeserializeObject<{(routeResponse.Dynamic ? "dynamic" : this.GetTypeFullyResolvedName(routeResponse.ResponseType))}>(content);");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -547,7 +606,7 @@ namespace MontoyaTech.Rest.Net
|
||||
break;
|
||||
|
||||
case TypeCode.DateTime:
|
||||
writer.WriteBreak().WriteLine("return DateTime.Parse(content);");
|
||||
writer.WriteBreak().WriteLine("return System.DateTime.Parse(content);");
|
||||
break;
|
||||
|
||||
case TypeCode.Decimal:
|
||||
@ -595,19 +654,19 @@ namespace MontoyaTech.Rest.Net
|
||||
break;
|
||||
|
||||
case TypeCode.Object:
|
||||
throw new NotSupportedException("ResponseType isn't JSON but is an object.");
|
||||
throw new NotSupportedException("RouteResponse has JSON=false but ResponseType is an object.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.Outdent().WriteLine("}").WriteLine("else").WriteLine("{").Indent();
|
||||
writer.WriteLine(@"throw new Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);");
|
||||
writer.WriteLine(@"throw new System.Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);");
|
||||
writer.Outdent().WriteLine("}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBreak().WriteLine("if (!response.IsSuccessStatusCode)").Indent();
|
||||
writer.WriteLine(@"throw new Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);").Outdent();
|
||||
writer.WriteLine(@"throw new System.Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);").Outdent();
|
||||
}
|
||||
|
||||
//Close off the route function.
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.Design;
|
||||
@ -58,76 +58,49 @@ namespace MontoyaTech.Rest.Net
|
||||
/// Finds all the dependencies for a given type and returns them.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="dependencies"></param>
|
||||
/// <returns></returns>
|
||||
protected internal virtual List<Type> FindTypeDependencies(Type type)
|
||||
protected internal virtual HashSet<Type> FindTypeDependencies(Type type, HashSet<Type> dependencies = null)
|
||||
{
|
||||
var dependencies = new HashSet<Type>();
|
||||
if (dependencies == null)
|
||||
dependencies = new HashSet<Type>();
|
||||
else if (dependencies.Contains(type))
|
||||
return dependencies;
|
||||
else if (!this.IsTypeDotNet(type))
|
||||
dependencies.Add(type);
|
||||
|
||||
var arguments = type.GetGenericArguments();
|
||||
|
||||
if (arguments != null)
|
||||
{
|
||||
foreach (var argument in arguments)
|
||||
{
|
||||
var types = this.FindTypeDependencies(argument);
|
||||
|
||||
for (int i = 0; i < types.Count; i++)
|
||||
if (!dependencies.Contains(types[i]))
|
||||
dependencies.Add(types[i]);
|
||||
}
|
||||
}
|
||||
if (argument != type)
|
||||
this.FindTypeDependencies(argument, dependencies);
|
||||
|
||||
if (this.IsTypeDotNet(type))
|
||||
return dependencies.ToList();
|
||||
return dependencies;
|
||||
|
||||
dependencies.Add(type);
|
||||
|
||||
if (type.IsEnum)
|
||||
return dependencies.ToList();
|
||||
return dependencies;
|
||||
|
||||
{
|
||||
var types = this.FindTypeDependencies(type.BaseType);
|
||||
|
||||
for (int i = 0; i < types.Count; i++)
|
||||
if (!dependencies.Contains(types[i]))
|
||||
dependencies.Add(types[i]);
|
||||
}
|
||||
this.FindTypeDependencies(type.BaseType, dependencies);
|
||||
|
||||
var fields = type.GetFields();
|
||||
|
||||
if (fields != null)
|
||||
{
|
||||
foreach (var field in fields)
|
||||
{
|
||||
if (field.IsPublic && !field.IsSpecialName)
|
||||
{
|
||||
var types = this.FindTypeDependencies(field.FieldType);
|
||||
|
||||
for (int i = 0; i < types.Count; i++)
|
||||
if (!dependencies.Contains(types[i]))
|
||||
dependencies.Add(types[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (field.IsPublic && !field.IsSpecialName && field.FieldType != type)
|
||||
this.FindTypeDependencies(field.FieldType, dependencies);
|
||||
|
||||
var properties = type.GetProperties();
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (!property.IsSpecialName && property.GetSetMethod() != null && property.GetGetMethod() != null)
|
||||
{
|
||||
var types = this.FindTypeDependencies(property.PropertyType);
|
||||
if (!property.IsSpecialName && property.GetSetMethod() != null && property.GetGetMethod() != null && property.PropertyType != type)
|
||||
this.FindTypeDependencies(property.PropertyType, dependencies);
|
||||
|
||||
for (int i = 0; i < types.Count; i++)
|
||||
if (!dependencies.Contains(types[i]))
|
||||
dependencies.Add(types[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies.ToList();
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -163,7 +136,7 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
var routeRequest = methodInfo.GetCustomAttribute<RouteRequest>();
|
||||
|
||||
if (routeRequest != null)
|
||||
if (routeRequest != null && routeRequest.RequestType != null)
|
||||
{
|
||||
var types = this.FindTypeDependencies(routeRequest.RequestType);
|
||||
|
||||
@ -174,7 +147,7 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
var routeResponse = methodInfo.GetCustomAttribute<RouteResponse>();
|
||||
|
||||
if (routeResponse != null)
|
||||
if (routeResponse != null && routeResponse.ResponseType != null)
|
||||
{
|
||||
var types = this.FindTypeDependencies(routeResponse.ResponseType);
|
||||
|
||||
@ -245,7 +218,7 @@ namespace MontoyaTech.Rest.Net
|
||||
case TypeCode.Char:
|
||||
return "char";
|
||||
case TypeCode.DateTime:
|
||||
return "DateTime";
|
||||
return "System.DateTime";
|
||||
case TypeCode.Decimal:
|
||||
return "decimal";
|
||||
case TypeCode.Double:
|
||||
|
@ -20,6 +20,11 @@ namespace MontoyaTech.Rest.Net
|
||||
/// </summary>
|
||||
public bool StaticCode = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to use Json Property names instead of the Field/Property names.
|
||||
/// </summary>
|
||||
public bool UseJsonNames = false;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a Javascript Client from a given set of routes and returns it.
|
||||
/// </summary>
|
||||
@ -33,21 +38,21 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
var writer = new CodeWriter();
|
||||
|
||||
writer.WriteLine("//Generated using MontoyaTech.Rest.Net");
|
||||
writer.WriteLine($"//Generated using MontoyaTech.Rest.Net - {DateTime.Now.ToShortDateString()}");
|
||||
|
||||
writer.WriteBreak().WriteLine($"class {this.ClientName} {{").Indent();
|
||||
|
||||
//Create the base url field
|
||||
if (this.StaticCode)
|
||||
{
|
||||
writer.WriteBreak().WriteLine("/** @type {string} */");
|
||||
writer.WriteLine("static BaseUrl = null;");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBreak().WriteLine("/** @type {string} */");
|
||||
writer.WriteLine("BaseUrl = null;");
|
||||
}
|
||||
writer.WriteBreak().WriteLine("/** @type {string} */");
|
||||
writer.WriteAssert(this.StaticCode, "static ").WriteLine("BaseUrl = null;");
|
||||
|
||||
//Create the url handler field
|
||||
writer.WriteBreak().WriteLine("/** @type {Function} */");
|
||||
writer.WriteAssert(this.StaticCode, "static ").WriteLine("UrlHandler = null;");
|
||||
|
||||
//Create the request handler field.
|
||||
writer.WriteBreak().WriteLine("/** @type {Function} */");
|
||||
writer.WriteAssert(this.StaticCode, "static ").WriteLine("RequestHandler = null;");
|
||||
|
||||
//Create fields foreach route group so they can be accessed.
|
||||
if (!this.StaticCode)
|
||||
@ -62,12 +67,13 @@ namespace MontoyaTech.Rest.Net
|
||||
//Create the client constructor or init method
|
||||
if (this.StaticCode)
|
||||
{
|
||||
|
||||
writer.WriteBreak().WriteLine("/**").Indent();
|
||||
writer.WriteLine("Initializes the api client with a given baseUrl of where to send requests.");
|
||||
writer.WriteLine("@param {string} baseUrl");
|
||||
writer.WriteLine("Initializes this api client with a given baseUrl of where to send requests.");
|
||||
writer.WriteLine("@param {string} baseUrl Base url of the server to make requests against.");
|
||||
writer.WriteLine("@param {Function} urlHandler An optional function to process request urls before they are sent. This must return the url.");
|
||||
writer.WriteLine("@param {Function} requestHandler An optional function to process requests before they are sent. This must return the request.");
|
||||
writer.Outdent().WriteLine("*/");
|
||||
writer.Write("static Init(baseUrl) ").WriteLine("{").Indent();
|
||||
writer.Write("static Init(baseUrl, urlHandler = null, requestHandler = null) ").WriteLine("{").Indent();
|
||||
|
||||
//Make sure the baseUrl isn't null or whitespace
|
||||
writer.WriteBreak().WriteLine("if (baseUrl == null || baseUrl == undefined || baseUrl.trim() == '') {").Indent();
|
||||
@ -82,12 +88,23 @@ namespace MontoyaTech.Rest.Net
|
||||
//Store the baseUrl
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.BaseUrl = baseUrl;");
|
||||
|
||||
//Store the urlHandler
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.UrlHandler = urlHandler;");
|
||||
|
||||
//Store the requestHandler
|
||||
writer.WriteBreak().WriteLine($"{this.ClientName}.RequestHandler = requestHandler;");
|
||||
|
||||
writer.Outdent().WriteLine("}");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBreak().WriteLine("/** @param {string} baseUrl */");
|
||||
writer.Write("constructor(baseUrl) ").WriteLine("{").Indent();
|
||||
writer.WriteBreak().WriteLine("/**").Indent();
|
||||
writer.WriteLine("Initializes this api client with a given baseUrl of where to send requests.");
|
||||
writer.WriteLine("@param {string} baseUrl Base url of the server to make requests against.");
|
||||
writer.WriteLine("@param {Function} urlHandler An optional function to process request urls before they are sent. This must return the url.");
|
||||
writer.WriteLine("@param {Function} requestHandler An optional function to process requests before they are sent. This must return the request.");
|
||||
writer.Outdent().WriteLine("*/");
|
||||
writer.Write("constructor(baseUrl, urlHandler = null, requestHandler = null) ").WriteLine("{").Indent();
|
||||
|
||||
//Make sure the baseUrl isn't null or whitespace
|
||||
writer.WriteBreak().WriteLine("if (baseUrl == null || baseUrl == undefined || baseUrl.trim() == '') {").Indent();
|
||||
@ -102,8 +119,15 @@ namespace MontoyaTech.Rest.Net
|
||||
//Store the baseUrl
|
||||
writer.WriteBreak().WriteLine("this.BaseUrl = baseUrl;");
|
||||
|
||||
//Store the urlHandler
|
||||
writer.WriteBreak().WriteLine($"this.UrlHandler = urlHandler;");
|
||||
|
||||
//Store the request handler
|
||||
writer.WriteBreak().WriteLine("this.RequestHandler = requestHandler;");
|
||||
|
||||
//Init all the route group fields
|
||||
writer.WriteBreak();
|
||||
|
||||
foreach (var group in routeGroups)
|
||||
writer.WriteLine($"this.{group.Key} = new {group.Key}Api(this);");
|
||||
|
||||
@ -213,6 +237,64 @@ namespace MontoyaTech.Rest.Net
|
||||
return base.GetTypeDefaultValue(type);
|
||||
}
|
||||
|
||||
protected internal string EscapeName(string name)
|
||||
{
|
||||
if (name != null)
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "arguments":
|
||||
case "await":
|
||||
case "break":
|
||||
case "case":
|
||||
case "catch":
|
||||
case "class":
|
||||
case "const":
|
||||
case "continue":
|
||||
case "debugger":
|
||||
case "default":
|
||||
case "delete":
|
||||
case "do":
|
||||
case "double":
|
||||
case "else":
|
||||
case "enum":
|
||||
case "eval":
|
||||
case "export":
|
||||
case "extends":
|
||||
case "false":
|
||||
case "finally":
|
||||
case "for":
|
||||
case "function":
|
||||
case "goto":
|
||||
case "if":
|
||||
case "import":
|
||||
case "in":
|
||||
case "instanceof":
|
||||
case "interface":
|
||||
case "let":
|
||||
case "new":
|
||||
case "null":
|
||||
case "return":
|
||||
case "static":
|
||||
case "super":
|
||||
case "switch":
|
||||
case "this":
|
||||
case "throw":
|
||||
case "true":
|
||||
case "try":
|
||||
case "typeof":
|
||||
case "var":
|
||||
case "void":
|
||||
case "while":
|
||||
case "with":
|
||||
case "yield":
|
||||
return "_" + name;
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
protected internal virtual void GenerateJavascriptIncludedTypes(List<Type> types, CodeWriter writer)
|
||||
{
|
||||
foreach (var type in types)
|
||||
@ -252,12 +334,12 @@ namespace MontoyaTech.Rest.Net
|
||||
fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
foreach (var field in fields)
|
||||
this.GenerateJavascriptIncludedField(field, writer);
|
||||
this.GenerateJavascriptIncludedField(field, writer);
|
||||
|
||||
var properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public).Where(property => property.GetSetMethod() != null && property.GetGetMethod() != null).ToArray();
|
||||
|
||||
foreach (var property in properties)
|
||||
this.GenerateJavascriptIncludedProperty(property, writer);
|
||||
this.GenerateJavascriptIncludedProperty(property, writer);
|
||||
|
||||
//Generate a helper constructor
|
||||
if (!type.IsEnum)
|
||||
@ -265,28 +347,64 @@ namespace MontoyaTech.Rest.Net
|
||||
writer.WriteBreak().WriteLine("/**").Indent();
|
||||
writer.WriteLine("@function");
|
||||
|
||||
//Docuemnt the fields
|
||||
foreach (var field in fields)
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(field.FieldType)}}} {field.Name}");
|
||||
{
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(field.FieldType)}}} {EscapeName(field.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? field.Name)}");
|
||||
else
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(field.FieldType)}}} {EscapeName(field.Name)}");
|
||||
}
|
||||
|
||||
//Document the properties
|
||||
foreach (var property in properties)
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(property.PropertyType)}}} {property.Name}");
|
||||
{
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(property.PropertyType)}}} {EscapeName(property.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? property.Name)}");
|
||||
else
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(property.PropertyType)}}} {EscapeName(property.Name)}");
|
||||
}
|
||||
|
||||
writer.Outdent().WriteLine("*/");
|
||||
writer.Write("constructor(");
|
||||
|
||||
//Write the default fields
|
||||
foreach (var field in fields)
|
||||
writer.WriteSeparator().Write(field.Name).Write(" = ").Write(this.GetTypeDefaultValue(field.FieldType));
|
||||
{
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteSeparator().Write(EscapeName(field.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? field.Name)).Write(" = ").Write(this.GetTypeDefaultValue(field.FieldType));
|
||||
else
|
||||
writer.WriteSeparator().Write(EscapeName(field.Name)).Write(" = ").Write(this.GetTypeDefaultValue(field.FieldType));
|
||||
}
|
||||
|
||||
//Write the default properties
|
||||
foreach (var property in properties)
|
||||
writer.WriteSeparator().Write(property.Name).Write(" = ").Write(this.GetTypeDefaultValue(property.PropertyType));
|
||||
{
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteSeparator().Write(EscapeName(property.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? property.Name)).Write(" = ").Write(this.GetTypeDefaultValue(property.PropertyType));
|
||||
else
|
||||
writer.WriteSeparator().Write(EscapeName(property.Name)).Write(" = ").Write(this.GetTypeDefaultValue(property.PropertyType));
|
||||
}
|
||||
|
||||
writer.WriteLine(") {").Indent();
|
||||
|
||||
//Init the default fields
|
||||
foreach (var field in fields)
|
||||
writer.Write("this.").Write(field.Name).Write(" = ").Write(field.Name).WriteLine(";");
|
||||
{
|
||||
if (this.UseJsonNames)
|
||||
writer.Write("this.").Write(field.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? field.Name).Write(" = ").Write(EscapeName(field.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? field.Name)).WriteLine(";");
|
||||
else
|
||||
writer.Write("this.").Write(field.Name).Write(" = ").Write(EscapeName(field.Name)).WriteLine(";");
|
||||
}
|
||||
|
||||
//Init the default properties
|
||||
foreach (var property in properties)
|
||||
writer.Write("this.").Write(property.Name).Write(" = ").Write(property.Name).WriteLine(";");
|
||||
{
|
||||
if (this.UseJsonNames)
|
||||
writer.Write("this.").Write(property.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? property.Name).Write(" = ").Write(EscapeName(property.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? property.Name)).WriteLine(";");
|
||||
else
|
||||
writer.Write("this.").Write(property.Name).Write(" = ").Write(EscapeName(property.Name)).WriteLine(";");
|
||||
}
|
||||
|
||||
writer.Outdent().WriteLine("}");
|
||||
}
|
||||
@ -398,12 +516,20 @@ namespace MontoyaTech.Rest.Net
|
||||
if (field.DeclaringType != null && field.DeclaringType.IsEnum)
|
||||
{
|
||||
writer.WriteLine($"/** @type {{{GetTypeFullyResolvedName(field.DeclaringType)}}} */");
|
||||
writer.WriteLine($"static {field.Name} = {field.GetRawConstantValue()};");
|
||||
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteLine($"static {(field.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? field.Name)} = {field.GetRawConstantValue()};");
|
||||
else
|
||||
writer.WriteLine($"static {field.Name} = {field.GetRawConstantValue()};");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine($"/** @type {{{GetTypeFullyResolvedName(field.FieldType)}}} */");
|
||||
writer.WriteLine($"{field.Name} = {GetTypeDefaultValue(field.FieldType)};");
|
||||
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteLine($"{(field.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? field.Name)} = {GetTypeDefaultValue(field.FieldType)};");
|
||||
else
|
||||
writer.WriteLine($"{field.Name} = {GetTypeDefaultValue(field.FieldType)};");
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,7 +538,11 @@ namespace MontoyaTech.Rest.Net
|
||||
writer.WriteBreak();
|
||||
|
||||
writer.WriteLine($"/** @type {{{GetTypeFullyResolvedName(property.PropertyType)}}} */");
|
||||
writer.WriteLine($"{property.Name} = {GetTypeDefaultValue(property.PropertyType)};");
|
||||
|
||||
if (this.UseJsonNames)
|
||||
writer.WriteLine($"{(property.GetCustomAttribute<Newtonsoft.Json.JsonPropertyAttribute>()?.PropertyName ?? property.Name)} = {GetTypeDefaultValue(property.PropertyType)};");
|
||||
else
|
||||
writer.WriteLine($"{property.Name} = {GetTypeDefaultValue(property.PropertyType)};");
|
||||
}
|
||||
|
||||
protected internal virtual void GenerateJavascriptRouteGroups(Dictionary<string, List<Route>> groups, CodeWriter writer)
|
||||
@ -496,11 +626,13 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
//Generate request doc if any
|
||||
if (routeRequest != null)
|
||||
writer.WriteLine($"@param {{{this.GetTypeFullyResolvedName(routeRequest.RequestType)}}} request");
|
||||
writer.WriteLine($"@param {{{(routeRequest.Dynamic ? "Any" : this.GetTypeFullyResolvedName(routeRequest.RequestType))}}} body");
|
||||
|
||||
//Generate response doc if any
|
||||
if (routeResponse != null)
|
||||
writer.WriteLine($"@returns {{{this.GetTypeFullyResolvedName(routeResponse.ResponseType)}}}");
|
||||
writer.WriteLine($"@returns {{{(routeResponse.Dynamic ? "Any" : this.GetTypeFullyResolvedName(routeResponse.ResponseType))}}}");
|
||||
|
||||
writer.WriteLine("@throws {Response} If response status was not ok.");
|
||||
|
||||
writer.Outdent().WriteLine("*/");
|
||||
|
||||
@ -523,7 +655,7 @@ namespace MontoyaTech.Rest.Net
|
||||
if (routeRequest != null)
|
||||
{
|
||||
writer.WriteSeparator();
|
||||
writer.Write("request");
|
||||
writer.Write("body");
|
||||
}
|
||||
|
||||
if (routeResponse != null && routeResponse.Parameter)
|
||||
@ -534,25 +666,25 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
writer.WriteLine(") {").Indent();
|
||||
|
||||
//Generate function body
|
||||
|
||||
writer.WriteLine("var response = await fetch(").Indent();
|
||||
//Generate the url
|
||||
writer.WriteBreak().Write("var url = ");
|
||||
|
||||
//Generate the request url
|
||||
if (this.StaticCode)
|
||||
writer.WriteSeparator().Write('`').Write($"${{{this.ClientName}.BaseUrl}}");
|
||||
writer.Write('`').Write($"${{{this.ClientName}.BaseUrl}}");
|
||||
else
|
||||
writer.WriteSeparator().Write('`').Write("${this.Client.BaseUrl}");
|
||||
writer.Write('`').Write("${this.Client.BaseUrl}");
|
||||
|
||||
//Reconstruct the route syntax into a request url.
|
||||
var components = route.Syntax.Split('/');
|
||||
int argumentIndex = 0;
|
||||
foreach (var component in components)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(component))
|
||||
{
|
||||
if (writer.Peek() != '/')
|
||||
writer.Write('/');
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(component))
|
||||
{
|
||||
if (component.StartsWith("{"))
|
||||
{
|
||||
writer.Write("${").Write(parameters[argumentIndex++ + 1].Name).Write("}");
|
||||
@ -572,7 +704,10 @@ namespace MontoyaTech.Rest.Net
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteLine("`, {").Indent();
|
||||
writer.WriteLine("`;");
|
||||
|
||||
//Generate the request
|
||||
writer.WriteBreak().WriteLine("var request = {").Indent();
|
||||
|
||||
//Include credentials
|
||||
writer.WriteLine("credentials: 'include',");
|
||||
@ -586,28 +721,44 @@ namespace MontoyaTech.Rest.Net
|
||||
if (routeRequest.RequestType.IsAssignableTo(typeof(Stream)))
|
||||
{
|
||||
writer.WriteLine("headers: new Headers({ 'Content-Type': 'application/octet-stream' }),");
|
||||
writer.WriteLine("body: request,");
|
||||
writer.WriteLine("body: body,");
|
||||
}
|
||||
else if (routeRequest.Json)
|
||||
{
|
||||
|
||||
writer.WriteLine("body: JSON.stringify(request),");
|
||||
writer.WriteLine("body: JSON.stringify(body),");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine("body: request.toString(),");
|
||||
writer.WriteLine("body: body.toString(),");
|
||||
}
|
||||
}
|
||||
|
||||
writer.Outdent().WriteLine("}");
|
||||
writer.Outdent().WriteLine("};");
|
||||
|
||||
writer.Outdent().WriteLine(");");
|
||||
//Generate the response
|
||||
writer.WriteBreak().Write("var response = await fetch(");
|
||||
|
||||
if (this.StaticCode)
|
||||
writer.Write($"{this.ClientName}.UrlHandler ? {this.ClientName}.UrlHandler(url) : url");
|
||||
else
|
||||
writer.Write($"this.Client.UrlHandler ? this.Client.UrlHandler(url) : url");
|
||||
|
||||
writer.WriteSeparator();
|
||||
|
||||
if (this.StaticCode)
|
||||
writer.Write($"{this.ClientName}.RequestHandler ? {this.ClientName}.RequestHandler(request) : request");
|
||||
else
|
||||
writer.Write("this.Client.RequestHandler ? this.Client.RequestHandler(request) : request");
|
||||
|
||||
writer.WriteLine(");");
|
||||
|
||||
//Generate code to handle the response
|
||||
if (routeResponse != null)
|
||||
{
|
||||
writer.WriteBreak().WriteLine("if (response.ok) {").Indent();
|
||||
|
||||
if (routeResponse.ResponseType.IsAssignableTo(typeof(Stream)))
|
||||
if (routeResponse.ResponseType != null && routeResponse.ResponseType.IsAssignableTo(typeof(Stream)))
|
||||
{
|
||||
if (routeResponse.Parameter)
|
||||
{
|
||||
@ -664,14 +815,14 @@ namespace MontoyaTech.Rest.Net
|
||||
}
|
||||
}
|
||||
|
||||
writer.Outdent().WriteLine("} else {").Indent();
|
||||
writer.WriteLine("throw `Unexpected http response status: ${response.status}`;");
|
||||
writer.Outdent().WriteLine("}");
|
||||
|
||||
writer.WriteBreak().WriteLine("throw response;");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteBreak().WriteLine("if (!response.ok) {").Indent();
|
||||
writer.WriteLine("throw `Unexpected http response status: ${response.status}`;");
|
||||
writer.WriteLine("throw response;");
|
||||
writer.Outdent().WriteLine("}");
|
||||
}
|
||||
|
||||
|
@ -49,9 +49,9 @@ namespace MontoyaTech.Rest.Net
|
||||
if (target == null)
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
else if (string.IsNullOrWhiteSpace(method))
|
||||
throw new ArgumentException("Cannot be null or empty", nameof(method));
|
||||
throw new ArgumentException("Method cannot be null or empty", nameof(method));
|
||||
else if (string.IsNullOrWhiteSpace(syntax))
|
||||
throw new ArgumentException("Cannot be null or empty", nameof(syntax));
|
||||
throw new ArgumentException("Syntax cannot be null or empty", nameof(syntax));
|
||||
|
||||
this.Method = method;
|
||||
this.Syntax = syntax;
|
||||
|
@ -19,96 +19,130 @@ namespace MontoyaTech.Rest.Net
|
||||
/// <returns></returns>
|
||||
public static T Convert<T>(string input)
|
||||
{
|
||||
var typeCode = Type.GetTypeCode(typeof(T));
|
||||
var result = Convert(typeof(T), input);
|
||||
|
||||
if (typeCode == TypeCode.String)
|
||||
if (result == null)
|
||||
return default(T);
|
||||
|
||||
return (T)result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to a given type if possible. Otherwise returns null.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static object Convert(Type type, string input)
|
||||
{
|
||||
var typeCode = Type.GetTypeCode(type);
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return (dynamic)input;
|
||||
return Enum.Parse(type, input, true);
|
||||
}
|
||||
else if (typeCode == TypeCode.String)
|
||||
{
|
||||
return input;
|
||||
}
|
||||
else if (typeCode == TypeCode.Object)
|
||||
{
|
||||
var castOperator = typeof(T).GetMethod("op_Explicit", new[] { typeof(string) });
|
||||
var castOperator = type.GetMethod("op_Explicit", new[] { typeof(string) });
|
||||
|
||||
if (castOperator == null)
|
||||
return default(T);
|
||||
return null;
|
||||
|
||||
return (T)castOperator.Invoke(null, new[] { input });
|
||||
return castOperator.Invoke(null, new[] { input });
|
||||
}
|
||||
else if (typeCode == TypeCode.Double)
|
||||
{
|
||||
double.TryParse(input, out double result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Single)
|
||||
{
|
||||
float.TryParse(input, out float result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Decimal)
|
||||
{
|
||||
decimal.TryParse(input, out decimal result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Int64)
|
||||
{
|
||||
long.TryParse(input, out long result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Int32)
|
||||
{
|
||||
int.TryParse(input, out int result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Int16)
|
||||
{
|
||||
short.TryParse(input, out short result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.SByte)
|
||||
{
|
||||
sbyte.TryParse(input, out sbyte result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.UInt64)
|
||||
{
|
||||
ulong.TryParse(input, out ulong result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.UInt32)
|
||||
{
|
||||
uint.TryParse(input, out uint result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.UInt16)
|
||||
{
|
||||
ushort.TryParse(input, out ushort result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Byte)
|
||||
{
|
||||
byte.TryParse(input, out byte result);
|
||||
return (dynamic)result;
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Boolean)
|
||||
{
|
||||
if (input == "f" || input == "0" || input == "F")
|
||||
return (dynamic)false;
|
||||
return false;
|
||||
|
||||
bool.TryParse(input, out bool result);
|
||||
return ((dynamic)result);
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.DateTime)
|
||||
{
|
||||
DateTime.TryParse(input, out DateTime result);
|
||||
return ((dynamic)result);
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (typeCode == TypeCode.Char)
|
||||
{
|
||||
char.TryParse(input, out char result);
|
||||
return ((dynamic)result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return default(T);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ namespace MontoyaTech.Rest.Net
|
||||
/// <summary>
|
||||
/// The internal http listener.
|
||||
/// </summary>
|
||||
private HttpListener HttpListener = null;
|
||||
protected HttpListener HttpListener = null;
|
||||
|
||||
/// <summary>
|
||||
/// The list of routes this RouteListener is listening for.
|
||||
@ -256,12 +256,13 @@ namespace MontoyaTech.Rest.Net
|
||||
/// <param name="clientName"></param>
|
||||
/// <param name="staticCode"></param>
|
||||
/// <returns></returns>
|
||||
public string GenerateJavascriptClient(string clientName = "Client", bool staticCode = false)
|
||||
public string GenerateJavascriptClient(string clientName = "Client", bool staticCode = false, bool useJsonNames = false)
|
||||
{
|
||||
var generator = new RestJavascriptClientGenerator();
|
||||
|
||||
generator.ClientName = clientName;
|
||||
generator.StaticCode = staticCode;
|
||||
generator.UseJsonNames = useJsonNames;
|
||||
|
||||
return generator.Generate(this);
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ namespace MontoyaTech.Rest.Net
|
||||
//Set the arguments to null, initially.
|
||||
arguments = null;
|
||||
|
||||
//If the input url is invalid, default to false.
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
return false;
|
||||
|
||||
//Trim the url and the syntax.
|
||||
url = url.Trim();
|
||||
syntax = syntax.Trim();
|
||||
@ -42,17 +46,27 @@ namespace MontoyaTech.Rest.Net
|
||||
if (url.StartsWith("http://"))
|
||||
{
|
||||
url = url.Substring(7);
|
||||
url = url.Substring(url.IndexOf('/'));
|
||||
|
||||
//If there is a slash, skip to the first one, or default to empty path.
|
||||
if (url.Contains('/'))
|
||||
url = url.Substring(url.IndexOf('/'));
|
||||
else
|
||||
url = "/";
|
||||
}
|
||||
else if (url.StartsWith("https://"))
|
||||
{
|
||||
url = url.Substring(8);
|
||||
url = url.Substring(url.IndexOf('/'));
|
||||
|
||||
//If there is a slash, skip to the first one, or default to empty path.
|
||||
if (url.Contains('/'))
|
||||
url = url.Substring(url.IndexOf('/'));
|
||||
else
|
||||
url = "/";
|
||||
}
|
||||
|
||||
//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();
|
||||
var urlSegments = url.Split('/').Select(segment => segment.Trim()).ToArray();
|
||||
var syntaxSegments = syntax.Split('/').Select(segment => segment.Trim()).ToArray();
|
||||
|
||||
//If we have no url segments, and we have no syntax segments, this is a root match which is fine.
|
||||
if (urlSegments.Length == 0 && syntaxSegments.Length == 0)
|
||||
@ -85,20 +99,25 @@ namespace MontoyaTech.Rest.Net
|
||||
return false;
|
||||
}
|
||||
//If the segments syntax is a double wild card then everything after this is a match.
|
||||
else if (syntaxSegment == "**")
|
||||
else if (syntaxSegment == "**" && urlSegment != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//If we ran out of url segments, and this syntax segment is a wild card, this is okay.
|
||||
else if (urlSegment == null && syntaxSegment == "*")
|
||||
//If we ran out of url segments, and this syntax segment is a wild card, this is not a match.
|
||||
else if (syntaxSegment == "*" && urlSegment != null)
|
||||
{
|
||||
return true;
|
||||
//Allowed
|
||||
}
|
||||
//If we have a syntaxSegment but no urlSegment, this can't be a match.
|
||||
else if (urlSegment == null && syntaxSegment != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//If both the url segment and syntax segment are empty then this is allowed
|
||||
else if (urlSegment != null && urlSegment.Length == 0 && syntaxSegment.Length == 0)
|
||||
{
|
||||
//Allowed
|
||||
}
|
||||
//If we have a url segment see if it matches against the syntax segment.
|
||||
else if (urlSegment != null)
|
||||
{
|
||||
|
@ -22,6 +22,11 @@ namespace MontoyaTech.Rest.Net
|
||||
/// </summary>
|
||||
public bool Json = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the request is a dynamic type. Default is false.
|
||||
/// </summary>
|
||||
public bool Dynamic = false;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a default route request.
|
||||
/// </summary>
|
||||
|
@ -23,10 +23,15 @@ namespace MontoyaTech.Rest.Net
|
||||
public bool Json = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the response is passed as a parameter to the route function.
|
||||
/// Whether or not the response is passed as a parameter to the route function. Default is false.
|
||||
/// </summary>
|
||||
public bool Parameter = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the response is a dynamic type. Default is false.
|
||||
/// </summary>
|
||||
public bool Dynamic = false;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a default route response.
|
||||
/// </summary>
|
||||
|
@ -18,5 +18,39 @@ namespace MontoyaTech.Rest.Net
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public static string Separate(this IList<string> input, char separator)
|
||||
{
|
||||
if (input == null || input.Count == 0)
|
||||
return "";
|
||||
else if (input.Count < 2)
|
||||
return input[0];
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append(input[0]);
|
||||
|
||||
for (int i = 1; i < input.Count; i++)
|
||||
builder.Append(separator).Append(input[i]);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string Separate(this IList<string> input, string separator)
|
||||
{
|
||||
if (input == null || input.Count == 0)
|
||||
return "";
|
||||
else if (input.Count < 2)
|
||||
return input[0];
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append(input[0]);
|
||||
|
||||
for (int i = 1; i < input.Count; i++)
|
||||
builder.Append(separator).Append(input[i]);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user