.NET MVC5 Attribute Routing Optional Prefix - asp.net

Trying to implement an optional routing prefix and running into some issues. Here is my route definition:
[RoutePrefix("{tenant:range(10,12)?}")]
[Route("{action=Index}")]
public class HomeController : Controller {
Routes are:
{tenant}/Index
{tenant}/Search
Loading the site with a tenant works fine, such as:
https://localhost:44300/10/
Using #Url.Action("Search", "Home") generates a correct link to the Search Action.
Without tenant, the site loads:
https://localhost:44300/
But I am unable to load the "non-default" action such as "Search", returns a 404. Also, the Url Helper generates a link such as: https://search
The range condition is temporary. I will have to further develop a custom constraint to actually verify the value.

Related

Asp.Net MVC custom routing interrupt default routing

My routes are not working don't know why. When I try attribute routing it works for for that action but breaks default routing for other controller or actions. I only want to change routing for an index action method of a controller CMS I want it like [Route("{countrycode}/{id}")]. but when I do this default route breaks for other index action methods of other controllers.
For example: When I use [Route("{countrycode}/{id}")] on cms controller's index action then route breaks for Home and other controllers index action methods so I have to call the index methods explicitly like /Home/Index instead of /Home otherwise it throw an error. Thanks in advance.

.Net Core Web API Post route endpoint not being hit

I have the following .Net Core API route defined.
[HttpPost("/addproduct")]
[Consumes("application/json")]
public ActionResult<IEnumerable<ProductDTO>> AddProduct([FromBody] ProductDTO){}
I already have the following attributes defined on the class:
[EnableCors()]
[Produces("application/json")]
[Route("api/[controller]")]
I am calling it like this: https://localhost:xxxxx/api/products/addproduct and I'm passing a payload to it that represents the productDTO. Why does this route not get hit?
The issue is with the routing attribute used on the HttpPost.
As defined above, the AddProduct action method matches the following url:
https://localhost:xxxx/addproduct
Even though you're using token replacement for the controller name,by using a leading slash you're overriding that route on the AddProduct method.
To properly route to the method remove the leading slash like this:
[HttpPost("addproduct")]
[Consumes("application/json")]
public ActionResult<IEnumerable<ProductDTO>> AddProduct([FromBody] ProductDTO productDto)
For more information regarding attribute routing or controller routing in general read this page on Microsoft Docs

Html.BeginForm in WebApi - routing

I have a Web API project as part of my solution (also containing an MVC4 project) and within the Api project I am trying to post a form to the Values controller Post method (from a view also within the Api project).
Using Html.BeginForm() or Html.BeginForm("Post", "Values") posts to /Values/Post but I need it to go to /api/Values/Post
Any idea which overload or settings I need to post to the correct location?
I can hit all the action methods fine from fiddler (e.g. localhost/api/values).
You would need to use BeginRouteForm as link generation to Web API routes always depends on the route name. Also make sure to supply the route value called httproute as below.
#using (Html.BeginRouteForm("DefaultApi", new { controller="Values", httproute="true" }))
The API controller uses a different route to the default. It's supposed to be consumed from JS (AJAX) rather than a real form post so there's no obvious support for it in HtmlHelpers. Try:
Html.BeginForm("values", "api")
This would trick it into thinking "values" is the action and "api" is the controller. "Post" is inferred from the http method.

Html.RouteLink to a Web API Route - possible?

My site is largely a suite of web services exposed via the Asp.Net Web API. There are also pages, designed to support the webservices (testing etc), written in Razor (and implicitly Asp.Net MVC 4).
For the XML versions of the webservices I have a schema-export action (uses the XsdDataContractExporter) which is picked up by my standard API route (although note - I've flipped the precedence of the Web API and Pages):
//page routes
routes.MapRoute(
"Default", // Route name
"pages/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home",
action = "Index",
id = UrlParameter.Optional
} // Parameter defaults
);
//an additional route for my Schema controller action
routes.MapHttpRoute("XSD", "schema.xsd",
new { controller = "schema" });
//API Catch-all Route
routes.MapHttpRoute("APIMain", "{controller}/{id}",
new { id = RouteParameter.Optional });
Now on a razor page I want to emit a link to the 'friendly' schema URL ~/Schema.xsd. Anticipating issues with route discovery I immediately went for hitting the route directly by name:
#Html.RouteLink("Schema", "XSD");
However this just emits a link equivalent to ~/.
I've tried some other combinations of route values - but it appears MVC's HtmlHelper and UrlHelper simply don't want to pick up Web API routes.
I'm sure if I cracked open the source of Asp.Net MVC 4 I'd find the reason - but I'm hoping somebody already knows, and since I can't find another SO about such cross-linking I figured it'd be a good addition to the SO library.
I should add that browsing to ~/Schema and ~/Schema.xsd do correctly display the XML schema produced by the API action.
Update
Post-RC a method was added to MVC's UrlHelper, HttpRouteUrl, which does exactly the same thing I suggest here in this answer. This is my discussion thread over on CodePlex where I was told this. So there is no need for you to use the magic string mention here in generating links to Web API routes.
Original answer
I've managed to get it to work - although it might not by the time MVC 4 is RTMd (disclaimer disclaimer!)
I changed my Html.RouteLink call as follows:
#Html.RouteLink("XML request schema", "XSD", new { httproute = true })
I didn't originally intend to answer my own question straight away - but having done some research I found an answer.
First I verified that the HtmlHelper's route collection is the same as the RouteTable.Routes collection (i.e. contained all routes).
Following the call-chain through, I remembered having trawled through the current Web API and page MVC 4 source code from CodePlex, that HttpRoutes (in System.Web.Http.Routing) need a 'hidden' route value to be added otherwise they will never match. Here's the source code from lines 21-25 of HttpRoute class (correct as of 8th June 2012 source):
/// <summary>
/// Key used to signify that a route URL generation request should include HTTP routes (e.g. Web API).
/// If this key is not specified then no HTTP routes will match.
/// </summary>
internal const string HttpRouteKey = "httproute";
A bit of further analysis of the code showed that it expects this route value to be a boolean.
Clearly, this is something that can be turned into extension methods - perhaps Html.HttpRouteLink (and Html.HttpActionLink) - with extra extensions on UrlHelper for hiding the magic string for the route data value.

Returning Requested URL within Custom Error Page in ASP.net

Working in ASP.net 3.5 and MVC 1.0.
What I would like to do is return the requested URL, which generates a 404 error, within the custom error page. Much like Google does on their error pages (http://www.google.com/test).
eg.
We're sorry, but the requested address "http://www.domain.com/nonexistantpage.aspx" does not exist on this server.
What would be the best way to accomplish this kind of soft 404?
Also, as a side note: Anyone familiar with returning the custom error page in place of the ugly ...notfound?aspxerrorpath=/awdawd nonsense, while keeping the requested URL in a browser's address bar? ...I suspect something to do with a server.transfer?
Check out these resources related to this topic:
ASP.Net MVC Custom Error Pages
Three common ASP.NET MVC URL routing issues
To summarize, you can accomplish a google-like implementation with keeping the requested URL by defining a catch-all route that executes a particular controller action.
//defined below all other routes
routes.MapRoute(
"Catch All",
"{*path}",
new { controller = "Error", action = "NotFound" }
);
public ActionResult NotFound(string path)
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
ViewData["path"] = path; //or Request.Url.ToString() if you want full url
return View();
}
This is not a complete solution, though. Assuming you've left the default route mapping, anything that matches {Controller}/{action}/{id} is still going to a throw a traditional 404 or custom error. You'd have to explicitly define all possible routes if you truly wanted to have the catch-all route pick up anything that didn't map to a specific controller/action or parameter type - not necessarily a trivial task.

Resources