public Assembly Build(HttpRequestHandlerDefinition[] definitions) { var references = new AssemblyReferencesHelper() .AddReferenceForTypes(typeof(object), typeof(Controller), typeof(RequestHandlerControllerBuilder)) .AddReferenceForTypes(definitions.SelectMany(x => new[] { x.Definition.RequestType, x.Definition.ResponseType }).ToArray()) .GetReferences(); var compilation = CSharpCompilation.Create(_assemblyName) .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) .AddReferences(references); var csharpControllers = new List <string>(); var operationResults = definitions.Select(temp => CreateCSharp(GetClassName(temp.Definition.RequestType), temp)).ToArray(); var files = new Dictionary <string, string>(); files.Add("ProxyController", $@"namespace Proxy {{ public class ProxyController : {GetCorrectFormat(typeof(Controller))} {{ private readonly {GetCorrectFormat(typeof(IWebRequestProcessor))} _requestProcessor; public ProxyController({GetCorrectFormat(typeof(IWebRequestProcessor))} requestProcessor) {{ _requestProcessor = requestProcessor; }} {CodeStr.Foreach(operationResults.SelectMany(x => x.Operation.Split(new[] { Environment.NewLine }, StringSplitOptions.None)), operation => $@" { operation } ")} }} }}"); foreach (var operationResult in operationResults) { files.Add(operationResult.OperationName, operationResult.RequestClass); } foreach (var temp in files) { compilation = compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(temp.Value)); } var assemblyStream = new MemoryStream(); var result = compilation.Emit(assemblyStream); if (!result.Success) { var errormsg = new StringBuilder(); foreach (var diagnostic in result.Diagnostics) { errormsg.AppendLine(diagnostic.ToString()); } throw new Exception(string.Join(Environment.NewLine, csharpControllers), new Exception(errormsg.ToString())); } assemblyStream.Seek(0, SeekOrigin.Begin); return(AssemblyLoadContext.Default.LoadFromStream(assemblyStream)); }
public OperationResult CreateCSharp(string operationName, HttpRequestHandlerDefinition builderDefinition, HashSet <string> uniqueClassNames) { var requestBodyProperties = builderDefinition.Parameters.Where(x => x.BindingType == BindingType.FromBody || x.BindingType == BindingType.FromForm).ToArray(); var requestClass = builderDefinition.Definition.RequestType.Name; var original = requestClass; var tryCount = 1; while (uniqueClassNames.Contains(requestClass)) { requestClass = $"{original}_{++tryCount}"; } var methodArgs = string.Join(", ", builderDefinition.Parameters.GroupBy(x => x.PropertyName).Select(x => new { Name = x.Key, Type = x.First().BindingType == BindingType.FromBody || x.First().BindingType == BindingType.FromForm ? requestClass : GetCorrectFormat(x.First().PropertyInfo.PropertyType), Binder = x.First().BindingType }).Select(x => $"[Microsoft.AspNetCore.Mvc.{x.Binder}Attribute] {x.Type} {x.Name}")); var isAsync = builderDefinition.Definition.ResponseType.IsConstructedGenericType && builderDefinition.Definition.ResponseType.GetGenericTypeDefinition() == typeof(Task <>); var responseType = isAsync ? builderDefinition.Definition.ResponseType.GetGenericArguments()[0] : builderDefinition.Definition.ResponseType; var requestVariable = "request_" + Guid.NewGuid().ToString().Replace("-", ""); var operationResult = new OperationResult(); operationResult.OperationName = operationName; operationResult.RequestClass = $@"public class {requestClass} {{{CodeStr.Foreach(requestBodyProperties, source => $@" public {GetCorrectFormat(source.PropertyInfo.PropertyType)} {source.PropertyInfo.Name} {{ get; set; }}")} }}"; operationResult.Operation = $@"{GetAttributes(builderDefinition.Definition)}[Microsoft.AspNetCore.Mvc.Http{builderDefinition.HttpMethod}Attribute(""{builderDefinition.Route}""), {GetCorrectFormat(typeof(ProducesAttribute))}(typeof({GetCorrectFormat(responseType)}))] public {(isAsync ? "async " : string.Empty)}{GetCorrectFormat(isAsync ? typeof(Task<IActionResult>) : typeof(IActionResult))} {operationName}({methodArgs}) {{ var {requestVariable} = new {GetCorrectFormat(builderDefinition.Definition.RequestType)} {{{CodeStr.Foreach(builderDefinition.Parameters, assignment => $@" {assignment.PropertyInfo.Name} = {assignment.PropertyName}{(assignment.BindingType == BindingType.FromBody || assignment.BindingType == BindingType.FromForm ? $".{assignment.PropertyInfo.Name}" : "")},").Trim(',')} }}; var response = {(isAsync ? "await " : string.Empty)}_requestProcessor.Process{(isAsync ? "Async" : string.Empty)}<{GetCorrectFormat(builderDefinition.Definition.RequestType)},{GetCorrectFormat(responseType)}>({requestVariable}, this); return response; }}"; return(operationResult); }