Route Aliases in ASP.NET Web API 2 - c#

I have a Web API that allows users to access/manipulate resources that "belong" to other users. It contains many routes similar to this:
/users/{userId}/resource
I'd like a corresponding set of routes that do the same on behalf of the currently authenticated user:
/resource
Ideally I'd like to get the second set of routes working without doubling the number of actions in my controllers, but I'm struggling to find the right hook. Ideally, I'd like to add a MessageHandler (or something) that intercepts each request, checks if it matches a route, and if it doesn't, prepends "users/" + ID of the authenticated user to the route and checks again. What is the best way to accomplish this?
One constraint: I'm using attribute routing to implement the first set of routes and would ideally like to pull this off without sacraficing that.

The hook is the action selector, as you can see here: Routing and Action Selection in ASP.NET Web API.
You can implement your own action selector to achieve what you want. Here is a sample on how to do that: Magical Web API action selector. From the same page:
We will create a class that implements IActionSelector, as that would allow us to plug into the hook provided by the Web API under GlobalConfiguration.Configuration.Services.

Related

Modify route of incoming request in Web API using ASP Net Core

I am working on a Web API project using Asp Net Core 2.1.
My existing Web API has the following Get method (and numerous other methods like these):
[HttpGet("GetEmployeByName/{Name}")]
public Employee GetEmployeeByName(string name)
{... some code...}
This responds to the following incoming request:
http://localhost:8080/Employee/GetEmployeeByName/{Name}
Now my requirement is such that some of the APIs could be called by passing an additional id such as:
http://localhost:8080/Employee/{Id}/GetEmployeeByName/{Name}.
I still need to map it to the original method without changing the route.
This can be done using ASP Net Core's feature of URL Rewrite and the URL can be re-written without the id.
However what i want to do is to capture the {Id} as well and save it to Session\ Context.
Does anyone know how to extract the id and rewrite the URL.
Maybe you can find what you need here optional parameters web api, you would need to add that parameter at the end as optional parameters always go at the end, also you could try to use both versions of the end point encapsulate the logic and reuse it on both versions.

How can I validate a URL before the request gets to the controller

Our service uses ASP.NET Core and in the application pipeline, we have several middlewares which are configured in StartUp.cs Configure(IApplicationBuilder app) method.
The middlewares are added by this method:
app.UseMiddleware<Type>();
I would like to validate the HttpContext.Request.Path and make sure it can hit one of the controllers. How can I get the list of available routes (controller path) in the middleware code or is there even a simpler way to see if this certain request path will hit one of the registered controller? We used xxxxcontroller : ControllerBase and a [Route("controller/{version}/{id}] attribute to register the controller.
Thanks a lot.
I suggest you to take a look at Asp.net core identity, If I understood what you`re looking for, you need to use roles to guarantee access to certain routes.
I don't know how to get a list of all routes and check that the path is for a valid route but you can use middleware to check the response status code after MVC runs and if the status code is a 404 then you know it wasn't a valid route and you can handle it accordingly.
The UseStatusCodePagesWithReExecute extension method basically uses this approach to handle not only 404 errors but all error status codes.

How to inject a route parameter into _Layout.cshtml

I am trying to create a multitenant web app using ASP.Net Core v1.1.0. A single user may belong to multiple tenants (ie - an area manager who oversees multiple stores.) A user should also be able to go to the site and see some basic marketing views without logging in or having access rights to any tenant, but the functionality would be greatly limited.
Structurally, my project has not evolved much from the default ASP.Net Core MVC template so far...
In Startup.cs, I have defined my routes as follows to attempt to use subdomains to define which store the user is attempting to log into. "DEMO" would indicate that the user should only see the marketing views:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{tenant=DEMO}/{controller=Home}/{action=Index}/{id?}");
});
Since I have done that, the variable tenant can be magically used in a controller action definition like this, and it works fine:
public IActionResult Contact(string tenant)
{
ViewData["Message"] = "Your contact page for " + tenant + ".";
return View();
}
But I use _Layout.cshtml as a wrapper that contains most of the site navigation and some personalized elements, and I would like to do things like disable most of the navigation for the DEMO tenant and display a store-specific logo for all other tenants. Since to the best of my knowledge there is no controller associated with _Layout.cshtml, I need a different way of injecting this string. I have tried adding the following line to _ViewImports.cshtml:
#inject System.String tenant
and I get the error InvalidOperationException: No service for type 'System.String' has been registered. This leads me to believe that I need to add something to the ConfigureServices method in Startup.cs, but I don't know what I'm doing and have not been able to find any similar code samples online. I am visualizing something like this:
services.AddScoped<ITenantFactory, MySeeminglyUnnecessaryFactory>();
but even then, I don't know how to get the tenant route parameter to the factory, or how to go about implementing that. If I can just find a canned method of passing in the string, I'm sure I can work with that to do what I need to do as far as changing the look and feel of the layout, and I feel pretty comfortable restricting user access at the controller level. Thanks in advance for any advice or ideas!
You can use the View Context:
Hello user of #(ViewContext.RouteData.Values["tenant"])!
source:
https://github.com/aspnet/Mvc/blob/19331f95326b18bd6f0400526074da934bf65cf0/test/WebSites/RazorPagesWebSite/HelloWorldWithRoute.cshtml
https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.Razor/RazorPageBase.cs

Getting an external webapi url given a list of routes it uses

I have a WebAPI (v1) app that I'm creating. It has various custom routes, that all work fine.
I have a client application I'm creating (which is MVC+webapi itself), which calls the webapi app using HttpClient. Currently I've hard-coded the urls to call, but I'd like to calculate them automatically based on a list of routes (which I could put in a shared library).
So, in my shared library I would have a list of a class that contains Name, RouteTemplate and Defaults, which in my webapi I'd iterate through that list to create my routes and in the client application i'd somehow use to calculate the url to get HttpClient to call.
How do I calculate the url to call an external webapi app from a client app (that could itself have its own routing)?
So since I know what you want, I give it a try
So I assume you have a routes table for your api which has the colums: route, controller, action, verb. An example row could be:
/foo/bar/{id}, fooController, barAction, GET
In the client app you have access to that data so you can compose an url of that when you know which controller and action to call with which verb. The combination of controller, action and verb is unique in mvc.
So you filter on fooController , barAction and verb GET and you get the route. You replace {id} with your id parameter and you have an url.

Routing with a non optional parameter (not MVC)

The site I'm building needs to have a users username as part of the url like:
mydomain/user1
I have set this up in global.asa as:
routes.MapPageRoute("SubscriptionList","{Username}/","~/subscriptionlist.aspx");
However if there are links on the site to pages that arent routed, for example, mydomain/login.aspx these get routed to the 'SubscriptionList' page. I presume that this is because the required URL '{Username}/' can actually be nothing. How do I set routing up so that the above only gets triggered when the Username actually exists?
The alternative, which I'm sure isnt best practice, is to set up a route for each page on the site.
I think this has to do with the order of your routes in your routing table.
From what I understand, you should make sure that this route is below others that have explicit routing set.
For instance, this should be below the route than handles the routing to Login.aspx as I think that rules are evaluated from top to bottom.
Or do I not understand the question=

Categories