Skip to content

Commit 127bf4b

Browse files
committed
chore: basics
1 parent 98b1119 commit 127bf4b

File tree

10 files changed

+73
-45
lines changed

10 files changed

+73
-45
lines changed

src/Examples/JsonApiDotNetCoreExample/Startup.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public Startup(IWebHostEnvironment env)
2525
}
2626

2727
public virtual void ConfigureServices(IServiceCollection services)
28-
{ services.AddJsonApi();
28+
{
29+
services.AddJsonApi();
2930
var loggerFactory = new LoggerFactory();
3031
services
3132
.AddSingleton<ILoggerFactory>(loggerFactory)
@@ -56,7 +57,6 @@ public virtual void Configure(
5657
{
5758

5859
context.Database.EnsureCreated();
59-
6060
app.UseJsonApi();
6161
}
6262

src/JsonApiDotNetCore/Builders/JsonApiApplicationBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public void ConfigureMvc()
7171

7272
_mvcBuilder.AddMvcOptions(options =>
7373
{
74-
options.EnableEndpointRouting = true;
74+
options.EnableEndpointRouting = false;
7575
options.Filters.Add(exceptionFilterProvider.Get());
7676
options.Filters.Add(typeMatchFilterProvider.Get());
7777
options.InputFormatters.Insert(0, new JsonApiInputFormatter());

src/JsonApiDotNetCore/Data/DefaultResourceRepository.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using JsonApiDotNetCore.Models;
1111
using JsonApiDotNetCore.Serialization;
1212
using Microsoft.EntityFrameworkCore;
13+
using Microsoft.EntityFrameworkCore.Internal;
1314
using Microsoft.EntityFrameworkCore.Query.Internal;
1415
using Microsoft.Extensions.Logging;
1516

@@ -308,7 +309,7 @@ public virtual async Task<IEnumerable<TResource>> PageAsync(IQueryable<TResource
308309
}
309310
else
310311
{
311-
if (entities is IAsyncQueryProvider)
312+
if (IsFromDatabase(entities))
312313
{
313314
// since EntityFramework does not support IQueryable.Reverse(), we need to know the number of queried entities
314315
var totalCount = await entities.CountAsync();
@@ -328,6 +329,11 @@ public virtual async Task<IEnumerable<TResource>> PageAsync(IQueryable<TResource
328329
}
329330
}
330331

332+
private static bool IsFromDatabase(IQueryable<TResource> entities)
333+
{
334+
return entities is DbSet<TResource>;
335+
}
336+
331337
/// <inheritdoc />
332338
public async Task<int> CountAsync(IQueryable<TResource> entities)
333339
{

src/JsonApiDotNetCore/Extensions/IApplicationBuilderExtensions.cs

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.AspNetCore.Mvc;
99
using Microsoft.Extensions.DependencyInjection;
1010
using Microsoft.Extensions.Logging;
11+
using System;
1112

1213
namespace JsonApiDotNetCore.Extensions
1314
{
@@ -33,19 +34,45 @@ public static void UseJsonApi(this IApplicationBuilder app)
3334
// An endpoint is selected and set on the HttpContext if a match is found
3435
app.UseRouting();
3536

36-
// middleware to run after routing occurs.
37-
app.UseMiddleware<CurrentRequestMiddleware>();
3837

39-
// Executes the endpoitns that was selected by routing.
40-
app.UseEndpoints(endpoints =>
38+
39+
40+
41+
42+
//our custom middleware
43+
app.Use((context, next) =>
4144
{
42-
endpoints.MapControllers();
45+
var endpointFeature = context.Features[typeof(Microsoft.AspNetCore.Http.Features.IEndpointFeature)]
46+
as Microsoft.AspNetCore.Http.Features.IEndpointFeature;
47+
48+
Microsoft.AspNetCore.Http.Endpoint endpoint = endpointFeature?.Endpoint;
49+
50+
//Note: endpoint will be null, if there was no
51+
//route match found for the request by the endpoint route resolver middleware
52+
if (endpoint != null)
53+
{
54+
var routePattern = (endpoint as Microsoft.AspNetCore.Routing.RouteEndpoint)?.RoutePattern
55+
?.RawText;
56+
57+
Console.WriteLine("Name: " + endpoint.DisplayName);
58+
Console.WriteLine($"Route Pattern: {routePattern}");
59+
Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
60+
}
61+
return next();
4362
});
63+
64+
65+
66+
// middleware to run after routing occurs.
67+
app.UseMiddleware<CurrentRequestMiddleware>();
68+
69+
app.UseMvc();
70+
4471
}
4572

4673
private static void DisableDetailedErrorsIfProduction(IApplicationBuilder app)
4774
{
48-
var webHostEnvironment = (IWebHostEnvironment) app.ApplicationServices.GetService(typeof(IWebHostEnvironment));
75+
var webHostEnvironment = (IWebHostEnvironment)app.ApplicationServices.GetService(typeof(IWebHostEnvironment));
4976
if (webHostEnvironment.EnvironmentName == "Production")
5077
{
5178
JsonApiOptions.DisableErrorStackTraces = true;

src/JsonApiDotNetCore/Extensions/IServiceCollectionExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,20 @@ public static IServiceCollection AddJsonApi(this IServiceCollection services,
5757
{
5858
var application = new JsonApiApplicationBuilder(services, mvcBuilder ?? services.AddMvcCore());
5959
if (options != null)
60+
{
6061
application.ConfigureJsonApiOptions(options);
62+
}
6163
application.ConfigureMvc();
64+
65+
// if the discovery facade is available, we should use it.
6266
if (discovery != null)
67+
{
6368
application.AutoDiscover(discovery);
69+
}
6470
if (resources != null)
71+
{
6572
application.ConfigureResources(resources);
73+
}
6674
application.ConfigureServices();
6775
return services;
6876
}

src/JsonApiDotNetCore/Internal/DefaultRoutingConvention.cs

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,12 @@ public class DefaultRoutingConvention : IJsonApiRoutingConvention, IControllerRe
3838
{
3939
private readonly string _namespace;
4040
private readonly IResourceNameFormatter _formatter;
41-
private readonly IResourceGraph _resourceGraph;
4241
private readonly HashSet<string> _registeredTemplates = new HashSet<string>();
4342
private readonly Dictionary<string, Type> _registeredResources = new Dictionary<string, Type>();
44-
public DefaultRoutingConvention(IJsonApiOptions options, IResourceNameFormatter formatter, IResourceGraph resourceGraph)
43+
public DefaultRoutingConvention(IJsonApiOptions options, IResourceNameFormatter formatter)
4544
{
4645
_namespace = options.Namespace;
4746
_formatter = formatter;
48-
_resourceGraph = resourceGraph;
4947
}
5048

5149
/// <inheritdoc/>
@@ -61,38 +59,21 @@ public void Apply(ApplicationModel application)
6159
foreach (var controller in application.Controllers)
6260
{
6361
var resourceType = GetResourceTypeFromController(controller.ControllerType);
64-
6562
if (resourceType != null)
6663
{
6764
_registeredResources.Add(controller.ControllerName, resourceType);
6865
}
69-
70-
if (RoutingConventionDisabled(controller) == false)
66+
if (!RoutingConventionDisabled(controller))
7167
{
7268
continue;
7369
}
74-
// if defined in resourcegraph, it should be used
75-
var contexts = _resourceGraph.GetResourceContexts();
76-
77-
var foundResourceGraph = contexts.First(c => c.ResourceType == resourceType);
78-
string template = null;
79-
if (foundResourceGraph != null)
80-
{
81-
template = $"{_namespace}/{foundResourceGraph.ResourceName}";
82-
}
83-
else
84-
{
85-
template = TemplateFromResource(controller) ?? TemplateFromController(controller);
86-
}
87-
70+
var template = TemplateFromResource(controller) ?? TemplateFromController(controller);
8871
if (template == null)
8972
{
9073
throw new JsonApiSetupException($"Controllers with overlapping route templates detected: {controller.ControllerType.FullName}");
9174
}
92-
9375
controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel { Template = template };
9476
}
95-
9677
}
9778

9879
public void HandleControllers(IList<ControllerModel> controllers)

src/JsonApiDotNetCore/Middleware/CurrentRequestMiddleware.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using JsonApiDotNetCore.Internal.Contracts;
77
using JsonApiDotNetCore.Managers.Contracts;
88
using Microsoft.AspNetCore.Http;
9+
using Microsoft.AspNetCore.Http.Features;
910
using Microsoft.AspNetCore.Routing;
1011
using Microsoft.Extensions.Primitives;
1112

@@ -165,6 +166,19 @@ private void FlushResponse(HttpContext context, int statusCode)
165166
/// <returns></returns>
166167
private ResourceContext GetCurrentEntity()
167168
{
169+
var endpointFeature = _httpContext.Features[typeof(IEndpointFeature)] as IEndpointFeature;
170+
171+
Endpoint endpoint = endpointFeature?.Endpoint;
172+
// endpoint will be null if no match found
173+
if(endpoint != null)
174+
{
175+
176+
var routePattern = (endpoint as RouteEndpoint)?.RoutePattern?.RawText;
177+
Console.WriteLine("Name: " + endpoint.DisplayName);
178+
Console.WriteLine($"Route Pattern: {routePattern}");
179+
Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
180+
181+
}
168182
var controllerName = (string)_httpContext.GetRouteData().Values["controller"];
169183
var resourceType = _controllerResourceMapping.GetAssociatedResource(controllerName);
170184
var requestResource = _resourceGraph.GetResourceContext(resourceType);

test/JsonApiDotNetCoreExampleTests/Acceptance/CamelCasedModelsControllerTests.cs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,22 @@ public CamelCasedModelsControllerTests(TestFixture<Startup> fixture)
2525
{
2626
_fixture = fixture;
2727
_context = fixture.GetService<AppDbContext>();
28-
_faker = new Faker<CamelCasedModel>()
29-
.RuleFor(m => m.CompoundAttr, f => f.Lorem.Sentence());
28+
_faker = new Faker<CamelCasedModel>().RuleFor(m => m.CompoundAttr, f => f.Lorem.Sentence());
3029
}
3130

3231
[Fact]
33-
public async Task Can_Get_CamelCasedModels()
32+
public async Task CamelCasedGet_ControllerExists_GivesBackResult()
3433
{
3534
// Arrange
3635
var model = _faker.Generate();
3736
_context.CamelCasedModels.Add(model);
3837
_context.SaveChanges();
39-
4038
var httpMethod = new HttpMethod("GET");
4139
var route = "api/v1/camelCasedModels";
42-
var builder = new WebHostBuilder()
43-
.UseStartup<Startup>();
44-
var server = new TestServer(builder);
45-
var client = server.CreateClient();
4640
var request = new HttpRequestMessage(httpMethod, route);
4741

4842
// Act
49-
var response = await client.SendAsync(request);
43+
var response = await _fixture.Client.SendAsync(request);
5044
var body = await response.Content.ReadAsStringAsync();
5145
var deserializedBody = _fixture.GetDeserializer().DeserializeList<CamelCasedModel>(body).Data;
5246

test/JsonApiDotNetCoreExampleTests/Acceptance/TestFixture.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ public class TestFixture<TStartup> : IDisposable where TStartup : class
2121
private IServiceProvider _services;
2222
public TestFixture()
2323
{
24-
var builder = new WebHostBuilder()
25-
.UseStartup<TStartup>();
24+
var builder = new WebHostBuilder().UseStartup<TStartup>();
2625
_server = new TestServer(builder);
2726
_services = _server.Host.Services;
2827

test/UnitTests/Routing/DefaultRoutingConventionTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public void DefaultRoutingCustomRoute_CustomRouteRegistered_ShouldBeRegisteredAs
2525
// Arrange
2626
var mockOptions = new Mock<IJsonApiOptions>();
2727
var mockFormatter = new Mock<IResourceNameFormatter>();
28-
var resourceGraph = new ResourceGraphBuilder().AddResource<TodoItem>("customRouteForMe").Build();
29-
var convention = new DefaultRoutingConvention(mockOptions.Object, mockFormatter.Object, resourceGraph);
28+
var convention = new DefaultRoutingConvention(mockOptions.Object, mockFormatter.Object);
3029
var attributes = new List<object>().AsReadOnly();
3130
var controllerModel = new ControllerModel(typeof(TodoItemsController).GetTypeInfo(), attributes);
3231
controllerModel.ControllerName = "Test";

0 commit comments

Comments
 (0)