Added RouteName and Request/Response handling to the code generator. More work is needed.
This commit is contained in:
parent
74f8921f7a
commit
1475159f1c
@ -13,14 +13,17 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
{
|
{
|
||||||
public string BaseUrl;
|
public string BaseUrl;
|
||||||
|
|
||||||
private HttpClient HttpClient;
|
public HttpClient HttpClient;
|
||||||
|
|
||||||
public TestApi Test;
|
public TestApi Test;
|
||||||
|
|
||||||
|
public AuthApi Auth;
|
||||||
|
|
||||||
public Client(string baseUrl)
|
public Client(string baseUrl)
|
||||||
{
|
{
|
||||||
this.BaseUrl = baseUrl;
|
this.BaseUrl = baseUrl;
|
||||||
this.Test = new TestApi(this);
|
this.Test = new TestApi(this);
|
||||||
|
this.Auth = new AuthApi(this);
|
||||||
this.HttpClient = new HttpClient();
|
this.HttpClient = new HttpClient();
|
||||||
this.HttpClient.DefaultRequestHeaders.Add("Accept", "*/*");
|
this.HttpClient.DefaultRequestHeaders.Add("Accept", "*/*");
|
||||||
this.HttpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
|
this.HttpClient.DefaultRequestHeaders.Add("Connection", "keep-alive");
|
||||||
@ -38,26 +41,72 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
|
|
||||||
public string Status()
|
public string Status()
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/status");
|
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/status");
|
||||||
return default;
|
|
||||||
|
var response = this.Client.HttpClient.Send(message);
|
||||||
|
|
||||||
|
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||||
|
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||||
|
else
|
||||||
|
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Add(double a, double b)
|
public string Add(double a, double b)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/add/{a}/{b}");
|
var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/add/{a}/{b}");
|
||||||
return default;
|
|
||||||
|
var response = this.Client.HttpClient.Send(message);
|
||||||
|
|
||||||
|
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||||
|
return Newtonsoft.Json.JsonConvert.DeserializeObject<string>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||||
|
else
|
||||||
|
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthApi
|
||||||
|
{
|
||||||
|
public Client Client;
|
||||||
|
|
||||||
|
public AuthApi(Client client)
|
||||||
|
{
|
||||||
|
this.Client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Signup(User user)
|
public bool UserExists(string name)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/signup/{user}");
|
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/auth/{name}");
|
||||||
return default;
|
|
||||||
|
var response = this.Client.HttpClient.Send(message);
|
||||||
|
|
||||||
|
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||||
|
return Newtonsoft.Json.JsonConvert.DeserializeObject<bool>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||||
|
else
|
||||||
|
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public User Json()
|
public void Signup(User request)
|
||||||
{
|
{
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/json");
|
var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/auth/signup");
|
||||||
return default;
|
|
||||||
|
message.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
||||||
|
|
||||||
|
var response = this.Client.HttpClient.Send(message);
|
||||||
|
|
||||||
|
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||||
|
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User Get()
|
||||||
|
{
|
||||||
|
var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/auth");
|
||||||
|
|
||||||
|
var response = this.Client.HttpClient.Send(message);
|
||||||
|
|
||||||
|
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||||
|
return Newtonsoft.Json.JsonConvert.DeserializeObject<User>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||||
|
else
|
||||||
|
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using MontoyaTech.Rest.Net;
|
using MontoyaTech.Rest.Net;
|
||||||
|
using System.Net.Mime;
|
||||||
|
|
||||||
namespace MontoyaTech.Rest.Net.Example
|
namespace MontoyaTech.Rest.Net.Example
|
||||||
{
|
{
|
||||||
@ -18,15 +19,12 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
|
|
||||||
public ulong Property { get; set; }
|
public ulong Property { get; set; }
|
||||||
|
|
||||||
|
public User() { }
|
||||||
|
|
||||||
public User(string name)
|
public User(string name)
|
||||||
{
|
{
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static explicit operator User(string input)
|
|
||||||
{
|
|
||||||
return new User(input.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
@ -34,24 +32,23 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
var listener = new RouteListener(8080,
|
var listener = new RouteListener(8080,
|
||||||
new Route(HttpRequestMethod.Get, "/status", Status),
|
new Route(HttpRequestMethod.Get, "/status", Status),
|
||||||
new Route<double, double>(HttpRequestMethod.Post, "/add/{a}/{b}", Add),
|
new Route<double, double>(HttpRequestMethod.Post, "/add/{a}/{b}", Add),
|
||||||
new Route<User>(HttpRequestMethod.Post, "/signup/{username}", Signup),
|
new Route<string>(HttpRequestMethod.Get, "/auth/{username}", Exists),
|
||||||
new Route(HttpRequestMethod.Get, "/json", Json)
|
new Route(HttpRequestMethod.Post, "/auth/signup", Signup),
|
||||||
|
new Route(HttpRequestMethod.Get, "/auth/", Json)
|
||||||
);
|
);
|
||||||
|
|
||||||
string code = CodeGenerator.GenerateCSharpClient(listener.Routes);
|
string code = CodeGenerator.GenerateCSharpClient(listener.Routes);
|
||||||
|
|
||||||
Console.WriteLine(code);
|
Console.WriteLine(code);
|
||||||
|
|
||||||
Console.ReadLine();
|
|
||||||
|
|
||||||
listener.RequestPreProcessEvent += (HttpListenerContext context) => {
|
listener.RequestPreProcessEvent += (HttpListenerContext context) => {
|
||||||
Console.WriteLine("Request start: " + context.Request.RawUrl);
|
Console.WriteLine($"[{context.Request.HttpMethod}] Request start: " + context.Request.RawUrl);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
listener.RequestPostProcessEvent += (HttpListenerContext context) =>
|
listener.RequestPostProcessEvent += (HttpListenerContext context) =>
|
||||||
{
|
{
|
||||||
Console.WriteLine("Request end: " + context.Request.RawUrl);
|
Console.WriteLine($"[{context.Request.HttpMethod}] Request end: " + context.Request.RawUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
listener.Start();
|
listener.Start();
|
||||||
@ -61,7 +58,11 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
foreach (var route in listener.Routes)
|
foreach (var route in listener.Routes)
|
||||||
Console.WriteLine($"- [{route.Method}] {route.Syntax}");
|
Console.WriteLine($"- [{route.Method}] {route.Syntax}");
|
||||||
|
|
||||||
Console.WriteLine($"Rest api server running at http://localhost:{listener.Port}");
|
Console.WriteLine($"Rest api server running at {listener.BaseUrl}");
|
||||||
|
|
||||||
|
var client = new Client(listener.BaseUrl);
|
||||||
|
|
||||||
|
var result = client.Auth.Get();
|
||||||
|
|
||||||
listener.Block();
|
listener.Block();
|
||||||
}
|
}
|
||||||
@ -80,12 +81,6 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
return context.Response.WithStatus(HttpStatusCode.OK).WithText((a + b).ToString());
|
return context.Response.WithStatus(HttpStatusCode.OK).WithText((a + b).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
[RouteGroup("Test")]
|
|
||||||
[RouteResponse(typeof(string))]
|
|
||||||
public static HttpListenerResponse Signup(HttpListenerContext context, User user)
|
|
||||||
{
|
|
||||||
return context.Response.WithStatus(HttpStatusCode.OK).WithText("User:" + user.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
[RouteGroup("Test")]
|
[RouteGroup("Test")]
|
||||||
[RouteRequest(typeof(User))]
|
[RouteRequest(typeof(User))]
|
||||||
@ -94,7 +89,25 @@ namespace MontoyaTech.Rest.Net.Example
|
|||||||
return context.Response.WithStatus(HttpStatusCode.OK);
|
return context.Response.WithStatus(HttpStatusCode.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
[RouteGroup("Test")]
|
[RouteGroup("Auth")]
|
||||||
|
[RouteName("UserExists")]
|
||||||
|
[RouteResponse(typeof(bool))]
|
||||||
|
public static HttpListenerResponse Exists(HttpListenerContext context, string name)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Auth.Exists called, name:" + name);
|
||||||
|
|
||||||
|
return context.Response.WithStatus(HttpStatusCode.OK).WithJson(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RouteGroup("Auth")]
|
||||||
|
[RouteRequest(typeof(User))]
|
||||||
|
public static HttpListenerResponse Signup(HttpListenerContext context)
|
||||||
|
{
|
||||||
|
return context.Response.WithStatus(HttpStatusCode.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RouteGroup("Auth")]
|
||||||
|
[RouteName("Get")]
|
||||||
[RouteResponse(typeof(User))]
|
[RouteResponse(typeof(User))]
|
||||||
public static HttpListenerResponse Json(HttpListenerContext context)
|
public static HttpListenerResponse Json(HttpListenerContext context)
|
||||||
{
|
{
|
||||||
|
@ -293,7 +293,7 @@ namespace MontoyaTech.Rest.Net
|
|||||||
|
|
||||||
writer.WriteBreak().WriteLine("public string BaseUrl;");
|
writer.WriteBreak().WriteLine("public string BaseUrl;");
|
||||||
|
|
||||||
writer.WriteBreak().WriteLine("private HttpClient HttpClient;");
|
writer.WriteBreak().WriteLine("public HttpClient HttpClient;");
|
||||||
|
|
||||||
//Create fields foreach route group so they can be accessed.
|
//Create fields foreach route group so they can be accessed.
|
||||||
foreach (var group in routeGroups)
|
foreach (var group in routeGroups)
|
||||||
@ -353,8 +353,6 @@ namespace MontoyaTech.Rest.Net
|
|||||||
GenerateCSharpIncludedProperty(property, writer);
|
GenerateCSharpIncludedProperty(property, writer);
|
||||||
|
|
||||||
writer.Outdent().WriteLine("}");
|
writer.Outdent().WriteLine("}");
|
||||||
|
|
||||||
System.Diagnostics.Debugger.Break();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateCSharpIncludedField(FieldInfo field, CodeWriter writer)
|
private static void GenerateCSharpIncludedField(FieldInfo field, CodeWriter writer)
|
||||||
@ -407,11 +405,14 @@ namespace MontoyaTech.Rest.Net
|
|||||||
|
|
||||||
var methodInfo = route.GetTarget().GetMethodInfo();
|
var methodInfo = route.GetTarget().GetMethodInfo();
|
||||||
|
|
||||||
|
var routeName = methodInfo.GetCustomAttribute<RouteName>();
|
||||||
|
|
||||||
var routeRequest = methodInfo.GetCustomAttribute<RouteRequest>();
|
var routeRequest = methodInfo.GetCustomAttribute<RouteRequest>();
|
||||||
|
|
||||||
var routeResponse = methodInfo.GetCustomAttribute<RouteResponse>();
|
var routeResponse = methodInfo.GetCustomAttribute<RouteResponse>();
|
||||||
|
|
||||||
writer.Write($"public {(routeResponse == null ? "void" : GetTypeFullyResolvedName(routeResponse.ResponseType))} {methodInfo.Name}(");
|
//Construct the routes request function
|
||||||
|
writer.Write($"public {(routeResponse == null ? "void" : GetTypeFullyResolvedName(routeResponse.ResponseType))} {(routeName == null ? methodInfo.Name : routeName.Name)}(");
|
||||||
|
|
||||||
var parameters = methodInfo.GetParameters();
|
var parameters = methodInfo.GetParameters();
|
||||||
|
|
||||||
@ -432,21 +433,8 @@ namespace MontoyaTech.Rest.Net
|
|||||||
|
|
||||||
writer.WriteLine(")").WriteLine("{").Indent();
|
writer.WriteLine(")").WriteLine("{").Indent();
|
||||||
|
|
||||||
//Generate code to send a request
|
//Generate the message code
|
||||||
/*
|
writer.WriteBreak().Write($"var message = new HttpRequestMessage(");
|
||||||
* var response = HttpClient.Send(new HttpRequestMessage(HttpMethod.Post, $"{Auth0Url}/oauth/token")
|
|
||||||
{
|
|
||||||
Content = new FormUrlEncodedContent(new[]
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>("grant_type", "authorization_code"),
|
|
||||||
new KeyValuePair<string, string>("code", code),
|
|
||||||
new KeyValuePair<string, string>("redirect_uri", redirectUrl),
|
|
||||||
new KeyValuePair<string, string>("client_id", ClientId)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
|
|
||||||
writer.Write($"var request = new HttpRequestMessage(");
|
|
||||||
|
|
||||||
switch (route.Method.ToLower())
|
switch (route.Method.ToLower())
|
||||||
{
|
{
|
||||||
@ -460,12 +448,60 @@ namespace MontoyaTech.Rest.Net
|
|||||||
throw new NotSupportedException("Unsupport route method:" + route.Method);
|
throw new NotSupportedException("Unsupport route method:" + route.Method);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteSeparator().Write('$').WriteString($"{{this.Client.BaseUrl}}/{route.Syntax}");
|
writer.WriteSeparator().Write('$').Write('"').Write("{this.Client.BaseUrl}");
|
||||||
|
|
||||||
writer.WriteLine(");");
|
//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))
|
||||||
|
{
|
||||||
|
writer.Write('/');
|
||||||
|
|
||||||
|
if (component.StartsWith("{"))
|
||||||
|
{
|
||||||
|
writer.Write("{").Write(parameters[argumentIndex++ + 1].Name).Write("}");
|
||||||
|
}
|
||||||
|
else if (component == "*")
|
||||||
|
{
|
||||||
|
writer.Write("*");
|
||||||
|
}
|
||||||
|
else if (component == "**")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.Write(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Write('"').WriteLine(");");
|
||||||
|
|
||||||
|
//Add the request content if any.
|
||||||
|
if (routeRequest != null)
|
||||||
|
{
|
||||||
|
writer.WriteBreak().WriteLine("message.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request));");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate the response code
|
||||||
|
writer.WriteBreak().WriteLine("var response = this.Client.HttpClient.Send(message);");
|
||||||
|
|
||||||
|
//Handle the response
|
||||||
if (routeResponse != null)
|
if (routeResponse != null)
|
||||||
writer.WriteLine("return default;");
|
{
|
||||||
|
writer.WriteBreak().WriteLine("if (response.StatusCode == System.Net.HttpStatusCode.OK)").Indent();
|
||||||
|
writer.WriteLine($"return Newtonsoft.Json.JsonConvert.DeserializeObject<{GetTypeFullyResolvedName(routeResponse.ResponseType)}>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
|
||||||
|
writer.Outdent().WriteLine("else").Indent();
|
||||||
|
writer.WriteLine(@"throw new Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);").Outdent();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WriteBreak().WriteLine("if (response.StatusCode == System.Net.HttpStatusCode.OK)").Indent();
|
||||||
|
writer.WriteLine(@"throw new Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);").Outdent();
|
||||||
|
}
|
||||||
|
|
||||||
writer.Outdent().WriteLine("}");
|
writer.Outdent().WriteLine("}");
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,17 @@ namespace MontoyaTech.Rest.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ushort Port = 8081;
|
public ushort Port = 8081;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the BaseUrl for this RouteListener.
|
||||||
|
/// </summary>
|
||||||
|
public string BaseUrl
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return $"http://localhost:{this.Port}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An event to preprocess routes before the route is executed.
|
/// An event to preprocess routes before the route is executed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
38
Rest.Net/RouteName.cs
Normal file
38
Rest.Net/RouteName.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MontoyaTech.Rest.Net
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The outline of an attribute that allows you to rename an attribute in
|
||||||
|
/// the output code generation.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
public class RouteName : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of this Route.
|
||||||
|
/// </summary>
|
||||||
|
public string Name = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new default RouteName.
|
||||||
|
/// </summary>
|
||||||
|
public RouteName() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new RouteName with a given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
public RouteName(string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
throw new ArgumentException("Cannot be null or whitespace", nameof(name));
|
||||||
|
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user