correct routes for API + backoffice

This commit is contained in:
2021-12-13 13:40:04 +01:00
parent 02e79a6dff
commit 16c980bad4
14 changed files with 163 additions and 50 deletions
+22
View File
@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace zero.Api;
public class ApiApplicationResolverHandler : IBackofficeApplicationResolverHandler
{
public bool TryResolve(HttpContext context, IEnumerable<Application> applications, ZeroUser user, out Application resolved)
{
var routeValues = context.Features.Get<IRouteValuesFeature>().RouteValues;
if (routeValues.ContainsKey("zero_app_key"))
{
string appKey = routeValues["zero_app_key"] as string;
resolved = applications.FirstOrDefault(x => x.Alias == appKey);
return resolved != null;
}
resolved = null;
return false;
}
}
@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc;
namespace zero.Api.Endpoints.NotFound;
public class NotFoundZeroApiController : Controller
{
public virtual ActionResult Index()
{
return NotFound();
}
}
+1
View File
@@ -23,6 +23,7 @@ public class ZeroApiPlugin : ZeroPlugin
{
services.AddOptions<ApiOptions>().Bind(configuration.GetSection("Zero:Api")).Configure<IWebHostEnvironment>(ConfigureOptions);
services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, ZeroApiMvcOptions>());
services.AddTransient<IBackofficeApplicationResolverHandler, ApiApplicationResolverHandler>();
ZeroModuleCollection modules = new();
+3 -1
View File
@@ -57,7 +57,9 @@ public class ZeroApiControllerModelConvention : IControllerModelConvention
if (appAware)
{
path.Append("{zero_app_slug}/");
path.Append("{zero_app_key}/");
// TODO add route constraint which only allows registered app-ids
// see https://nemi-chand.github.io/creating-custom-routing-constraint-in-aspnet-core-mvc/
}
path.Append("[controller]");
@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Builder;
namespace zero.Backoffice;
public static class ZeroEndpointRouteBuilderExtensions
{
public static void MapZeroApi(this IZeroEndpointRouteBuilder endpoints, string path = "/zero/api")
{
endpoints.MapFallbackToController(path.EnsureEndsWith('/') + "{**path}", "Index", "NotFoundZeroApi");
//app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments(path + "/api"), app1 =>
//{
// app1.UseEndpoints(endpoints =>
// {
// //IZeroOptions options = app.ApplicationServices.GetService<IZeroOptions>(); // TODO oO
// // see https://our.umbraco.com/documentation/reference/routing/custom-routes#where-to-put-your-routing-logic
// //string path = options.BackofficePath.EnsureStartsWith('/').TrimEnd('/');
// //endpoints.MapFallbackToController(path + "/{**path}", "Index", "ZeroIndex");
// //endpoints.MapControllers();
// });
//});
}
}
@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Builder;
namespace zero.Backoffice;
public static class ZeroEndpointRouteBuilderExtensions
{
public static void MapZeroBackoffice(this IZeroEndpointRouteBuilder endpoints, string path = "/zero")
{
endpoints.MapFallbackToController(path.EnsureEndsWith('/') + "{**path}", "Index", "ZeroIndex");
endpoints.MapFallbackToController(path.EnsureEndsWith('/') + "backoffice/{**path}", "Index", "NotFoundZeroApi");
//app.UseWhen(ctx => ctx.Request.Path.StartsWithSegments(path + "/api"), app1 =>
//{
// app1.UseEndpoints(endpoints =>
// {
// //IZeroOptions options = app.ApplicationServices.GetService<IZeroOptions>(); // TODO oO
// // see https://our.umbraco.com/documentation/reference/routing/custom-routes#where-to-put-your-routing-logic
// //string path = options.BackofficePath.EnsureStartsWith('/').TrimEnd('/');
// //endpoints.MapFallbackToController(path + "/{**path}", "Index", "ZeroIndex");
// //endpoints.MapControllers();
// });
//});
}
}
+52 -38
View File
@@ -39,29 +39,65 @@ public class ApplicationResolver : IApplicationResolver
return null;
}
Application app;
Application app = null;
//if (context.IsBackofficeRequest(Options.ZeroPath))
//{
// app = await ResolveFromUser(user);
//}
//else
//{
// app = await ResolveFromRequest(context);
//}
app = await ResolveFromRequest(context);
if (context.IsBackofficeRequest(Options.ZeroPath))
{
ZeroUser userEntity = await GetBackofficeUser(user);
app = await ResolveFromBackofficeHandlers(context, userEntity) ?? await ResolveFromUser(userEntity);
}
if (app == null)
{
//Logger.LogWarning("Could not resolve application for host {host}", context.Request.Host);
IList<Application> apps = await GetApplications();
app = apps.FirstOrDefault();
app = await ResolveFromHandlers(context) ?? await ResolveFromRequest(context);
}
if (app == null)
{
Logger.LogWarning("Could not resolve application for host {host}", context.Request.Host);
return null;
}
return app;
}
/// <inheritdoc />
public async Task<Application> ResolveFromHandlers(HttpContext context)
{
IList<Application> apps = await GetApplications();
IEnumerable<IApplicationResolverHandler> handlers = Handler.GetAll<IApplicationResolverHandler>();
foreach (IApplicationResolverHandler handler in handlers)
{
if (handler.TryResolve(context, apps, out Application resolved))
{
return resolved;
}
}
return null;
}
/// <inheritdoc />
public async Task<Application> ResolveFromBackofficeHandlers(HttpContext context, ZeroUser user)
{
IList<Application> apps = await GetApplications();
IEnumerable<IBackofficeApplicationResolverHandler> handlers = Handler.GetAll<IBackofficeApplicationResolverHandler>();
foreach (IBackofficeApplicationResolverHandler handler in handlers)
{
if (handler.TryResolve(context, apps, user, out Application resolved))
{
return resolved;
}
}
return null;
}
/// <inheritdoc />
public async Task<Application> ResolveFromUser(ClaimsPrincipal user)
{
@@ -108,37 +144,15 @@ public class ApplicationResolver : IApplicationResolver
/// <inheritdoc />
public async Task<Application> ResolveFromRequest(HttpContext context)
{
//if (Options.Applications.Count < 2)
//{
// return (await GetApplications()).FirstOrDefault();
//}
IApplicationResolverHandler handler = Handler.Get<IApplicationResolverHandler>();
Application app = handler?.Resolve(context.Request, await GetApplications());
if (app == null)
{
app = await ResolveFromUri(context.Request.GetEncodedUrl());
}
return app;
}
public Task<Application> ResolveFromRequest(HttpContext context) => ResolveFromUri(context.Request.GetEncodedUrl());
/// <inheritdoc />
public async Task<Application> ResolveFromUri(string uriString)
{
return ResolveFromUriInternal(new Uri(uriString, UriKind.Absolute), await GetApplications());
}
public async Task<Application> ResolveFromUri(string uriString) => ResolveFromUriInternal(new Uri(uriString, UriKind.Absolute), await GetApplications());
/// <inheritdoc />
public async Task<Application> ResolveFromUri(Uri uri)
{
return ResolveFromUriInternal(uri, await GetApplications());
}
public async Task<Application> ResolveFromUri(Uri uri) => ResolveFromUriInternal(uri, await GetApplications());
/// <summary>
@@ -4,5 +4,5 @@ namespace zero.Applications;
public interface IApplicationResolverHandler : IHandler
{
Application Resolve(HttpRequest request, IEnumerable<Application> applications);
bool TryResolve(HttpContext context, IEnumerable<Application> applications, out Application resolved);
}
@@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Http;
namespace zero.Applications;
public interface IBackofficeApplicationResolverHandler : IHandler
{
bool TryResolve(HttpContext context, IEnumerable<Application> applications, ZeroUser user, out Application resolved);
}
+1 -1
View File
@@ -110,7 +110,7 @@ public class ZeroContext : IZeroContext
Application = await AppResolver.Resolve(context, BackofficeUser);
AppId = Application.Id;
Logger.LogDebug("Resolved {appId} for request {uri}", AppId, context.Request.Host.ToString() + context.Request.Path.Value.EnsureStartsWith('/'));
Logger.LogInformation("Resolved {appId} ({uri})", AppId, context.Request.Host.ToString() + context.Request.Path.Value.EnsureStartsWith('/'));
// set default database for document store
Store.ResolvedDatabase = Application.Database;
+1 -1
View File
@@ -14,8 +14,8 @@ public class ZeroApplicationBuilder : IZeroApplicationBuilder
App = app;
App.UseStaticFiles();
//App.UseExceptionHandler("/zero/api/error");
App.UseMiddleware<ZeroContextMiddleware>();
App.UseRouting();
App.UseMiddleware<ZeroContextMiddleware>();
App.UseAuthentication();
App.UseAuthorization();
+12 -7
View File
@@ -20,22 +20,27 @@ public class DevApplicationResolverHandler : IApplicationResolverHandler
}
public Application Resolve(HttpRequest request, IEnumerable<Application> applications)
public bool TryResolve(HttpContext context, IEnumerable<Application> applications, out Application resolved)
{
resolved = null;
//if (!Env.IsDevelopment())
//{
// return null;
// return false;
//}
if (request.Host.Host.Contains("ngrok.io"))
if (context.Request.Host.Host.Contains("ngrok.io"))
{
return applications.First(x => x.Id == "app.hofbauer");
resolved = applications.First(x => x.Id == "app.hofbauer");
return true;
}
if (request.Host.Port.HasValue && PortMap.TryGetValue(request.Host.Port.Value, out string appId))
if (context.Request.Host.Port.HasValue && PortMap.TryGetValue(context.Request.Host.Port.Value, out string appId))
{
return applications.FirstOrDefault(x => x.Id == appId);
resolved = applications.FirstOrDefault(x => x.Id == appId);
return true;
}
return null;
return false;
}
}
+2 -1
View File
@@ -1,10 +1,11 @@
@page
@model IndexModel
@inject zero.Context.IZeroContext context
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<h1 class="display-4">Welcome to <u>@context.AppId</u></h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
+2
View File
@@ -41,6 +41,8 @@ app.UseZero().WithEndpoints(x =>
//x.MapControllerRoute("default", "api/{controller}/{action=Index}/{id?}");
x.MapControllers();
x.MapRazorPages();
x.MapZeroApi();
x.MapZeroBackoffice();
x.MapZeroRoutes();
});