diff --git a/Rest.Net.Example/Program.cs b/Rest.Net.Example/Program.cs
index 0b327b5..181aca9 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 = RestClientGenerator.GenerateCSharpClient(listener.Routes);
+ string code = listener.GenerateCSharpClient();
Console.WriteLine(code);
diff --git a/Rest.Net/CodeWriter.cs b/Rest.Net/CodeWriter.cs
index b28521a..35d580f 100644
--- a/Rest.Net/CodeWriter.cs
+++ b/Rest.Net/CodeWriter.cs
@@ -10,7 +10,7 @@ namespace MontoyaTech.Rest.Net
///
/// The outline of a writer that helps with generating code.
///
- internal class CodeWriter
+ public class CodeWriter
{
///
/// The internal string builder.
diff --git a/Rest.Net/Rest.Net.csproj b/Rest.Net/Rest.Net.csproj
index 9c2df86..c559a22 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.2.2
+ 1.2.3
Logo_Symbol_Black_Outline.png
diff --git a/Rest.Net/RestCSharpClientGenerator.cs b/Rest.Net/RestCSharpClientGenerator.cs
new file mode 100644
index 0000000..9fdc610
--- /dev/null
+++ b/Rest.Net/RestCSharpClientGenerator.cs
@@ -0,0 +1,397 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace MontoyaTech.Rest.Net
+{
+ ///
+ /// The outline of a Rest Client Generator that can generate a C# Client.
+ ///
+ public class RestCSharpClientGenerator : RestClientGenerator
+ {
+ ///
+ /// Generates a CSharp Client from a given set of routes and returns it.
+ ///
+ ///
+ ///
+ public override string Generate(List routes)
+ {
+ //Remove any hidden routes from code generation.
+ for (int i = 0; i < routes.Count; i++)
+ {
+ var methodInfo = routes[i].GetTarget().GetMethodInfo();
+
+ var routeHidden = methodInfo.GetCustomAttribute();
+
+ if (routeHidden != null)
+ {
+ routes.RemoveAt(i);
+ i--;
+ }
+ }
+
+ var includedTypes = this.FindRoutesDependencies(routes);
+
+ var routeGroups = this.FindRouteGroups(routes);
+
+ var writer = new CodeWriter();
+
+ writer.WriteLine("using System;");
+ writer.WriteLine("using System.Net.Http;");
+ writer.WriteLine("using Newtonsoft.Json;");
+
+ writer.WriteBreak().WriteLine($"public class {this.ClientName}").WriteLine("{").Indent();
+
+ writer.WriteBreak().WriteLine("public string BaseUrl;");
+
+ writer.WriteBreak().WriteLine("public HttpClient HttpClient;");
+
+ //Create fields foreach route group so they can be accessed.
+ foreach (var group in routeGroups)
+ writer.WriteBreak().WriteLine($"public {group.Key}Api {group.Key};");
+
+ //Create the client constructor
+ writer.WriteBreak().WriteLine("public Client(string baseUrl)").WriteLine("{").Indent();
+
+ //Init the base url
+ writer.WriteLine("this.BaseUrl = baseUrl;");
+
+ //Init all the route group fields
+ foreach (var group in routeGroups)
+ writer.WriteLine($"this.{group.Key} = new {group.Key}Api(this);");
+
+ //Init the http client
+ writer.WriteLine("this.HttpClient = new HttpClient();");
+ writer.WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Accept"", ""*/*"");");
+ writer.WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Connection"", ""keep-alive"");");
+ writer.WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Accept-Encoding"", ""identity"");");
+
+ writer.Outdent().WriteLine("}");
+
+ this.GenerateCSharpRouteGroups(routeGroups, writer);
+
+ this.GenerateCSharpIncludedTypes(includedTypes, writer);
+
+ writer.Outdent().WriteLine("}");
+
+ return writer.ToString();
+ }
+
+ ///
+ /// Generates C# for a set of included types.
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpIncludedTypes(List types, CodeWriter writer)
+ {
+ foreach (var type in types)
+ this.GenerateCSharpIncludedType(type, writer);
+ }
+
+ ///
+ /// Generates C# for a given included type.
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpIncludedType(Type type, CodeWriter writer)
+ {
+ writer.WriteBreak();
+
+ writer.WriteLine($"public class {type.Name}").WriteLine("{").Indent();
+
+ var fields = type.GetFields();
+
+ if (fields != null)
+ foreach (var field in fields)
+ if (field.IsPublic)
+ this.GenerateCSharpIncludedField(field, writer);
+
+ var properties = type.GetProperties();
+
+ if (properties != null)
+ foreach (var property in properties)
+ if (property.GetSetMethod() != null && property.GetGetMethod() != null)
+ this.GenerateCSharpIncludedProperty(property, writer);
+
+ writer.Outdent().WriteLine("}");
+ }
+
+ ///
+ /// Generates C# for a field inside an included type.
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpIncludedField(FieldInfo field, CodeWriter writer)
+ {
+ writer.WriteBreak();
+
+ writer.WriteLine($"public {this.GetTypeFullyResolvedName(field.FieldType)} {field.Name};");
+ }
+
+ ///
+ /// Generates C# for a property inside an included type.
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpIncludedProperty(PropertyInfo property, CodeWriter writer)
+ {
+ writer.WriteBreak();
+
+ writer.WriteLine($"public {this.GetTypeFullyResolvedName(property.PropertyType)} {property.Name} {{ get; set; }}");
+ }
+
+ ///
+ /// Generates C# for a set of route groups.
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpRouteGroups(Dictionary> groups, CodeWriter writer)
+ {
+ foreach (var group in groups)
+ this.GenerateCSharpRouteGroup(group.Key, group.Value, writer);
+ }
+
+ ///
+ /// Generates C# for a given route group.
+ ///
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpRouteGroup(string name, List routes, CodeWriter writer)
+ {
+ writer.WriteBreak();
+
+ writer.WriteLine($"public class {name}Api").WriteLine("{").Indent();
+
+ writer.WriteBreak();
+
+ writer.WriteLine("public Client Client;");
+
+ writer.WriteBreak();
+
+ writer.WriteLine($"public {name}Api(Client client)").WriteLine("{").Indent();
+
+ writer.WriteLine("this.Client = client;");
+
+ writer.Outdent().WriteLine("}");
+
+ foreach (var route in routes)
+ this.GenerateCSharpRouteFunction(route, writer);
+
+ writer.Outdent().WriteLine("}");
+ }
+
+ ///
+ /// Generates a C# function for a given route.
+ ///
+ ///
+ ///
+ ///
+ protected virtual void GenerateCSharpRouteFunction(Route route, CodeWriter writer)
+ {
+ writer.WriteBreak();
+
+ var methodInfo = route.GetTarget().GetMethodInfo();
+
+ var routeName = methodInfo.GetCustomAttribute();
+
+ var routeRequest = methodInfo.GetCustomAttribute();
+
+ var routeResponse = methodInfo.GetCustomAttribute();
+
+ //Generate the route function header
+ writer.Write($"public {(routeResponse == null ? "void" : this.GetTypeFullyResolvedName(routeResponse.ResponseType))} {(routeName == null ? methodInfo.Name : routeName.Name)}(");
+
+ //Generate the functions parameters
+ var parameters = methodInfo.GetParameters();
+
+ if (parameters != null)
+ {
+ for (int i = 1; i < parameters.Length; i++)
+ {
+ writer.WriteSeparator();
+ writer.Write(this.GetTypeFullyResolvedName(parameters[i].ParameterType)).Write(" ").Write(parameters[i].Name);
+ }
+ }
+
+ if (routeRequest != null)
+ {
+ writer.WriteSeparator();
+ writer.Write(this.GetTypeFullyResolvedName(routeRequest.RequestType)).Write(" request");
+ }
+
+ writer.WriteLine(")").WriteLine("{").Indent();
+
+ //Generate the message code
+ writer.WriteBreak().Write($"var message = new HttpRequestMessage(");
+
+ switch (route.Method.ToLower())
+ {
+ case "post":
+ writer.Write("HttpMethod.Post");
+ break;
+ case "get":
+ writer.Write("HttpMethod.Get");
+ break;
+ case "delete":
+ writer.Write("HttpMethod.Delete");
+ break;
+ case "put":
+ writer.Write("HttpMethod.Put");
+ break;
+ case "options":
+ writer.Write("HttpMethod.Options");
+ break;
+ case "patch":
+ writer.Write("HttpMethod.Patch");
+ break;
+ case "head":
+ writer.Write("HttpMethod.Head");
+ break;
+ case "trace":
+ writer.Write("HttpMethod.Trace");
+ break;
+ default:
+ throw new NotSupportedException("Unsupport route method:" + route.Method);
+ }
+
+ writer.WriteSeparator().Write('$').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))
+ {
+ 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)
+ {
+ if (routeRequest.Json)
+ writer.WriteBreak().WriteLine("message.Content = new StringContent(JsonConvert.SerializeObject(request));");
+ else
+ writer.WriteBreak().WriteLine("message.Content = new StringContent(request.ToString());");
+ }
+
+ //Generate the response code
+ writer.WriteBreak().WriteLine("var response = this.Client.HttpClient.Send(message);");
+
+ //Handle the response
+ if (routeResponse != null)
+ {
+ writer.WriteBreak().WriteLine("if (response.StatusCode == System.Net.HttpStatusCode.OK)").Indent();
+
+ if (routeResponse.Json)
+ {
+ writer.WriteLine($"return JsonConvert.DeserializeObject<{this.GetTypeFullyResolvedName(routeResponse.ResponseType)}>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ }
+ else
+ {
+ switch (Type.GetTypeCode(routeResponse.ResponseType))
+ {
+ case TypeCode.Boolean:
+ writer.WriteLine("return bool.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Byte:
+ writer.WriteLine("return byte.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Char:
+ writer.WriteLine("return response.Content.ReadAsStringAsync().GetAwaiter().GetResult()[0];");
+ break;
+
+ case TypeCode.DateTime:
+ writer.WriteLine("return DateTime.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Decimal:
+ writer.WriteLine("return decimal.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Double:
+ writer.WriteLine("return double.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Int16:
+ writer.WriteLine("return short.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Int32:
+ writer.WriteLine("return int.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Int64:
+ writer.WriteLine("return long.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.SByte:
+ writer.WriteLine("return sbyte.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Single:
+ writer.WriteLine("return float.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.String:
+ writer.WriteLine("return response.Content.ReadAsStringAsync().GetAwaiter().GetResult();");
+ break;
+
+ case TypeCode.UInt16:
+ writer.WriteLine("return ushort.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.UInt32:
+ writer.WriteLine("return uint.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.UInt64:
+ writer.WriteLine("return ulong.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
+ break;
+
+ case TypeCode.Object:
+ throw new NotSupportedException("ResponseType isn't JSON but is an object.");
+ }
+ }
+
+ 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();
+ }
+
+ //Close off the route function.
+ writer.Outdent().WriteLine("}");
+ }
+ }
+}
diff --git a/Rest.Net/RestClientGenerator.cs b/Rest.Net/RestClientGenerator.cs
index d05ddbf..67ee307 100644
--- a/Rest.Net/RestClientGenerator.cs
+++ b/Rest.Net/RestClientGenerator.cs
@@ -17,12 +17,17 @@ namespace MontoyaTech.Rest.Net
///
public class RestClientGenerator
{
+ ///
+ /// The name of the client to generate.
+ ///
+ public string ClientName = "Client";
+
///
/// Returns whether or not a given type belongs to DotNet.
///
///
///
- private static bool IsTypeDotNet(Type type)
+ protected virtual bool IsTypeDotNet(Type type)
{
if (type.Assembly.GetName().Name == "System.Private.CoreLib")
return true;
@@ -35,11 +40,11 @@ namespace MontoyaTech.Rest.Net
///
///
///
- private static List FindTypeDependencies(Type type)
+ protected virtual List FindTypeDependencies(Type type)
{
var dependencies = new HashSet();
- if (IsTypeDotNet(type))
+ if (this.IsTypeDotNet(type))
return dependencies.ToList();
dependencies.Add(type);
@@ -50,7 +55,7 @@ namespace MontoyaTech.Rest.Net
{
foreach (var argument in arguments)
{
- var types = FindTypeDependencies(argument);
+ var types = this.FindTypeDependencies(argument);
for (int i = 0; i < types.Count; i++)
if (!dependencies.Contains(types[i]))
@@ -66,7 +71,7 @@ namespace MontoyaTech.Rest.Net
{
if (field.IsPublic)
{
- var types = FindTypeDependencies(field.FieldType);
+ var types = this.FindTypeDependencies(field.FieldType);
for (int i = 0; i < types.Count; i++)
if (!dependencies.Contains(types[i]))
@@ -83,7 +88,7 @@ namespace MontoyaTech.Rest.Net
{
if (property.GetSetMethod() != null && property.GetGetMethod() != null)
{
- var types = FindTypeDependencies(property.PropertyType);
+ var types = this.FindTypeDependencies(property.PropertyType);
for (int i = 0; i < types.Count; i++)
if (!dependencies.Contains(types[i]))
@@ -100,7 +105,7 @@ namespace MontoyaTech.Rest.Net
///
///
///
- private static List FindRouteDependencies(Route route)
+ protected virtual List FindRouteDependencies(Route route)
{
var dependencies = new HashSet();
@@ -114,7 +119,7 @@ namespace MontoyaTech.Rest.Net
{
for (int i = 1; i < parameters.Length; i++)
{
- var types = FindTypeDependencies(parameters[i].ParameterType);
+ var types = this.FindTypeDependencies(parameters[i].ParameterType);
foreach (var type in types)
if (!dependencies.Contains(type))
@@ -126,7 +131,7 @@ namespace MontoyaTech.Rest.Net
if (routeRequest != null)
{
- var types = FindTypeDependencies(routeRequest.RequestType);
+ var types = this.FindTypeDependencies(routeRequest.RequestType);
foreach (var type in types)
if (!dependencies.Contains(type))
@@ -137,7 +142,7 @@ namespace MontoyaTech.Rest.Net
if (routeResponse != null)
{
- var types = FindTypeDependencies(routeResponse.ResponseType);
+ var types = this.FindTypeDependencies(routeResponse.ResponseType);
foreach (var type in types)
if (!dependencies.Contains(type))
@@ -153,13 +158,13 @@ namespace MontoyaTech.Rest.Net
///
///
///
- private static List FindRoutesDependencies(List routes)
+ protected virtual List FindRoutesDependencies(List routes)
{
var dependencies = new HashSet();
foreach (var route in routes)
{
- var types = FindRouteDependencies(route);
+ var types = this.FindRouteDependencies(route);
if (types != null)
for (int i = 0; i < types.Count; i++)
@@ -175,9 +180,9 @@ namespace MontoyaTech.Rest.Net
///
///
///
- private static string GetTypeFullyResolvedName(Type type)
+ protected virtual string GetTypeFullyResolvedName(Type type)
{
- if (IsTypeDotNet(type))
+ if (this.IsTypeDotNet(type))
{
var typeCode = Type.GetTypeCode(type);
@@ -236,7 +241,7 @@ namespace MontoyaTech.Rest.Net
if (i > 0)
builder.Append(", ");
- builder.Append(GetTypeFullyResolvedName(genericArguments[i]));
+ builder.Append(this.GetTypeFullyResolvedName(genericArguments[i]));
}
builder.Append(">");
@@ -267,7 +272,7 @@ namespace MontoyaTech.Rest.Net
if (i > 0)
builder.Append(", ");
- builder.Append(GetTypeFullyResolvedName(genericArguments[i]));
+ builder.Append(this.GetTypeFullyResolvedName(genericArguments[i]));
}
builder.Append(">");
@@ -282,7 +287,7 @@ namespace MontoyaTech.Rest.Net
///
///
///
- private static Dictionary> FindRouteGroups(List routes)
+ protected virtual Dictionary> FindRouteGroups(List routes)
{
var groups = new Dictionary>();
@@ -309,405 +314,20 @@ namespace MontoyaTech.Rest.Net
}
///
- /// Generates a CSharpClient from a RouteListener.
+ /// Generates a Rest Client from a RouteListener and returns the code.
///
- ///
- /// 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")
+ public string Generate(RouteListener listener)
{
- //Remove any hidden routes from code generation.
- for (int i = 0; i < routes.Count; i++)
- {
- var methodInfo = routes[i].GetTarget().GetMethodInfo();
-
- var routeHidden = methodInfo.GetCustomAttribute();
-
- if (routeHidden != null)
- {
- routes.RemoveAt(i);
- i--;
- }
- }
-
- var includedTypes = FindRoutesDependencies(routes);
-
- var routeGroups = FindRouteGroups(routes);
-
- var writer = new CodeWriter();
-
- writer.WriteLine("using System;");
- writer.WriteLine("using System.Net.Http;");
- writer.WriteLine("using Newtonsoft.Json;");
-
- writer.WriteBreak().WriteLine($"public class {name}").WriteLine("{").Indent();
-
- writer.WriteBreak().WriteLine("public string BaseUrl;");
-
- writer.WriteBreak().WriteLine("public HttpClient HttpClient;");
-
- //Create fields foreach route group so they can be accessed.
- foreach (var group in routeGroups)
- writer.WriteBreak().WriteLine($"public {group.Key}Api {group.Key};");
-
- //Create the client constructor
- writer.WriteBreak().WriteLine("public Client(string baseUrl)").WriteLine("{").Indent();
-
- //Init the base url
- writer.WriteLine("this.BaseUrl = baseUrl;");
-
- //Init all the route group fields
- foreach (var group in routeGroups)
- writer.WriteLine($"this.{group.Key} = new {group.Key}Api(this);");
-
- //Init the http client
- writer.WriteLine("this.HttpClient = new HttpClient();");
- writer.WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Accept"", ""*/*"");");
- writer.WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Connection"", ""keep-alive"");");
- writer.WriteLine(@"this.HttpClient.DefaultRequestHeaders.Add(""Accept-Encoding"", ""identity"");");
-
- writer.Outdent().WriteLine("}");
-
- GenerateCSharpRouteGroups(routeGroups, writer);
-
- GenerateCSharpIncludedTypes(includedTypes, writer);
-
- writer.Outdent().WriteLine("}");
-
- return writer.ToString();
+ return this.Generate(listener.Routes);
}
///
- /// 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();
-
- writer.WriteLine($"public class {type.Name}").WriteLine("{").Indent();
-
- var fields = type.GetFields();
-
- if (fields != null)
- foreach (var field in fields)
- if (field.IsPublic)
- GenerateCSharpIncludedField(field, writer);
-
- var properties = type.GetProperties();
-
- if (properties != null)
- foreach (var property in properties)
- if (property.GetSetMethod() != null && property.GetGetMethod() != null)
- GenerateCSharpIncludedProperty(property, writer);
-
- writer.Outdent().WriteLine("}");
- }
-
- ///
- /// Generates C# for a field inside an included type.
- ///
- ///
- ///
- private static void GenerateCSharpIncludedField(FieldInfo field, CodeWriter writer)
- {
- writer.WriteBreak();
-
- 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();
-
- 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();
-
- writer.WriteLine($"public class {name}Api").WriteLine("{").Indent();
-
- writer.WriteBreak();
-
- writer.WriteLine("public Client Client;");
-
- writer.WriteBreak();
-
- writer.WriteLine($"public {name}Api(Client client)").WriteLine("{").Indent();
-
- writer.WriteLine("this.Client = client;");
-
- writer.Outdent().WriteLine("}");
-
- foreach (var route in routes)
- GenerateCSharpRouteFunction(route, writer);
-
- writer.Outdent().WriteLine("}");
- }
-
- ///
- /// Generates a C# function for a given route.
- ///
- ///
- ///
- ///
- private static void GenerateCSharpRouteFunction(Route route, CodeWriter writer)
- {
- writer.WriteBreak();
-
- var methodInfo = route.GetTarget().GetMethodInfo();
-
- var routeName = methodInfo.GetCustomAttribute();
-
- var routeRequest = methodInfo.GetCustomAttribute();
-
- var routeResponse = methodInfo.GetCustomAttribute();
-
- //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)
- {
- for (int i = 1; i < parameters.Length; i++)
- {
- writer.WriteSeparator();
- writer.Write(GetTypeFullyResolvedName(parameters[i].ParameterType)).Write(" ").Write(parameters[i].Name);
- }
- }
-
- if (routeRequest != null)
- {
- writer.WriteSeparator();
- writer.Write(GetTypeFullyResolvedName(routeRequest.RequestType)).Write(" request");
- }
-
- writer.WriteLine(")").WriteLine("{").Indent();
-
- //Generate the message code
- writer.WriteBreak().Write($"var message = new HttpRequestMessage(");
-
- switch (route.Method.ToLower())
- {
- case "post":
- writer.Write("HttpMethod.Post");
- break;
- case "get":
- writer.Write("HttpMethod.Get");
- break;
- case "delete":
- writer.Write("HttpMethod.Delete");
- break;
- case "put":
- writer.Write("HttpMethod.Put");
- break;
- case "options":
- writer.Write("HttpMethod.Options");
- break;
- case "patch":
- writer.Write("HttpMethod.Patch");
- break;
- case "head":
- writer.Write("HttpMethod.Head");
- break;
- case "trace":
- writer.Write("HttpMethod.Trace");
- break;
- default:
- throw new NotSupportedException("Unsupport route method:" + route.Method);
- }
-
- writer.WriteSeparator().Write('$').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))
- {
- 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)
- {
- if (routeRequest.Json)
- writer.WriteBreak().WriteLine("message.Content = new StringContent(JsonConvert.SerializeObject(request));");
- else
- writer.WriteBreak().WriteLine("message.Content = new StringContent(request.ToString());");
- }
-
- //Generate the response code
- writer.WriteBreak().WriteLine("var response = this.Client.HttpClient.Send(message);");
-
- //Handle the response
- if (routeResponse != null)
- {
- writer.WriteBreak().WriteLine("if (response.StatusCode == System.Net.HttpStatusCode.OK)").Indent();
-
- if (routeResponse.Json)
- {
- writer.WriteLine($"return JsonConvert.DeserializeObject<{GetTypeFullyResolvedName(routeResponse.ResponseType)}>(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- }
- else
- {
- switch (Type.GetTypeCode(routeResponse.ResponseType))
- {
- case TypeCode.Boolean:
- writer.WriteLine("return bool.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Byte:
- writer.WriteLine("return byte.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Char:
- writer.WriteLine("return response.Content.ReadAsStringAsync().GetAwaiter().GetResult()[0];");
- break;
-
- case TypeCode.DateTime:
- writer.WriteLine("return DateTime.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Decimal:
- writer.WriteLine("return decimal.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Double:
- writer.WriteLine("return double.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Int16:
- writer.WriteLine("return short.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Int32:
- writer.WriteLine("return int.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Int64:
- writer.WriteLine("return long.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.SByte:
- writer.WriteLine("return sbyte.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Single:
- writer.WriteLine("return float.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.String:
- writer.WriteLine("return response.Content.ReadAsStringAsync().GetAwaiter().GetResult();");
- break;
-
- case TypeCode.UInt16:
- writer.WriteLine("return ushort.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.UInt32:
- writer.WriteLine("return uint.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.UInt64:
- writer.WriteLine("return ulong.Parse(response.Content.ReadAsStringAsync().GetAwaiter().GetResult());");
- break;
-
- case TypeCode.Object:
- throw new NotSupportedException("ResponseType isn't JSON but is an object.");
- }
- }
-
- 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();
- }
-
- //Close off the route function.
- writer.Outdent().WriteLine("}");
- }
-
- ///
- /// Generates a Javascript client from a given set of routes.
+ /// Generates a Rest Client from a set of routes and returns the code.
///
///
///
- ///
- public static string GenerateJavascriptClient(List routes)
+ public virtual string Generate(List routes)
{
throw new NotImplementedException();
}
diff --git a/Rest.Net/RouteListener.cs b/Rest.Net/RouteListener.cs
index 8e47df0..2365b84 100644
--- a/Rest.Net/RouteListener.cs
+++ b/Rest.Net/RouteListener.cs
@@ -223,11 +223,15 @@ namespace MontoyaTech.Rest.Net
///
/// Generates a C# client from this Route Listener and returns the code.
///
- /// The name of the Client. Default is Client.
+ /// The name of the Client. Default is Client.
///
- public string GenerateCSharpClient(string name = "Client")
+ public string GenerateCSharpClient(string clientName = "Client")
{
- return RestClientGenerator.GenerateCSharpClient(this, name);
+ var generator = new RestCSharpClientGenerator();
+
+ generator.ClientName = clientName;
+
+ return generator.Generate(this);
}
}
}