Filter for static file middleware - asp.net-core

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.

Related

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

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.

Check if request is made to Razor Page

How can I check within middleware code if current request is made to Razor Page not to any other resource (static file, or API)?
All my APIs are located within api folder, so if (!context.Request.Path.StartsWithSegments("/api")) {} filters out APIs, but that will not work for static content as these files and libraries are placed within number of folders what results in number of URL segments.
Could not find any relevant property in context.
First step - place the middleware after app.UseRouting(). Any request for a static file will never reach your middleware because the static files middleware will short circuit the request. Also, after this point, the routing middleware will have selected the endpoint and populated the endpoint metadata. Then you can test the endpoint metadata collection to see if it includes PageRouteMetaData, which tells you that this is a Razor page route:
app.Use((context, next) => {
var endpoint = context.GetEndpoint();
if (endpoint != null)
{
foreach(var md in endpoint.Metadata)
{
if( md is PageRouteMetadata)
{
// this is a page route
}
}
}
return next(context);
});

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

catch all file extension controller action together with static files

I have a set of files in the wwwroot folder. With webpack I generate js bundles with js.map files. I want to put security on the *.map files to only allow certain people to have access to it.
The documentation of ASP.NET core static files concludes that all files in wwwroot have no security. If security is needed advice is given to make an MVC controller and to put security on the action method.
I want to have the static files in wwwroot with one catch all *.js.map URLs which performs security and gives a notfound. How do I define this action method.
I don't want to put the map files in a different folder and to serve them differently.
Define a route like this with a catchAll template and a constraint:
app.UseMvc(routes =>
{
// https://haacked.com/archive/2008/07/14/make-routing-ignore-requests-for-a-file-extension.aspx/
routes.MapRoute(
name: "MapFiles",
template: "{*relativeFileUrl}",
defaults: new { controller = "FileSystem", action = "AccessDevFile" },
constraints: new { relativeFileUrl = #".*\.js.map" }
);
});
The action method looks like this. If no access allowed we just return NotFound()
public IActionResult AccessDevFile(string relativeFileUrl)
{
bool hasAccess = ... do your check ...
if(hasAccess)
{
return base.PhysicalFile(_hostingEnvironment.WebRootPath + "\\" + relativeFileUrl.Replace("/", #"\"), "application/json");
}
return NotFound();
}
Also make sure to have the UseMvc call before the UserStaticFiles call otherwise the action method can never be reached.