Bumped package version to 1.1.9. Added documentation and cleaned up code. Going to merge into Master.

This commit is contained in:
MattMo 2023-02-05 12:28:37 -08:00
parent 1475159f1c
commit 42c4682c89
5 changed files with 119 additions and 17 deletions

View File

@ -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<string>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
return JsonConvert.DeserializeObject<string>(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<string>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
return JsonConvert.DeserializeObject<string>(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<bool>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
return JsonConvert.DeserializeObject<bool>(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<User>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
return JsonConvert.DeserializeObject<User>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());
else
throw new Exception("Unexpected Http Response StatusCode:" + response.StatusCode);
}

View File

@ -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);

View File

@ -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.
/// </summary>
public class CodeGenerator
public class ClientCodeGenerator
{
/// <summary>
/// Returns whether or not a given type belongs to DotNet.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static bool IsTypeDotNet(Type type)
{
if (type.Assembly.GetName().Name == "System.Private.CoreLib")
@ -25,6 +30,11 @@ namespace MontoyaTech.Rest.Net
return false;
}
/// <summary>
/// Finds all the dependencies for a given type and returns them.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static List<Type> FindTypeDependencies(Type type)
{
var dependencies = new HashSet<Type>();
@ -85,6 +95,11 @@ namespace MontoyaTech.Rest.Net
return dependencies.ToList();
}
/// <summary>
/// Finds all the types that a given route depends on to function.
/// </summary>
/// <param name="route"></param>
/// <returns></returns>
private static List<Type> FindRouteDependencies(Route route)
{
var dependencies = new HashSet<Type>();
@ -133,6 +148,11 @@ namespace MontoyaTech.Rest.Net
return dependencies.ToList();
}
/// <summary>
/// Finds all the types that a given set of routes depend on to function.
/// </summary>
/// <param name="routes"></param>
/// <returns></returns>
private static List<Type> FindRoutesDependencies(List<Route> routes)
{
var dependencies = new HashSet<Type>();
@ -150,6 +170,11 @@ namespace MontoyaTech.Rest.Net
return dependencies.ToList();
}
/// <summary>
/// Returns the fully resolve name for a given type.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private static string GetTypeFullyResolvedName(Type type)
{
if (IsTypeDotNet(type))
@ -252,6 +277,11 @@ namespace MontoyaTech.Rest.Net
}
}
/// <summary>
/// Finds all the route groupings from a set of routes and returns those groups.
/// </summary>
/// <param name="routes"></param>
/// <returns></returns>
private static Dictionary<string, List<Route>> FindRouteGroups(List<Route> routes)
{
var groups = new Dictionary<string, List<Route>>();
@ -278,7 +308,24 @@ namespace MontoyaTech.Rest.Net
return groups;
}
public static string GenerateCSharpClient(List<Route> routes)
/// <summary>
/// Generates a CSharpClient from a RouteListener.
/// </summary>
/// <param name="listener"></param>
/// <param name="name">The name of the Client class, default is Client.</param>
/// <returns>The generated C# code.</returns>
public static string GenerateCSharpClient(RouteListener listener, string name = "Client")
{
return GenerateCSharpClient(listener.Routes, name);
}
/// <summary>
/// Generates a CSharpClient from a given set of Routes.
/// </summary>
/// <param name="routes"></param>
/// <param name="name">The name of the Client class, default is Client.</param>
/// <returns></returns>
public static string GenerateCSharpClient(List<Route> 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();
}
/// <summary>
/// Generates C# for a set of included types.
/// </summary>
/// <param name="types"></param>
/// <param name="writer"></param>
private static void GenerateCSharpIncludedTypes(List<Type> types, CodeWriter writer)
{
foreach (var type in types)
GenerateCSharpIncludedType(type, writer);
}
/// <summary>
/// Generates C# for a given included type.
/// </summary>
/// <param name="type"></param>
/// <param name="writer"></param>
private static void GenerateCSharpIncludedType(Type type, CodeWriter writer)
{
writer.WriteBreak();
@ -355,6 +413,11 @@ namespace MontoyaTech.Rest.Net
writer.Outdent().WriteLine("}");
}
/// <summary>
/// Generates C# for a field inside an included type.
/// </summary>
/// <param name="field"></param>
/// <param name="writer"></param>
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};");
}
/// <summary>
/// Generates C# for a property inside an included type.
/// </summary>
/// <param name="property"></param>
/// <param name="writer"></param>
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; }}");
}
/// <summary>
/// Generates C# for a set of route groups.
/// </summary>
/// <param name="groups"></param>
/// <param name="writer"></param>
private static void GenerateCSharpRouteGroups(Dictionary<string, List<Route>> groups, CodeWriter writer)
{
foreach (var group in groups)
GenerateCSharpRouteGroup(group.Key, group.Value, writer);
}
/// <summary>
/// Generates C# for a given route group.
/// </summary>
/// <param name="name"></param>
/// <param name="routes"></param>
/// <param name="writer"></param>
private static void GenerateCSharpRouteGroup(string name, List<Route> routes, CodeWriter writer)
{
writer.WriteBreak();
@ -399,6 +478,12 @@ namespace MontoyaTech.Rest.Net
writer.Outdent().WriteLine("}");
}
/// <summary>
/// Generates a C# function for a given route.
/// </summary>
/// <param name="route"></param>
/// <param name="writer"></param>
/// <exception cref="NotSupportedException"></exception>
private static void GenerateCSharpRouteFunction(Route route, CodeWriter writer)
{
writer.WriteBreak();
@ -411,9 +496,10 @@ namespace MontoyaTech.Rest.Net
var routeResponse = methodInfo.GetCustomAttribute<RouteResponse>();
//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<Route> routes)
/// <summary>
/// Generates a Javascript client from a given set of routes.
/// </summary>
/// <param name="routes"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public static string GenerateJavascriptClient(List<Route> routes)
{
return null;
throw new NotImplementedException();
}
}
}

View File

@ -17,7 +17,7 @@
<AssemblyName>MontoyaTech.Rest.Net</AssemblyName>
<RootNamespace>MontoyaTech.Rest.Net</RootNamespace>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<Version>1.1.8</Version>
<Version>1.1.9</Version>
<PackageReleaseNotes></PackageReleaseNotes>
<PackageIcon>Logo_Symbol_Black_Outline.png</PackageIcon>
</PropertyGroup>

View File

@ -219,5 +219,15 @@ namespace MontoyaTech.Rest.Net
if (!Thread.Yield())
Thread.Sleep(1000);
}
/// <summary>
/// Generates a C# client from this Route Listener and returns the code.
/// </summary>
/// <param name="name">The name of the Client. Default is Client.</param>
/// <returns></returns>
public string GenerateCSharpClient(string name = "Client")
{
return ClientCodeGenerator.GenerateCSharpClient(this, name);
}
}
}