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.
Related
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();
});
I am pretty new to the C# and ASP.NET and now I am trying to understand what does the Endpoint in ASP.NET mean, or what is the essence of this concept, thank you!
Example:
app.UseMvc(route =>
{
route.MapRoute(name:"default", template:"{controller=Home}/{action=index}/{id?}");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
What are the differences when using this two method?
In your context an endpoint is a URL that causes a netcore server to do something (run some code) when a browser connects to the server, quotes the url as part of a http request and possibly includes a body or other parameter data
Per the comments, UseMvc/UseSignalR on 2.2 were effectively replaced by a single UseEndpoints in 3.0. The netcore migration guide discusses the differences in depth and makes recommendations on how to switch from UseMvc to UseEndpoints
Per my comment, I strongly recommend you shouldn't seek to establish a totally different dev environment to what your course teaches via/is expecting to see submissions of assignments in, just because you have a Mac and can't/won't make it the same environment the institution uses. Handing in an app that uses 3.0 to a tutor marking it on a machine that uses 2.2 may well get you fewer points because it doesn't compile
I am currently trying to use Swagger UI to interact with my OData enabled Web API.
Versions for the bits and bobs are as follows:
.Net 4.5.2,
Web API 2.2,
NuGet package Microsoft.AspNet.OData 6.0.0 for OData 4.0 endpoints,
Swashbuckle 5.3.2,
Swashbuckle.Core 5.3.2,
Swashbuckle.OData 3.0.0.
My application has a SwaggerConfig.cs and a WebApiConfig.cs as expected. And I have followed many of the instructions in this article, this article and a few others on the web.
When I launch my API through Visual Studio, I initially get a new browser tab with the local host URL. If I append the word "/swagger" (no quotes) at the end of that URL, I get a nice Swagger UI in the same tab. This tab shows the name of of my API but not much else. I don't see any of the individual URL interfaces for the Actions exposed by my ODataController derived Controller. Moreover, underneath the displayed name of the URL, all I have is [ base url: , api version: v1 ] where "v1" is coming in from SwaggerConfig.cs (same with the API name).
I know I can talk to the API from Swagger UI because I can arrive at the "Get" action of the Controller by modifying the displayed URL appropriately. The actions created were the standard Get, Put, Post, Patch, Delete ones. But I cannot see any of these in the Swagger UI.
This is because I am new to this and obviously have missed out or miscoded stuff to link everything correctly. I have made very little change to SwaggerConfig.cs and left most of the things as they were when it was created. The significant change I have made was adding this line:
c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, GlobalConfiguration.Configuration));
Based on this info, if anyone can guide me in the direction of what pieces could be missing or developed incorrectly, I would greatly appreciate it. If you had any further questions for me, I would be happy to respond in the comments.
It turns out that because I had been recreating the application, Entity Framework was no longer creating the database for me since it was trying to use a name it had already recently used (a known EF bug). So I refractored the name of the database to something else. After this, things were plain sailing.
This negates my comment: "I know I can talk to the API from Swagger UI because I can arrive at the "Get" action of the Controller by modifying the displayed URL appropriately. The actions created were the standard Get, Put, Post, Patch, Delete ones. But I cannot see any of these in the Swagger UI."
Clearly this was me not understanding the issue clearly. But by going through the steps again one by one, I was able to find the problem and come to the desired place :)
In Startup.cs I want to configure 2 middlewares:
An app.Use (or app.Map with app.Use) which handles websocket requests, but requires a specific dynamic route endpoint.
app.UseMvc() with attribute routing.
How the router can be created and reused in MVC in such situation?
PS. Here is my related question where I am looking at the same problem from a different perspective: Opening a websocket channel inside MVC controller
I had similar issue and after checking the sources I found that the UseMvc method creates its own instance of RouteBuilder and IRouter. This means that you have no control over the route creation while using UseMvc.
So I can suggest creating an alternative to UseMvc that will create two routes mapped to different handlers, one to Mvc and the second to Websocket. Though I haven't tested it yet, hope it helps.
Ok I had a huge Issue giving this a proper title, my excuses for that.
Anyways I have started slowly to look at Web and ASP.NET again, I am a C# developer but I have mostly worked with Windows applications the past 5 years or so, It is not that I haven't touched the web as such in that time, but this is as web services (Restfull as well as the ugly SOAP services) I have also worked with more "raw" web requests.
But I have not worked with IIS or ASP.NET in all that time.
What I would like to do is hos a web page that uses a URL style I could best describe with "like rest", hence the "Restfull urls" title. Because I think most people thinks of such URL's in terms of:
http://example.com/item/
http://example.com/item/23/
and so forth. Not that they have to look like that, however I would like to use such URL's instead of
http://example.com/item?id=23
I know subtext does this, but i have not had any luck finding it in their code base.
Now as far as I can tell I could just implement some IHttpHandler's, but at least for the examples I have seen of that, they write the page source back in code, and I still have master pages etc. I wish to use instead of taking over all that stuff my self, I really just kinda wants to route http://example.com/item/23/ to http://example.com/item and asking for the item with id 23...
I hope this makes sense at all >.<... And that someone has some better examples at hand that what I have been able to find.
You can achieve this using Routing here is a link to an MSDN blog, The .Net Endpoint - Using Routes to Compose WCF WebHttp Services that should get you started.
If you're looking at asp.net/IIS, another option to look at is ASP.Net MVC. It's pretty straight forward to create RESTful services.
Here's a tutorial:
http://www.codeproject.com/Articles/233572/Build-truly-RESTful-API-and-website-using-same-ASP
So here are your options-
For .net 3.5 sp1 framework with IIS7 you can use asp.net routing feature to have MVC style urls that you mentioned should create a custom route handler implementing IRouteHandler interface as explained here How to: Use Routing with Web Forms and register your route rules in Application_Start method in Global.asax. For your example you can register a route like this
routes.Add("ItemRoute", new Route
(
"item/{itemId}",
new CustomRouteHandler("~/item.aspx")
));
and then you can access itemId in your routed item.aspx page by checking request context item
requestContext.HttpContext.Items["itemId"]
For .net framework 4 MVC you dont have to create a custom handler, you can directly use
routes.MapPageRoute("ItemRoute", "item/{itemId}", "~/item.aspx");
in you global.asax Application_Start method.
This link explains more about the Routing
A way of achieve this is using URL rewriting.
If you're planning to host your Web application in Internet Information Services 7.x, you can take advantage of IIS URL Rewriting Module:
http://www.iis.net/download/urlrewrite
URL rewriting is just mapping a friendly URL to an unfriendly, common one, which is programming-friendly to inspect GET parameters.
For example:
http://yourdomain.com/item/48 => http://yourdomain.com/Items.aspx?Id=48