I have a set of APIs in an ASP.NET Core (.NET6) project that are exposed both internally (private) and through an API gateway. When served privately, API urls are of the form service.internal/api/v1/resource which is achieved with a RouteAttribute on the ApiController:
[ApiController]
[Route("api/v{version:apiVersion}/[controller]")]
public class ResourceController : ControllerBase
{
// actions
}
When accessed via our api gateway, however, the /api/ component of the url is absent, ie. gateway.com/v1/resource. The gateway performs a transformation on the Url which adds in the extra path segment for the internal/proxied request.
This all works "fine" except in a few circumstances. The primary issue I'm having is with link/url generation for requests coming through the gateway. Location headers added by CreatedAt and link headers generated with IUrlHelper include the /api/ segment of the route with the gateways hostname rendering them invalid. I also have some issues with swagger but I believe they should resolve themselves if I can solve this.
Question: Is there a way to make the route template dynamic based on the host name (which would not be a compile time constant, ie. from config)? For example for requests coming from gateway.com, the route template would be v{version:apiVersion}/[controller] and otherwise would be api/v{version:apiVersion}/[controller]?
It doesn't need to be attribute driven if there's a different way. But my understanding is that the ApiControllerAttribute makes attribute routing required and I wouldn't want to lose the other benefits of that.
If I can get this to work, I'd be able to update the gateway and not have it add the /api/ segment to the proxied urls and it should remove any issues with swagger since the proper paths would be detected by the api explorer.
Unfortunately I have no idea where to start looking. I reviewed some of the routing docs but I didn't see anything that would do the job. I admit I'm out of my league here with minimal aspnetcore experience.
If it matters we are using endpoint routing:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Related
Trying to provide more info and not sure how much is relevant.
One of our webapi is deployed to IIS : abcdomain.com/xyzweb. We started upgrading our env to .net 7 from .net 5. Web api also uses ServiceStack 6.4.
One of the route defined in the c# Webapi, ServiceStack plugin is "/api". Until recently requests to endpoint abcdomain.com/xyzweb/api was fine. But now (.net 7 upgrade?) we noticed that the calls to endpoint does not reach the (http get/post method) handler. We have a small middleware defined in startup.cs configure method and see the execution flow through the middleware code when the abcdomain.com/xyzweb/api request is made and the middleware ends by calling next() and after which execution flow lost (webapi is still live).
After much trials, something I read but could not put my fingers on the content, went ahead and changed the route definition to "/apihello" instead of "/api" and then the requests started working as before.
Any pointers what made it break or what made it work?
Searching is difficult with "api", brings only irrelevant results.
I would like to add that before changing /api to /apihello, the http request would return HTTP status 200 (though it did not go to the handler) and Raw response "Error: System.NotImplementedException: The operation '' does not exist for this service".
You can disable (or change) ServiceStack's JSON /api pre-defined route with:
ConfigurePlugin<PredefinedRoutesFeature>(feature => feature.JsonApiRoute = null);
I have been trying to Implement Authorization in my Server Side Blazor application, currently it seems to be working but the Authorization is limited to the .razor pages and components. Try as I might I cant seem to get the [Authorize] Microsoft.AspNetCore.Authorization attributes to work in my underlying services.
Currently the only means of enforcing this is to read the claims directly from the HttpContextAccessor.HttpContext.User witch can be injected into the underlying services. I can also call the RevalidatingIdentityAuthenticationStateProvider.
I have the following setup correctly Registered in my Startup.cs`
RevalidatingIdentityAuthenticationStateProvider<TUser>
app.UseAuthentication();
app.UseAuthorization();
along with a CascadingAuthenticationState and AuthorizeRouteView in the App.razor
These are functioning and do indeed authorize and restricts access were needed. My biggest issue is that I originally planned on driving the Navigation with the "Front End" Authorization but restrict actions in the services themselves.
As a quick side note, I spun up a new Template with Individual User Account Authentication, it also seems to ignore any [Authorize] tags placed in the WeatherForecastService.cs
[Authorize]
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
** Boiler Plate Code **
}
Any suggestions in overcoming this issue, I also suspect I may be barking up the wrong tree as this is all server side and thus there is no real need to Authorize the underlying services.
What I want to achieve
Mapping my normal domain e.g. example.com to no area if possible.
Mapping my subdomain e.g. blog.example.com to a area named blog.
What I have found
There are actually quite a lot of posts regarding to this topic, especially mapping subdomains to areas.
From SO:
area-and-subdomain-routing
asp-net-core-mapping-subdomains-to-areas
Others:
danylkoweb.com
benjii.me
web.archive.org
And there are probably even more.
Problem
But there is one big problem, in ASP.Net Core 3 they changed a lot of things, one of them being the routing in general, see mircosoft's devblog. Basically they changed it so everything should now be endpoints.
All the classes e.g. MvcRouteHandler and interfaces e.g. IRouter are basically obsolete now, at least from my understanding. After a while googling around and diggin' in the GitHub repositories I couldn't find anything useful.
Additional information
I am using SDK 3.0.100-preview6-012264, but trying to upgrade to
SDK 3.0.100-preview7-012821 as soon as possible.
I am using a reserve proxy (nginx) which passes the request to the ASP.Net Core Server.
You said all requests pass on nginx but nothing said about nginx redirection, did you try to use nginx to do that, just redirect the sub-domain to domain using /etc/nginx/nginx.conf.
server {
server_name sub.domain.co;
location / {
return 301 $scheme://domain.co/BlogSite$request_uri;
}
}
(BlogSite is your area routing on ASP.Net Core Server.)
To give an update to this whole situation, with the release of .Net Core 3 you can now make use of the RequireHost method.
This would look something like the following:
app.UseEndpoints(endpoints =>
{
endpoints.MapAreaControllerRoute(
name: "Home",
areaName: "Home",
pattern: "{controller=Home}/{action=Index}")
.RequireHost("localhost:5001", "sub.domain.com");
}
If you remove the Area in the pattern parameter, like in the example, you can achieve exactly that. It is still somewhat hacky, but a lot cleaner.
Note, that you would have to put a RequireHost on all of the endpoints in order to get proper default route matching.
I have Swagger setup for an ASP.NET Core 2 MVC API application. I'm using OpenIddict for OAuth but want to customize how the request and responses appear on the documentation.
Since the method in the controller takes an OpenIdConnectRequest, the generated default output looks like so:
... and it just goes on and on.
This is a far cry from the neat JSON required for a client to consume since the middleware does a bunch of work inbetween the client and the controller method.
How do I change how Swagger represents these? I am already using a hack to massage the responses via a custom, private type for token responses, so any help on how to use that would also be appreciated. I have tried to use the SwaggerGenOptions.MapType<> function as the documentation claims that tells Swagger how to map a type to a custom output. Unfortunately, I've not gotten the Swagger output to reflect anything I've done with .MapType<>.
To be clear, these aren't models I control so I can't decorate the members myself.
Note that this is different from How to show WebApi OAuth token endpoint in Swagger. My controller action is discovered fine. Unfortunately, I'm thinking it may be easier to filter it out and use that as another work around to define it manually but I'd rather not if possible.
new to c sharp, visual studio and web api. (come from java).
Anyways I'm playing around with web api from visual studio. In the ValuesControler class I notice it set something call a attribute on top of the class, so whenever a browser make a request to api/values it will need to be authorized first.
But what exactly is an attribute?
[Authorize]
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
I also found the routing attributes, but I cant find any info on what exactly is attributes and how is it getting read or understood by the program.
In c# Attributes provide a powerful method of associating declarative information with C# code (types, methods, properties, and so forth). Once associated with a program entity, the attribute can be queried at run time and used in any number of ways.
For authorize attribute check out
Authentication and Authorization in ASP.NET Web API
Using the [Authorize] Attribute
Web API provides a built-in authorization filter, AuthorizeAttribute.
This filter checks whether the user is authenticated. If not, it
returns HTTP status code 401 (Unauthorized), without invoking the
action.
For attribute routing check out
Attribute Routing in ASP.NET Web API 2
Routing is how Web API matches a URI to an action. Web API 2 supports
a new type of routing, called attribute routing. As the name implies,
attribute routing uses attributes to define routes. Attribute routing
gives you more control over the URIs in your web API. For example, you
can easily create URIs that describe hierarchies of resources.