ASP.NET Core Endpoint - route all calls to specific route first - asp.net-core

What do I need to change this to route all requests to /api/ShibAuth?
endpoints.MapGet("/", async context =>
{
context.Response.Redirect("/api/ShibAuth");
});
The code above obviously routes any calls to root URL and I've already tried what I though was appropriate wildcard.

What do I need to change this to route all requests to /api/ShibAuth?
Well, if I correctly understand the requirement, you would like all of your request to redirect to this /api/ShibAuth route at the begining.
Certainly, we can implement above scenario using UriBuilder class which provides the functionality to modify HttpRequest.Path. Finally, rebuild the request URI and redirect to your expected path. You can do as following
Solution:
app.MapGet("/", async context =>
{
var originalUrl = context.Request.GetDisplayUrl();
var routeToCallFirst = "api/ShibAuth";
var updatedUrl = (new UriBuilder(originalUrl) { Host = context.Request.Host.Host, Path = routeToCallFirst }).Uri;
context.Response.Redirect(updatedUrl.AbsoluteUri);
});
Output:
Note: Here, I am redirecting the all landing request to /api/ShibAuth controller from the middleware.

Related

ASP.NET Core URL rewriting with query parameters

I have a LitElement based SPA with an ASP.NET Core backend which hosts the static files and a REST API for loading data into the SPA.
The user starts with /index.html and the client-side router brings him to, f.e.,
/data-analysis or /dashboard.
When the user now presses the browser refresh button she gets 404 which is to be expected since the server does not know any of these subpaths.
I read elsewhere that I have to take care of this on the server side, so I came up with this middleware in my Startup.cs Configure method:
app.Use(async (c, next) =>
{
//Identify subpaths...
c.Request.Path = "/index.html";
await next();
});
For all subpaths it brings the user back to index.html which is nice. Better yet would be to let the client side know which subpath to restore. For this I added the following lines to the code above:
var url = c.Request.Path.Value;
c.Request.QueryString = c.Request.QueryString.Add("page", $"{url.Substring(1)}");
I expected the client to see a window.location of, f.e.
.../index.html?page=data-analysis
but the query string never arrives, window.location.search is always empty on the client side.
Is this possible at all or am I misunderstanding something here?
Nicolas
Studying Microsofts documentation about the URL rewriting middleware led me to the conclusion that I should redirect and not rewrite! The following code produces the desired result. Note that the 'return' statement is critical, because no further middleware should be called!
app.Use(async (c, next) =>
{
var url = c.Request.Path.Value;
//Identify subpaths...
if(... should redirect ...)
{
c.Response.Redirect($"/index.html?page={url.Substring(1)}");
return;
}
await next();
});

Passing Controller Action output as SupplyData in UseSpaPrerendering of .Net Core

In .Net Core application, I have below code in Configure method of Startup.cs file.
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
spa.UseSpaPrerendering(options =>
{
options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.js";
options.BootModuleBuilder = env.IsDevelopment() ? new AngularCliBuilder(npmScript: "build:ssr") : null;
options.ExcludeUrls = new[] { "/sockjs-node" };
});
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
UseSpaPrerendering has an option to provide SupplyData callback which lets you pass arbitrary, per-request, JSON-serializable data.
In my case there are pages in my Angular application which makes http requests to fetch data. Since these requests are made to the same application. I see a potential of optimization i.e. if we could just call the corresponding Controller Action method and supply its data to Angular, so that we dont have to make an http request for SSR.
Can anyone please guide how to achieve this.
I know that below is how we pass data using SupplyData
options.SupplyData = (context, data) =>
{
// Creates a new value called isHttpsRequest that's passed to TypeScript code
data["isHttpsRequest"] = context.Request.IsHttps;
};
But how to we pass the results/output of a Controller Actions (which returns json).
I wrote a package to determine the currently activated SPA route from the supplydata delegate.
https://github.com/MusicDemons/AspNetSpaPrerendering
You have to define all your SPA routes using the SpaRouteBuilder and then you can check which route was activated and get the route data (like an id). Based on that you get data from your database through your repositories and add this data to the array. A complete example is included.

Override routing in ASP.NET CORE 2.2 to implicitly route to an area if user have some permissions

I'm looking for an easy way to change routing behaviour a little and add extra area data into route data if the user has some sorts of permissions.
Let's say for regular user url site/shop/12 should route to ShopController
but for admin it should route to AdminArea/ShopController
Please, consider that this question isn't about HTTP redirect, it's about extending infrastructure on a framework level to allow extra functionality on Routing or controller invocation
You could use URL Rewriting Middleware to redirect the request for Admin user
1.Create a Redirect rule:
public class RewriteRules
{
public static void RedirectRequests(RewriteContext context)
{
//Your logic
var IsAdminRole = context.HttpContext.User.IsInRole("Admin");
if (IsAdminRole)
{
var request = context.HttpContext.Request;
string area = "AdminArea";
var path = request.Path.Value;
//Add your conditions of redirecting
if(path.Split("/")[1] != area)// If the url does not start with "/AdminArea"
{
context.HttpContext.Response.Redirect($"/{area}{ request.Path.Value }");
}
}
}
}
2.Use the middleware in Startup Configure method:
app.UseAuthentication();//before the Rewriter middleware
app.UseRewriter(new RewriteOptions()
.Add(RewriteRules.RedirectRequests)
);
Add logic to the controller method that handles site/shop/12 to check if the user is an admin, and if it is, redirect to to the proper admin area and controller.
var isAdmin = IsUserAnAdmin();
if (isAdmin) {
// This will redirect to the Index method defined in the ShopController
// in the area name AdminArea
return RedirectToAction("Index", "Shop", new { Area = "AdminArea" });
}
I think the best way is to set the correct URLs on the front-end and then validate the request on the end-point doing something like this:
[HttpGet]
[Route("v1.0/download/document")]
public IActionResult download_document(int id, string token)
{
try
{
if (token == null || isNotAdmin(token))
return Unauthorized();
That way your end-points are protected and you avoid redirections. Plus, in my opinion everything makes a lot more sense on the front-end

Generate route templates from URL using ASP.NET Core

I've been reading about URL generation based on values in a route dictionary.
app.Run(async (context) =>
{
var dictionary = new RouteValueDictionary
{
{ "operation", "create" },
{ "id", 123}
};
var vpc = new VirtualPathContext(context, null, dictionary,
"Track Package Route");
var path = routes.GetVirtualPath(vpc).VirtualPath;
context.Response.ContentType = "text/html";
await context.Response.WriteAsync("Menu<hr/>");
await context.Response.WriteAsync(
$"<a href='{path}'>Create Package 123</a><br/>");
});
Is it possible to perform the reverse action and generate a route template from a URL? I would think ASP.NET core would need to do this in order to check an incoming request URL to see if it matches a route in the route table in middleware. So if a route was mapped using say "/package/{operation}/{id}", it would have to have some mechanism to see that the URL "/package/create/123" matches this route.
I have a need to perform this type of action to see if a URL matches a custom route template that I have stored in the database when a request comes in.

Filter for static file middleware

Is there a way to intercept the request before it got serve, so I can edit a picture or create dynamic pdf on demand? I tried using MapArea and redirect the request to a controller, but when I use staticfiles middleware, it catch the request, and my controller wont handle the request.
If your static files does not exist and you want generate them on-thy-fly - it's better to create your own middelware and register it before UseStaticFiles.
If files exist, but you want "slightly" modify response (for different users for example) - you may use OnPrepareResponse handler in static file options:
var staticFileOptions = new StaticFileOptions
{
OnPrepareResponse = (context) =>
{
var fn = context.File.Name.ToLowerInvariant();
if (fn.EndsWith(".pdf"))
{
SomeService.LogPdfDownload(context.Context.Response);
}
else
{
context.Context.Response.Headers.Add("Cache-Control", "public, max-age=15552000"); // 180 days
}
}
};
app.UseStaticFiles(staticFileOptions);
From docs: OnPrepareResponse is called after the status code and headers have been set, but before the body has been written
Is there a way to intercept the request before it got serve
Yes. You can write your own middleware and add it to IApplicationBuilder before you call UseStaticFiles. See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware#ordering
See also https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing. You may also be able to solve this problem by writing routes instead of middleware.