Skip to content

Commit

Permalink
Attempted to implement PR requests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Swieboda committed Mar 22, 2020
2 parents e4854a5 + c77513d commit 3f40b08
Show file tree
Hide file tree
Showing 22 changed files with 581 additions and 234 deletions.
14 changes: 12 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,19 @@ jobs:
- name: Test with dotnet
run: dotnet test
working-directory: ./src
- name: Create the package
- name: Create the SimpleEndPoints package
if: github.ref == 'refs/heads/master'
run: dotnet pack --configuration Release SimpleEndPoints
working-directory: ./src
- name: Publish the package to NUGET.ORG
- name: Create the SimpleEndpoints.Swashbuckle package
if: github.ref == 'refs/heads/master'
run: dotnet pack --configuration Release SimpleEndpoints.Swashbuckle
working-directory: ./src
- name: Publish the SimpleEndpoints package to NUGET.ORG
if: github.ref == 'refs/heads/master'
run: dotnet nuget push SimpleEndPoints/bin/Release/*.nupkg -k ${{secrets.NUGET_APIKEY}} -s https://api.nuget.org/v3/index.json --skip-duplicate
working-directory: ./src
- name: Publish the SimpleEndpoints.Swashbuckle package to NUGET.ORG
if: github.ref == 'refs/heads/master'
run: dotnet nuget push SimpleEndpoints.Swashbuckle/bin/Release/*.nupkg -k ${{secrets.NUGET_APIKEY}} -s https://api.nuget.org/v3/index.json --skip-duplicate
working-directory: ./src
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ In the NuGet Package Manager Console, type:
services.AddControllers((options) =>
{
options.AddEndpointRoutingConvention(); // This is required to translate endpoint names
options.AddSimpleEndpointsRouting(); // This is required to translate endpoint names
// Optional: If you need to support Swashbuckle, you will need the "SimpleEndpoints.Swashbuckle" package too
options.AddSwashbuckleCompatibilityForSimpleEndpoints(); // this is required to support Swashbuckle
});
}
```
Expand Down
3 changes: 3 additions & 0 deletions src/SimpleEndPoints/Assembly.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("SimpleEndpoints.Tests")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using SimpleEndpoints.VerbScoped;

namespace SimpleEndpoints.Conventions
{
internal class ApiDescriptionGroupCollectionProviderDecorator : IApiDescriptionGroupCollectionProvider
{
private readonly IApiDescriptionGroupCollectionProvider _inner;

public ApiDescriptionGroupCollectionProviderDecorator(IApiDescriptionGroupCollectionProvider inner)
{
_inner = inner;
}

public ApiDescriptionGroupCollection ApiDescriptionGroups
{
get
{
foreach (var apiDescriptionGroup in _inner.ApiDescriptionGroups.Items)
{
foreach (var apiDescription in apiDescriptionGroup.Items)
{
if (apiDescription.ActionDescriptor is ControllerActionDescriptor controller)
{
if (typeof(IDeleteEndpoint).IsAssignableFrom(controller.ControllerTypeInfo))
{
apiDescription.HttpMethod = "DELETE";
}
if (typeof(IGetEndpoint).IsAssignableFrom(controller.ControllerTypeInfo))
{
apiDescription.HttpMethod = "GET";
}
if (typeof(IPostEndpoint).IsAssignableFrom(controller.ControllerTypeInfo))
{
apiDescription.HttpMethod = "POST";
}
if (typeof(IPutEndpoint).IsAssignableFrom(controller.ControllerTypeInfo))
{
apiDescription.HttpMethod = "PUT";
}
}
}
}

return _inner.ApiDescriptionGroups;
}
}
}
}
65 changes: 9 additions & 56 deletions src/SimpleEndPoints/Conventions/EndpointRoutingConvention.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
using System;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Routing;
using SimpleEndpoints.Extensions;
using SimpleEndpoints.VerbScoped;
using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace SimpleEndpoints.Conventions
{
public class EndpointRoutingConvention : IApplicationModelConvention
public sealed class EndpointRoutingConvention : IApplicationModelConvention
{
private const string EndpointPlaceholder = "[endpoint]";
private readonly IConventionMutator[] _conventionMutators =
{
new RouteMutator(),
new HttpMethodMetadataMutator()
};

private readonly SimpleEndpointsConfiguration _configuration;

Expand All @@ -23,55 +21,10 @@ public void Apply(ApplicationModel application)
{
foreach (var controller in application.Controllers)
{
MapRouteConvention(controller);
}
}

private void MapRouteConvention(ControllerModel controller)
{
var routeTemplate = controller.Selectors[0].AttributeRouteModel.Template;

//If we haven't set a route with [Route("")] on our endpoint
if (routeTemplate.Equals(EndpointPlaceholder, StringComparison.OrdinalIgnoreCase))
{
var routeBuilder = new StringBuilder();

//Do we want to set a global route prefix e.g. api/*?
if (!string.IsNullOrWhiteSpace(_configuration.RoutePrefix))
foreach (var mutator in _conventionMutators)
{
routeBuilder.Append($"{_configuration.RoutePrefix}/");
mutator.Mutate(controller, _configuration);
}

//Do a replacement on the Endpoint name e.g. MyGreatEndpoint to just MyGreat
routeBuilder.Append(routeTemplate.Replace($"{EndpointPlaceholder}",
controller.ControllerName.Replace(_configuration.EndpointReplacementToken, string.Empty)));

controller.Selectors[0].AttributeRouteModel.Template = routeBuilder.ToString();
}

AddHttpMethodMetadata(controller);
}

//This allows us to get away from having to add Http verb attributes to our action methods, it can be driven by base class
private static void AddHttpMethodMetadata(ControllerModel controller)
{
var controllerInterfaces = controller.ControllerType.ImplementedInterfaces.ToArray();

if (controllerInterfaces.Contains(typeof(IDeleteEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"DELETE"}));
}
else if (controllerInterfaces.Contains(typeof(IGetEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"GET"}));
}
else if (controllerInterfaces.Contains(typeof(IPostEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"POST"}));
}
else if (controllerInterfaces.Contains(typeof(IPutEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"PUT"}));
}
}
}
Expand Down
32 changes: 32 additions & 0 deletions src/SimpleEndPoints/Conventions/HttpMethodMetadataMutator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System.Linq;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Routing;
using SimpleEndpoints.VerbScoped;

namespace SimpleEndpoints.Conventions
{
internal class HttpMethodMetadataMutator : IConventionMutator
{
public void Mutate(ControllerModel controller, SimpleEndpointsConfiguration configuration)
{
var controllerInterfaces = controller.ControllerType.ImplementedInterfaces.ToArray();

if (controllerInterfaces.Contains(typeof(IDeleteEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"DELETE"}));
}
else if (controllerInterfaces.Contains(typeof(IGetEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"GET"}));
}
else if (controllerInterfaces.Contains(typeof(IPostEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"POST"}));
}
else if (controllerInterfaces.Contains(typeof(IPutEndpoint)))
{
controller.Selectors[0].EndpointMetadata.Add(new HttpMethodMetadata(new[] {"PUT"}));
}
}
}
}
9 changes: 9 additions & 0 deletions src/SimpleEndPoints/Conventions/IConventionMutator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace SimpleEndpoints.Conventions
{
internal interface IConventionMutator
{
void Mutate(ControllerModel controller, SimpleEndpointsConfiguration configuration);
}
}
31 changes: 31 additions & 0 deletions src/SimpleEndPoints/Conventions/RouteMutator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Text;
using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace SimpleEndpoints.Conventions
{
internal class RouteMutator : IConventionMutator
{
private const string EndpointPlaceholder = "[endpoint]";

public void Mutate(ControllerModel controller, SimpleEndpointsConfiguration configuration)
{
var routeBuilder = new StringBuilder();
var routeTemplate = controller.Selectors[0].AttributeRouteModel.Template;

if (routeTemplate.Equals(EndpointPlaceholder, StringComparison.OrdinalIgnoreCase))
{
routeBuilder
.Append($"{configuration.RoutePrefix}/")
.Append(routeTemplate.Replace($"{EndpointPlaceholder}",
controller.ControllerName.Replace(configuration.EndpointReplacementToken, string.Empty)));
}
else
{
routeBuilder.Append(routeTemplate);
}

controller.Selectors[0].AttributeRouteModel.Template = routeBuilder.ToString();
}
}
}
99 changes: 0 additions & 99 deletions src/SimpleEndPoints/Extensions/MvcOptionsExtensions.cs

This file was deleted.

26 changes: 26 additions & 0 deletions src/SimpleEndPoints/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.DependencyInjection;
using SimpleEndpoints.Conventions;

namespace SimpleEndpoints.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddSimpleEndpointRouting(this IServiceCollection services,
Action<SimpleEndpointsConfiguration> configure = null)
{
var configuration = new SimpleEndpointsConfiguration();
configure?.Invoke(configuration);

services.AddMvcCore(options => { options.Conventions.Add(new EndpointRoutingConvention(configuration)); });

services.AddSingleton<ApiDescriptionGroupCollectionProvider>();
services.AddSingleton<IApiDescriptionGroupCollectionProvider>(x =>
new ApiDescriptionGroupCollectionProviderDecorator(
x.GetService<ApiDescriptionGroupCollectionProvider>()));

return services;
}
}
}
2 changes: 1 addition & 1 deletion src/SimpleEndPoints/SimpleEndpoints.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/dasiths/SimpleEndpoints</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<PackageTags>aspnetcore api controller endpoints</PackageTags>
<Version>1.1.0</Version>
<Version>1.2.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 3f40b08

Please sign in to comment.