From e95a6e7122643ff89cbeb28a93d51d6301284fa8 Mon Sep 17 00:00:00 2001 From: Mauro Servienti Date: Sun, 20 Dec 2020 19:02:40 +0100 Subject: [PATCH 1/5] Add MyGet --- src/nuget.config | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/nuget.config diff --git a/src/nuget.config b/src/nuget.config new file mode 100644 index 0000000..fe14dfe --- /dev/null +++ b/src/nuget.config @@ -0,0 +1,10 @@ + + + + + + + + + + From 48584db84fe9700559a0d501445a36046bca0776 Mon Sep 17 00:00:00 2001 From: Mauro Servienti Date: Sun, 20 Dec 2020 19:03:17 +0100 Subject: [PATCH 2/5] Update to experimental TypedViewModel support --- .../Swagger for ServiceComposer.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj b/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj index c5689ca..f9b4b97 100644 --- a/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj +++ b/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj @@ -6,7 +6,8 @@ - + + From b6d0a175ab28946093abe0930aca8ddfede49619 Mon Sep 17 00:00:00 2001 From: Mauro Servienti Date: Sun, 20 Dec 2020 19:20:36 +0100 Subject: [PATCH 3/5] failed attempt to provide a typed response --- .../ServiceComposerApiDescriptionProvider.cs | 13 +++++++++++ .../Documentation/DocumentationHandler.cs | 22 ------------------- .../Handlers/ServiceA/SampleHandler.cs | 5 ++++- .../Handlers/ServiceB/SampleHandler.cs | 5 ++++- .../Models/Response/IAValue.cs | 7 ++++++ .../Models/Response/IAnotherValue.cs | 7 ++++++ .../Models/Response/Sample.cs | 8 ------- .../Properties/launchSettings.json | 2 +- 8 files changed, 36 insertions(+), 33 deletions(-) delete mode 100644 src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs create mode 100644 src/Swagger for ServiceComposer/Models/Response/IAValue.cs create mode 100644 src/Swagger for ServiceComposer/Models/Response/IAnotherValue.cs delete mode 100644 src/Swagger for ServiceComposer/Models/Response/Sample.cs diff --git a/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs b/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs index a309a81..4543d24 100644 --- a/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs +++ b/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Routing; +using ServiceComposer.AspNetCore.TypedViewModel; namespace Swagger_for_ServiceComposer.ApiDescription { @@ -95,6 +96,18 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiParameterDescriptionAttribute.Type) }); } + + foreach (var typedViewModelAttribute in routeEndpoint.Metadata.OfType()) + { + apiDescription.SupportedResponseTypes.Add(new ApiResponseType + { + Type = typedViewModelAttribute.Type, + ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, + StatusCode = 200, + IsDefaultResponse = false, + ModelMetadata = _modelMetadataProvider.GetMetadataForType(typedViewModelAttribute.Type) + }); + } return apiDescription; } diff --git a/src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs b/src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs deleted file mode 100644 index 15e5c44..0000000 --- a/src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using ServiceComposer.AspNetCore; -using Swagger_for_ServiceComposer.ApiDescription; -using Swagger_for_ServiceComposer.Models.Response; - -namespace Swagger_for_ServiceComposer.Handlers.Documentation -{ - public class DocumentationHandler : ICompositionRequestsHandler - { - [HttpGet("/sample/{id}")] - [ProducesDefaultResponseType(typeof(void))] - [ProducesResponseType(typeof(Sample), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] - [ApiParameterDescription(Name = "id", IsRequired = true, Type = typeof(int), Source = "Path")] - public Task Handle(HttpRequest request) - { - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs b/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs index 3fbe8e5..a7ead8b 100644 --- a/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs +++ b/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs @@ -4,18 +4,21 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using ServiceComposer.AspNetCore; +using ServiceComposer.AspNetCore.TypedViewModel; +using Swagger_for_ServiceComposer.Models.Response; namespace Swagger_for_ServiceComposer.Handlers.ServiceA { public class SampleHandler : ICompositionRequestsHandler { [HttpGet("/sample/{id}")] + [TypedViewModel(typeof(IAValue))] public Task Handle(HttpRequest request) { var routeData = request.HttpContext.GetRouteData(); var id = Convert.ToInt32(routeData.Values["id"]); - var vm = request.GetComposedResponseModel(); + var vm = request.GetComposedResponseModel(); vm.AValue = id; return Task.CompletedTask; diff --git a/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs b/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs index eb37942..4403d5a 100644 --- a/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs +++ b/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs @@ -2,15 +2,18 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using ServiceComposer.AspNetCore; +using ServiceComposer.AspNetCore.TypedViewModel; +using Swagger_for_ServiceComposer.Models.Response; namespace Swagger_for_ServiceComposer.Handlers.ServiceB { public class SampleHandler : ICompositionRequestsHandler { [HttpGet("/sample/{id}")] + [TypedViewModel(typeof(IAnotherValue))] public Task Handle(HttpRequest request) { - var vm = request.GetComposedResponseModel(); + var vm = request.GetComposedResponseModel(); vm.AnotherValue = "Hi, there."; return Task.CompletedTask; diff --git a/src/Swagger for ServiceComposer/Models/Response/IAValue.cs b/src/Swagger for ServiceComposer/Models/Response/IAValue.cs new file mode 100644 index 0000000..e4a8541 --- /dev/null +++ b/src/Swagger for ServiceComposer/Models/Response/IAValue.cs @@ -0,0 +1,7 @@ +namespace Swagger_for_ServiceComposer.Models.Response +{ + public interface IAValue + { + int AValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Models/Response/IAnotherValue.cs b/src/Swagger for ServiceComposer/Models/Response/IAnotherValue.cs new file mode 100644 index 0000000..40afef1 --- /dev/null +++ b/src/Swagger for ServiceComposer/Models/Response/IAnotherValue.cs @@ -0,0 +1,7 @@ +namespace Swagger_for_ServiceComposer.Models.Response +{ + public interface IAnotherValue + { + string AnotherValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Models/Response/Sample.cs b/src/Swagger for ServiceComposer/Models/Response/Sample.cs deleted file mode 100644 index c992881..0000000 --- a/src/Swagger for ServiceComposer/Models/Response/Sample.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Swagger_for_ServiceComposer.Models.Response -{ - public class Sample - { - public int AValue { get; set; } - public string AnotherValue { get; set; } - } -} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Properties/launchSettings.json b/src/Swagger for ServiceComposer/Properties/launchSettings.json index 4bd9e0f..a6454bf 100644 --- a/src/Swagger for ServiceComposer/Properties/launchSettings.json +++ b/src/Swagger for ServiceComposer/Properties/launchSettings.json @@ -3,7 +3,7 @@ "Swagger_for_ServiceComposer": { "commandName": "Project", "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "applicationUrl": "http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From 100fae550c7c2132a273d4d0962b39ef99c9796b Mon Sep 17 00:00:00 2001 From: Mauro Servienti Date: Mon, 21 Dec 2020 06:08:10 +0100 Subject: [PATCH 4/5] it works! --- .../ServiceComposerApiDescriptionProvider.cs | 62 ++++++++++++++----- .../Handlers/ServiceA/SampleHandler.cs | 2 + .../Handlers/ServiceB/SampleHandler.cs | 2 + 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs b/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs index 4543d24..7eb318d 100644 --- a/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs +++ b/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs @@ -1,6 +1,9 @@ using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Reflection; +using System.Reflection.Emit; +using Castle.DynamicProxy; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ApiExplorer; @@ -13,9 +16,10 @@ namespace Swagger_for_ServiceComposer.ApiDescription { internal class ServiceComposerApiDescriptionProvider : IApiDescriptionProvider { + private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(); private readonly EndpointDataSource _endpointDataSource; private readonly IModelMetadataProvider _modelMetadataProvider; - + public ServiceComposerApiDescriptionProvider(EndpointDataSource endpointDataSource, IModelMetadataProvider modelMetadataProvider) { _endpointDataSource = endpointDataSource; @@ -46,7 +50,7 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription var verb = httpMethodMetadata?.HttpMethods.FirstOrDefault(); var apiDescription = new Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription(); - // Default to a GET in case a Route map was registered inline - it's unlikely to be a composition handler in that case. + // Default to a GET in case a Route map was registered inline - it's unlikely to be a composition handler in that case. apiDescription.HttpMethod = verb ?? "GET"; apiDescription.ActionDescriptor = new ActionDescriptor { @@ -55,25 +59,28 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription // Swagger uses this to group endpoints together. // Group methods together using the service name. // NOTE: Need a metadata model in service composer to begin supplying more info other than just http verbs and route patterns. - ["controller"] = "ViewModelComposition"// routeEndpoint.RoutePattern.GetParameter("controller").Default.ToString() + ["controller"] = + "ViewModelComposition" // routeEndpoint.RoutePattern.GetParameter("controller").Default.ToString() } }; apiDescription.RelativePath = routeEndpoint.RoutePattern.RawText.TrimStart('/'); - apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat { MediaType = "application/json" }); + apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat {MediaType = "application/json"}); - foreach (var producesDefaultResponseTypeAttribute in routeEndpoint.Metadata.OfType()) + foreach (var producesDefaultResponseTypeAttribute in routeEndpoint.Metadata + .OfType()) { apiDescription.SupportedResponseTypes.Add(new ApiResponseType { Type = producesDefaultResponseTypeAttribute.Type, - ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, + ApiResponseFormats = {new ApiResponseFormat {MediaType = "application/json"}}, StatusCode = producesDefaultResponseTypeAttribute.StatusCode, IsDefaultResponse = true, ModelMetadata = _modelMetadataProvider.GetMetadataForType(producesDefaultResponseTypeAttribute.Type) }); } - foreach (var producesResponseTypeAttribute in routeEndpoint.Metadata.OfType()) + foreach (var producesResponseTypeAttribute in routeEndpoint.Metadata.OfType() + ) { apiDescription.SupportedResponseTypes.Add(new ApiResponseType { @@ -85,7 +92,8 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription }); } - foreach (var apiParameterDescriptionAttribute in routeEndpoint.Metadata.OfType()) + foreach (var apiParameterDescriptionAttribute in routeEndpoint.Metadata + .OfType()) { apiDescription.ParameterDescriptions.Add(new ApiParameterDescription() { @@ -96,16 +104,35 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription ModelMetadata = _modelMetadataProvider.GetMetadataForType(apiParameterDescriptionAttribute.Type) }); } - - foreach (var typedViewModelAttribute in routeEndpoint.Metadata.OfType()) + + var typedViewModelAttributes = routeEndpoint.Metadata + .OfType() + .ToList(); + if (typedViewModelAttributes.Any()) { + var types = typedViewModelAttributes.Select(a => a.Type).Distinct(); + + var ctor = typeof(DisplayNameAttribute).GetConstructor(new[] { typeof(string) }); + var options = new ProxyGenerationOptions() + { + AdditionalAttributes = + { + new CustomAttributeInfo(ctor, new object[]{"composed view model"}) + } + }; + var vm = ProxyGenerator.CreateClassProxy( + typeof(ComposedViewModel), + types.ToArray(), + options); + var vmType = vm.GetType(); + apiDescription.SupportedResponseTypes.Add(new ApiResponseType { - Type = typedViewModelAttribute.Type, - ApiResponseFormats = { new ApiResponseFormat { MediaType = "application/json" } }, + Type = vmType, + ApiResponseFormats = {new ApiResponseFormat {MediaType = "application/json"}}, StatusCode = 200, - IsDefaultResponse = false, - ModelMetadata = _modelMetadataProvider.GetMetadataForType(typedViewModelAttribute.Type) + IsDefaultResponse = true, + ModelMetadata = _modelMetadataProvider.GetMetadataForType(vmType) }); } @@ -114,7 +141,7 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription BindingSource GetBindingSource(string source) { - var staticProps = typeof(BindingSource).GetFields(BindingFlags.Static|BindingFlags.Public); + var staticProps = typeof(BindingSource).GetFields(BindingFlags.Static | BindingFlags.Public); var prop = staticProps.Single(p => p.Name == source); return prop.GetValue(null) as BindingSource; @@ -125,4 +152,9 @@ public void OnProvidersExecuted(ApiDescriptionProviderContext context) // no-op } } + + public abstract class ComposedViewModel + { + + } } \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs b/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs index a7ead8b..78c4d4c 100644 --- a/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs +++ b/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Routing; using ServiceComposer.AspNetCore; using ServiceComposer.AspNetCore.TypedViewModel; +using Swagger_for_ServiceComposer.ApiDescription; using Swagger_for_ServiceComposer.Models.Response; namespace Swagger_for_ServiceComposer.Handlers.ServiceA @@ -13,6 +14,7 @@ public class SampleHandler : ICompositionRequestsHandler { [HttpGet("/sample/{id}")] [TypedViewModel(typeof(IAValue))] + [ApiParameterDescription(Name = "id", IsRequired = true, Source = "Path", Type = typeof(int))] public Task Handle(HttpRequest request) { var routeData = request.HttpContext.GetRouteData(); diff --git a/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs b/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs index 4403d5a..723b136 100644 --- a/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs +++ b/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc; using ServiceComposer.AspNetCore; using ServiceComposer.AspNetCore.TypedViewModel; +using Swagger_for_ServiceComposer.ApiDescription; using Swagger_for_ServiceComposer.Models.Response; namespace Swagger_for_ServiceComposer.Handlers.ServiceB @@ -11,6 +12,7 @@ public class SampleHandler : ICompositionRequestsHandler { [HttpGet("/sample/{id}")] [TypedViewModel(typeof(IAnotherValue))] + [ApiParameterDescription(Name = "id", IsRequired = true, Source = "Path", Type = typeof(int))] public Task Handle(HttpRequest request) { var vm = request.GetComposedResponseModel(); From 0e8338d0757c01f539ac2f63bb40918d7a47e994 Mon Sep 17 00:00:00 2001 From: mauroservienti Date: Mon, 21 Dec 2020 16:41:55 +0100 Subject: [PATCH 5/5] Use publicly available view model factory support --- .../ServiceComposerApiDescriptionProvider.cs | 71 +++++++++---------- .../Documentation/DocumentationHandler.cs | 22 ++++++ .../Handlers/ServiceA/SampleHandler.cs | 2 - .../Handlers/ServiceB/SampleHandler.cs | 2 - .../Models/Response/ViewModel.cs | 8 +++ .../Models/ViewModelFactory.cs | 14 ++++ src/Swagger for ServiceComposer/Startup.cs | 2 + .../Swagger for ServiceComposer.csproj | 3 +- 8 files changed, 80 insertions(+), 44 deletions(-) create mode 100644 src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs create mode 100644 src/Swagger for ServiceComposer/Models/Response/ViewModel.cs create mode 100644 src/Swagger for ServiceComposer/Models/ViewModelFactory.cs diff --git a/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs b/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs index 7eb318d..490a4da 100644 --- a/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs +++ b/src/Swagger for ServiceComposer/ApiDescription/ServiceComposerApiDescriptionProvider.cs @@ -1,25 +1,20 @@ using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Reflection; -using System.Reflection.Emit; -using Castle.DynamicProxy; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; using Microsoft.AspNetCore.Routing; -using ServiceComposer.AspNetCore.TypedViewModel; namespace Swagger_for_ServiceComposer.ApiDescription { internal class ServiceComposerApiDescriptionProvider : IApiDescriptionProvider { - private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(); + // private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator(); private readonly EndpointDataSource _endpointDataSource; private readonly IModelMetadataProvider _modelMetadataProvider; - + public ServiceComposerApiDescriptionProvider(EndpointDataSource endpointDataSource, IModelMetadataProvider modelMetadataProvider) { _endpointDataSource = endpointDataSource; @@ -105,36 +100,36 @@ private Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription CreateApiDescription }); } - var typedViewModelAttributes = routeEndpoint.Metadata - .OfType() - .ToList(); - if (typedViewModelAttributes.Any()) - { - var types = typedViewModelAttributes.Select(a => a.Type).Distinct(); - - var ctor = typeof(DisplayNameAttribute).GetConstructor(new[] { typeof(string) }); - var options = new ProxyGenerationOptions() - { - AdditionalAttributes = - { - new CustomAttributeInfo(ctor, new object[]{"composed view model"}) - } - }; - var vm = ProxyGenerator.CreateClassProxy( - typeof(ComposedViewModel), - types.ToArray(), - options); - var vmType = vm.GetType(); - - apiDescription.SupportedResponseTypes.Add(new ApiResponseType - { - Type = vmType, - ApiResponseFormats = {new ApiResponseFormat {MediaType = "application/json"}}, - StatusCode = 200, - IsDefaultResponse = true, - ModelMetadata = _modelMetadataProvider.GetMetadataForType(vmType) - }); - } + // var typedViewModelAttributes = routeEndpoint.Metadata + // .OfType() + // .ToList(); + // if (typedViewModelAttributes.Any()) + // { + // var types = typedViewModelAttributes.Select(a => a.Type).Distinct(); + // + // var ctor = typeof(DisplayNameAttribute).GetConstructor(new[] { typeof(string) }); + // var options = new ProxyGenerationOptions() + // { + // AdditionalAttributes = + // { + // new CustomAttributeInfo(ctor, new object[]{"composed view model"}) + // } + // }; + // var vm = ProxyGenerator.CreateClassProxy( + // typeof(ComposedViewModel), + // types.ToArray(), + // options); + // var vmType = vm.GetType(); + // + // apiDescription.SupportedResponseTypes.Add(new ApiResponseType + // { + // Type = vmType, + // ApiResponseFormats = {new ApiResponseFormat {MediaType = "application/json"}}, + // StatusCode = 200, + // IsDefaultResponse = true, + // ModelMetadata = _modelMetadataProvider.GetMetadataForType(vmType) + // }); + // } return apiDescription; } @@ -155,6 +150,6 @@ public void OnProvidersExecuted(ApiDescriptionProviderContext context) public abstract class ComposedViewModel { - + } } \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs b/src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs new file mode 100644 index 0000000..95d7168 --- /dev/null +++ b/src/Swagger for ServiceComposer/Handlers/Documentation/DocumentationHandler.cs @@ -0,0 +1,22 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using ServiceComposer.AspNetCore; +using Swagger_for_ServiceComposer.ApiDescription; +using Swagger_for_ServiceComposer.Models.Response; + +namespace Swagger_for_ServiceComposer.Handlers.Documentation +{ + public class DocumentationHandler : ICompositionRequestsHandler + { + [HttpGet("/sample/{id}")] + [ProducesDefaultResponseType(typeof(void))] + [ProducesResponseType(typeof(ViewModel), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] + [ApiParameterDescription(Name = "id", IsRequired = true, Type = typeof(int), Source = "Path")] + public Task Handle(HttpRequest request) + { + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs b/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs index 78c4d4c..4268bbf 100644 --- a/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs +++ b/src/Swagger for ServiceComposer/Handlers/ServiceA/SampleHandler.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using ServiceComposer.AspNetCore; -using ServiceComposer.AspNetCore.TypedViewModel; using Swagger_for_ServiceComposer.ApiDescription; using Swagger_for_ServiceComposer.Models.Response; @@ -13,7 +12,6 @@ namespace Swagger_for_ServiceComposer.Handlers.ServiceA public class SampleHandler : ICompositionRequestsHandler { [HttpGet("/sample/{id}")] - [TypedViewModel(typeof(IAValue))] [ApiParameterDescription(Name = "id", IsRequired = true, Source = "Path", Type = typeof(int))] public Task Handle(HttpRequest request) { diff --git a/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs b/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs index 723b136..7a93ef3 100644 --- a/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs +++ b/src/Swagger for ServiceComposer/Handlers/ServiceB/SampleHandler.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using ServiceComposer.AspNetCore; -using ServiceComposer.AspNetCore.TypedViewModel; using Swagger_for_ServiceComposer.ApiDescription; using Swagger_for_ServiceComposer.Models.Response; @@ -11,7 +10,6 @@ namespace Swagger_for_ServiceComposer.Handlers.ServiceB public class SampleHandler : ICompositionRequestsHandler { [HttpGet("/sample/{id}")] - [TypedViewModel(typeof(IAnotherValue))] [ApiParameterDescription(Name = "id", IsRequired = true, Source = "Path", Type = typeof(int))] public Task Handle(HttpRequest request) { diff --git a/src/Swagger for ServiceComposer/Models/Response/ViewModel.cs b/src/Swagger for ServiceComposer/Models/Response/ViewModel.cs new file mode 100644 index 0000000..b38cf5c --- /dev/null +++ b/src/Swagger for ServiceComposer/Models/Response/ViewModel.cs @@ -0,0 +1,8 @@ +namespace Swagger_for_ServiceComposer.Models.Response +{ + public class ViewModel : IAValue, IAnotherValue + { + public int AValue { get; set; } + public string AnotherValue { get; set; } + } +} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Models/ViewModelFactory.cs b/src/Swagger for ServiceComposer/Models/ViewModelFactory.cs new file mode 100644 index 0000000..3f20fd5 --- /dev/null +++ b/src/Swagger for ServiceComposer/Models/ViewModelFactory.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Http; +using ServiceComposer.AspNetCore; +using Swagger_for_ServiceComposer.Models.Response; + +namespace Swagger_for_ServiceComposer.Models +{ + public class ViewModelFactory : IViewModelFactory + { + public object CreateViewModel(HttpContext httpContext, ICompositionContext compositionContext) + { + return new ViewModel(); + } + } +} \ No newline at end of file diff --git a/src/Swagger for ServiceComposer/Startup.cs b/src/Swagger for ServiceComposer/Startup.cs index a2d885d..59b25b1 100644 --- a/src/Swagger for ServiceComposer/Startup.cs +++ b/src/Swagger for ServiceComposer/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using ServiceComposer.AspNetCore; using Swagger_for_ServiceComposer.ApiDescription; +using Swagger_for_ServiceComposer.Models; namespace Swagger_for_ServiceComposer { @@ -14,6 +15,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddRouting(); services.AddViewModelComposition(); + services.AddSingleton(); services.AddSwaggerGen(); services.AddControllers(); // Swagger needs this for the ApiExplorer. diff --git a/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj b/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj index f9b4b97..6550431 100644 --- a/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj +++ b/src/Swagger for ServiceComposer/Swagger for ServiceComposer.csproj @@ -6,8 +6,7 @@ - - +