diff --git a/Rest.Net.Example/Client.cs b/Rest.Net.Example/Client.cs index 8947e6b..4307c2e 100644 --- a/Rest.Net.Example/Client.cs +++ b/Rest.Net.Example/Client.cs @@ -8,6 +8,7 @@ namespace MontoyaTech.Rest.Net.Example { using System; using System.Net.Http; + using Newtonsoft.Json; public class Client { @@ -46,7 +47,7 @@ namespace MontoyaTech.Rest.Net.Example var response = this.Client.HttpClient.Send(message); if (response.StatusCode == System.Net.HttpStatusCode.OK) - return Newtonsoft.Json.JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); + return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); else throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode); } @@ -58,7 +59,7 @@ namespace MontoyaTech.Rest.Net.Example var response = this.Client.HttpClient.Send(message); if (response.StatusCode == System.Net.HttpStatusCode.OK) - return Newtonsoft.Json.JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); + return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); else throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode); } @@ -80,7 +81,7 @@ namespace MontoyaTech.Rest.Net.Example var response = this.Client.HttpClient.Send(message); if (response.StatusCode == System.Net.HttpStatusCode.OK) - return Newtonsoft.Json.JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); + return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); else throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode); } @@ -89,7 +90,7 @@ namespace MontoyaTech.Rest.Net.Example { var message = new HttpRequestMessage(HttpMethod.Post, $"{this.Client.BaseUrl}/auth/signup"); - message.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request)); + message.Content = new StringContent(JsonConvert.SerializeObject(request)); var response = this.Client.HttpClient.Send(message); @@ -104,7 +105,7 @@ namespace MontoyaTech.Rest.Net.Example var response = this.Client.HttpClient.Send(message); if (response.StatusCode == System.Net.HttpStatusCode.OK) - return Newtonsoft.Json.JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); + return JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); else throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode); } diff --git a/Rest.Net.Example/Program.cs b/Rest.Net.Example/Program.cs index b434522..a4e6d87 100644 --- a/Rest.Net.Example/Program.cs +++ b/Rest.Net.Example/Program.cs @@ -37,7 +37,7 @@ namespace MontoyaTech.Rest.Net.Example new Route(HttpRequestMethod.Get, "/auth/", Json) ); - string code = CodeGenerator.GenerateCSharpClient(listener.Routes); + string code = ClientCodeGenerator.GenerateCSharpClient(listener.Routes); Console.WriteLine(code); diff --git a/Rest.Net/CodeGenerator.cs b/Rest.Net/ClientCodeGenerator.cs similarity index 80% rename from Rest.Net/CodeGenerator.cs rename to Rest.Net/ClientCodeGenerator.cs index c1f6b79..9b7f815 100644 --- a/Rest.Net/CodeGenerator.cs +++ b/Rest.Net/ClientCodeGenerator.cs @@ -15,8 +15,13 @@ namespace MontoyaTech.Rest.Net /// A class that can take a set of routes and generate code /// for a client that can be used to interact with them. /// - public class CodeGenerator + public class ClientCodeGenerator { + /// + /// Returns whether or not a given type belongs to DotNet. + /// + /// + /// private static bool IsTypeDotNet(Type type) { if (type.Assembly.GetName().Name == "System.Private.CoreLib") @@ -25,6 +30,11 @@ namespace MontoyaTech.Rest.Net return false; } + /// + /// Finds all the dependencies for a given type and returns them. + /// + /// + /// private static List FindTypeDependencies(Type type) { var dependencies = new HashSet(); @@ -85,6 +95,11 @@ namespace MontoyaTech.Rest.Net return dependencies.ToList(); } + /// + /// Finds all the types that a given route depends on to function. + /// + /// + /// private static List FindRouteDependencies(Route route) { var dependencies = new HashSet(); @@ -133,6 +148,11 @@ namespace MontoyaTech.Rest.Net return dependencies.ToList(); } + /// + /// Finds all the types that a given set of routes depend on to function. + /// + /// + /// private static List FindRoutesDependencies(List routes) { var dependencies = new HashSet(); @@ -150,6 +170,11 @@ namespace MontoyaTech.Rest.Net return dependencies.ToList(); } + /// + /// Returns the fully resolve name for a given type. + /// + /// + /// private static string GetTypeFullyResolvedName(Type type) { if (IsTypeDotNet(type)) @@ -252,6 +277,11 @@ namespace MontoyaTech.Rest.Net } } + /// + /// Finds all the route groupings from a set of routes and returns those groups. + /// + /// + /// private static Dictionary> FindRouteGroups(List routes) { var groups = new Dictionary>(); @@ -278,7 +308,24 @@ namespace MontoyaTech.Rest.Net return groups; } - public static string GenerateCSharpClient(List routes) + /// + /// Generates a CSharpClient from a RouteListener. + /// + /// + /// The name of the Client class, default is Client. + /// The generated C# code. + public static string GenerateCSharpClient(RouteListener listener, string name = "Client") + { + return GenerateCSharpClient(listener.Routes, name); + } + + /// + /// Generates a CSharpClient from a given set of Routes. + /// + /// + /// The name of the Client class, default is Client. + /// + public static string GenerateCSharpClient(List routes, string name = "Client") { var includedTypes = FindRoutesDependencies(routes); @@ -288,8 +335,9 @@ namespace MontoyaTech.Rest.Net writer.WriteLine("using System;"); writer.WriteLine("using System.Net.Http;"); + writer.WriteLine("using Newtonsoft.Json;"); - writer.WriteBreak().WriteLine("public class Client").WriteLine("{").Indent(); + writer.WriteBreak().WriteLine($"public class {name}").WriteLine("{").Indent(); writer.WriteBreak().WriteLine("public string BaseUrl;"); @@ -326,12 +374,22 @@ namespace MontoyaTech.Rest.Net return writer.ToString(); } + /// + /// Generates C# for a set of included types. + /// + /// + /// private static void GenerateCSharpIncludedTypes(List types, CodeWriter writer) { foreach (var type in types) GenerateCSharpIncludedType(type, writer); } + /// + /// Generates C# for a given included type. + /// + /// + /// private static void GenerateCSharpIncludedType(Type type, CodeWriter writer) { writer.WriteBreak(); @@ -355,6 +413,11 @@ namespace MontoyaTech.Rest.Net writer.Outdent().WriteLine("}"); } + /// + /// Generates C# for a field inside an included type. + /// + /// + /// private static void GenerateCSharpIncludedField(FieldInfo field, CodeWriter writer) { writer.WriteBreak(); @@ -362,6 +425,11 @@ namespace MontoyaTech.Rest.Net writer.WriteLine($"public {GetTypeFullyResolvedName(field.FieldType)} {field.Name};"); } + /// + /// Generates C# for a property inside an included type. + /// + /// + /// private static void GenerateCSharpIncludedProperty(PropertyInfo property, CodeWriter writer) { writer.WriteBreak(); @@ -369,12 +437,23 @@ namespace MontoyaTech.Rest.Net writer.WriteLine($"public {GetTypeFullyResolvedName(property.PropertyType)} {property.Name} {{ get; set; }}"); } + /// + /// Generates C# for a set of route groups. + /// + /// + /// private static void GenerateCSharpRouteGroups(Dictionary> groups, CodeWriter writer) { foreach (var group in groups) GenerateCSharpRouteGroup(group.Key, group.Value, writer); } + /// + /// Generates C# for a given route group. + /// + /// + /// + /// private static void GenerateCSharpRouteGroup(string name, List routes, CodeWriter writer) { writer.WriteBreak(); @@ -399,6 +478,12 @@ namespace MontoyaTech.Rest.Net writer.Outdent().WriteLine("}"); } + /// + /// Generates a C# function for a given route. + /// + /// + /// + /// private static void GenerateCSharpRouteFunction(Route route, CodeWriter writer) { writer.WriteBreak(); @@ -411,9 +496,10 @@ namespace MontoyaTech.Rest.Net var routeResponse = methodInfo.GetCustomAttribute(); - //Construct the routes request function + //Generate the route function header writer.Write($"public {(routeResponse == null ? "void" : GetTypeFullyResolvedName(routeResponse.ResponseType))} {(routeName == null ? methodInfo.Name : routeName.Name)}("); + //Generate the functions parameters var parameters = methodInfo.GetParameters(); if (parameters != null) @@ -482,9 +568,7 @@ namespace MontoyaTech.Rest.Net //Add the request content if any. if (routeRequest != null) - { - writer.WriteBreak().WriteLine("message.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(request));"); - } + writer.WriteBreak().WriteLine("message.Content = new StringContent(JsonConvert.SerializeObject(request));"); //Generate the response code writer.WriteBreak().WriteLine("var response = this.Client.HttpClient.Send(message);"); @@ -493,7 +577,7 @@ namespace MontoyaTech.Rest.Net if (routeResponse != null) { 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.WriteLine($"return 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(); } @@ -503,12 +587,19 @@ namespace MontoyaTech.Rest.Net writer.WriteLine(@"throw new Exception(""Unexpected Http Response StatusCode:"" + response.StatusCode);").Outdent(); } + //Close off the route function. writer.Outdent().WriteLine("}"); } - public static string GenerateJavascriptClient(IList routes) + /// + /// Generates a Javascript client from a given set of routes. + /// + /// + /// + /// + public static string GenerateJavascriptClient(List routes) { - return null; + throw new NotImplementedException(); } } } diff --git a/Rest.Net/Rest.Net.csproj b/Rest.Net/Rest.Net.csproj index 34bfb69..66a48a1 100644 --- a/Rest.Net/Rest.Net.csproj +++ b/Rest.Net/Rest.Net.csproj @@ -17,7 +17,7 @@ MontoyaTech.Rest.Net MontoyaTech.Rest.Net True - 1.1.8 + 1.1.9 Logo_Symbol_Black_Outline.png diff --git a/Rest.Net/RouteListener.cs b/Rest.Net/RouteListener.cs index f5ce862..67dd520 100644 --- a/Rest.Net/RouteListener.cs +++ b/Rest.Net/RouteListener.cs @@ -219,5 +219,15 @@ namespace MontoyaTech.Rest.Net if (!Thread.Yield()) Thread.Sleep(1000); } + + /// + /// Generates a C# client from this Route Listener and returns the code. + /// + /// The name of the Client. Default is Client. + /// + public string GenerateCSharpClient(string name = "Client") + { + return ClientCodeGenerator.GenerateCSharpClient(this, name); + } } }