Added RouteName and Request/Response handling to the code generator. More work is needed.
This commit is contained in:
		| @@ -13,14 +13,17 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|     { | ||||
|         public string BaseUrl; | ||||
|  | ||||
|         private HttpClient HttpClient; | ||||
|         public HttpClient HttpClient; | ||||
|  | ||||
|         public TestApi Test; | ||||
|  | ||||
|         public AuthApi Auth; | ||||
|  | ||||
|         public Client(string baseUrl) | ||||
|         { | ||||
|             this.BaseUrl = baseUrl; | ||||
|             this.Test = new TestApi(this); | ||||
|             this.Auth = new AuthApi(this); | ||||
|             this.HttpClient = new HttpClient(); | ||||
|             this.HttpClient.DefaultRequestHeaders.Add("Accept", "*/*"); | ||||
|             this.HttpClient.DefaultRequestHeaders.Add("Connection", "keep-alive"); | ||||
| @@ -38,26 +41,72 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|  | ||||
|             public string Status() | ||||
|             { | ||||
|                 var request = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/status"); | ||||
|                 return default; | ||||
|                 var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/status"); | ||||
|  | ||||
|                 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) | ||||
|             { | ||||
|                 var request = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/add/{a}/{b}"); | ||||
|                 return default; | ||||
|                 var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/add/{a}/{b}"); | ||||
|  | ||||
|                 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 Signup(User user) | ||||
|         public class AuthApi | ||||
|         { | ||||
|                 var request = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/signup/{user}"); | ||||
|                 return default; | ||||
|             public Client Client; | ||||
|  | ||||
|             public AuthApi(Client client) | ||||
|             { | ||||
|                 this.Client = client; | ||||
|             } | ||||
|  | ||||
|             public User Json() | ||||
|             public bool UserExists(string name) | ||||
|             { | ||||
|                 var request = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/json"); | ||||
|                 return default; | ||||
|                 var message = new HttpRequestMessage(HttpMethod.Get, $"{this.Client.BaseUrl}/auth/{name}"); | ||||
|  | ||||
|                 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 void Signup(User request) | ||||
|             { | ||||
|                 var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/auth/signup"); | ||||
|  | ||||
|                 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.Net; | ||||
| using MontoyaTech.Rest.Net; | ||||
| using System.Net.Mime; | ||||
|  | ||||
| namespace MontoyaTech.Rest.Net.Example | ||||
| { | ||||
| @@ -18,15 +19,12 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|  | ||||
|             public ulong Property { get; set; } | ||||
|  | ||||
|             public User() { } | ||||
|  | ||||
|             public User(string name) | ||||
|             { | ||||
|                 this.Name = name; | ||||
|             } | ||||
|  | ||||
|             public static explicit operator User(string input) | ||||
|             { | ||||
|                 return new User(input.ToString()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public static void Main(string[] args) | ||||
| @@ -34,24 +32,23 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|             var listener = new RouteListener(8080, | ||||
|                 new Route(HttpRequestMethod.Get, "/status", Status), | ||||
|                 new Route<double, double>(HttpRequestMethod.Post, "/add/{a}/{b}", Add), | ||||
|                 new Route<User>(HttpRequestMethod.Post, "/signup/{username}", Signup), | ||||
|                 new Route(HttpRequestMethod.Get, "/json", Json) | ||||
|                 new Route<string>(HttpRequestMethod.Get, "/auth/{username}", Exists), | ||||
|                 new Route(HttpRequestMethod.Post, "/auth/signup", Signup), | ||||
|                 new Route(HttpRequestMethod.Get, "/auth/", Json) | ||||
|             ); | ||||
|  | ||||
|             string code = CodeGenerator.GenerateCSharpClient(listener.Routes); | ||||
|  | ||||
|             Console.WriteLine(code); | ||||
|  | ||||
|             Console.ReadLine(); | ||||
|  | ||||
|             listener.RequestPreProcessEvent += (HttpListenerContext context) => { | ||||
|                 Console.WriteLine("Request start: " + context.Request.RawUrl); | ||||
|                 Console.WriteLine($"[{context.Request.HttpMethod}] Request start: " + context.Request.RawUrl); | ||||
|                 return true; | ||||
|             }; | ||||
|  | ||||
|             listener.RequestPostProcessEvent += (HttpListenerContext context) => | ||||
|             { | ||||
|                 Console.WriteLine("Request end: " + context.Request.RawUrl); | ||||
|                 Console.WriteLine($"[{context.Request.HttpMethod}] Request end: " + context.Request.RawUrl); | ||||
|             }; | ||||
|  | ||||
|             listener.Start(); | ||||
| @@ -61,7 +58,11 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|             foreach (var route in listener.Routes) | ||||
|                 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(); | ||||
|         } | ||||
| @@ -80,12 +81,6 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|             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")] | ||||
|         [RouteRequest(typeof(User))] | ||||
| @@ -94,7 +89,25 @@ namespace MontoyaTech.Rest.Net.Example | ||||
|             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))] | ||||
|         public static HttpListenerResponse Json(HttpListenerContext context) | ||||
|         { | ||||
|   | ||||
| @@ -293,7 +293,7 @@ namespace MontoyaTech.Rest.Net | ||||
|  | ||||
|             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. | ||||
|             foreach (var group in routeGroups) | ||||
| @@ -353,8 +353,6 @@ namespace MontoyaTech.Rest.Net | ||||
|                         GenerateCSharpIncludedProperty(property, writer); | ||||
|  | ||||
|             writer.Outdent().WriteLine("}"); | ||||
|  | ||||
|             System.Diagnostics.Debugger.Break(); | ||||
|         } | ||||
|  | ||||
|         private static void GenerateCSharpIncludedField(FieldInfo field, CodeWriter writer) | ||||
| @@ -407,11 +405,14 @@ namespace MontoyaTech.Rest.Net | ||||
|  | ||||
|             var methodInfo = route.GetTarget().GetMethodInfo(); | ||||
|  | ||||
|             var routeName = methodInfo.GetCustomAttribute<RouteName>(); | ||||
|  | ||||
|             var routeRequest = methodInfo.GetCustomAttribute<RouteRequest>(); | ||||
|  | ||||
|             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(); | ||||
|  | ||||
| @@ -432,21 +433,8 @@ namespace MontoyaTech.Rest.Net | ||||
|  | ||||
|             writer.WriteLine(")").WriteLine("{").Indent(); | ||||
|  | ||||
|             //Generate code to send a request | ||||
|             /* | ||||
|              * 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("); | ||||
|             //Generate the message code | ||||
|             writer.WriteBreak().Write($"var message = new HttpRequestMessage("); | ||||
|  | ||||
|             switch (route.Method.ToLower()) | ||||
|             { | ||||
| @@ -460,12 +448,60 @@ namespace MontoyaTech.Rest.Net | ||||
|                     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) | ||||
|                 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("}"); | ||||
|         } | ||||
|   | ||||
| @@ -29,6 +29,17 @@ namespace MontoyaTech.Rest.Net | ||||
|         /// </summary> | ||||
|         public ushort Port = 8081; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Returns the BaseUrl for this RouteListener. | ||||
|         /// </summary> | ||||
|         public string BaseUrl | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return $"http://localhost:{this.Port}"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// An event to preprocess routes before the route is executed. | ||||
|         /// </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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user