Route attribute hides actions - asp.net-mvc

Why Route attribute hides|applied to other methods?
[HttpGet]
[Route("Issues/ReportIssue")]
public ActionResult ReportIssue()
Action without Route attribute stops working
[HttpPost]
public ActionResult ReportIssue(IssueModel viewModel)
jQuery returns "Not found" error
If rename Post action or add Route attribute, all works. Is there are any priority rules for a Route attribute?

I tried following code sample -
[HttpGet]
[Route("Products/Create")]
public ActionResult Create()
{
ProductCategory category = new ProductCategory();
category.ProductCategoryId = 1;
return View(category);
}
[HttpPost]
public ActionResult Create(ProductCategory category)
{
return View(category);
}
And I could see this working properly without any issues. The controller name in my case is "Product", and the below code works if I specify route attribute as "Products/Create" (different from controller name), or "Product/Create". So not sure, why you would be facing the issue.
The Get and Post actions should work without route attribute as well, as they were working. Attribute routing is something newly added in MVC 5, and is there to give more control over the routes. But still, this is not mandatory to use. The traditional routes should work fine.
Take a look of - http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx article.

Related

In MVC5, how can I use a "folder" as parameter for Index?

In MVC5, how can I use a "folder" as parameter for Index?
I have this controller method:
public class HookController : Controller
{
[HttpGet]
[Route("hook/{pattern}")]
public ActionResult Index(string pattern)
{
}
}
I can currently call it like this: /hook/?pattern=testpattern
..but I'd like pattern to be populated when I call /hook/testpattern as a folder/path.
I thought I could do it with [Route("hook/{pattern}")] but that has no effect and I just get 404 not found.
Fixed it. MVC Routing Attributes weren't enabled as I was missing this line:
routes.MapMvcAttributeRoutes();
This goes in RegisterRoutes() (RouteConfig.cs) before the default route.

ASP.NET MVC Routing with Model Parameter

I have an action method in a controller that I'm calling via Ajax. The specification is:
[HttpPost]
public ActionResult SomeFunction(FormCollection form)
This works fine without any special routing configuration.
However, if I try to use a model as the parameter instead of the FormCollection, thus:
[HttpPost]
public ActionResult SomeFunction(SomeModel model)
I get a 500 error because the function can't be found.
What do I need to put in the RouteConfig to get this to work?
I would recommend using Help plugin: http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/creating-api-help-pages
When using POST I would specify signature as such:
#region POST
[Route("")]
public IHttpActionResult Post([FromBody]Contact newContact)

MVC Route conflict seems strange

I am using MVC 5.1 with AutoFac.
I dont understand why the below route from each controller conflict with this URL: https://localhost:44300/Home/login
I thought it would map to the first method. I get this error though:
Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
The request has found the following matching controller types:
AllThings.WebUI.Controllers.AccountController
AllThings.WebUI.Controllers.PostController
public class AccountController : Controller
{
//
// GET: /Account/Login
[Route("~/{site}/Login")]
[Route("~/Account/Login")]
[Route("~/{country:maxlength(2)}/{site}/Login")]
[Route("~/{country:maxlength(2)}/Account/Login")]
[AllowAnonymous]
public ActionResult Login(string returnUrl, string country, string site)
{
return View();
}
}
public class PostController : Controller
{
[Route("~/{site}/{CategoryUrl?}")]
[Route("~/{country:maxlength(2)}/{site}/{CategoryUrl?}", Name = "ResultList")]
[AllowAnonymous]
public ActionResult List(string country, string site, SearchCriteriaViewModel searchCriteriaViewModel)
{
return View("List", searchCriteriaViewModel);
}
}
The main problem is that you have 3 possible routes that can match /Home/Login.
[Route("~/{site}/Login")]
[Route("~/Account/Login")]
[Route("~/{site}/{CategoryUrl?}")]
Liberal use of placeholders, especially that is all you have in a URL template definition is not a good thing. You should use literals in the URL or if you use placeholders, there should be constraints on them so they don't conflict.
Note that the following routs conflict as well:
[Route("~/{country:maxlength(2)}/{site}/Login")]
[Route("~/{country:maxlength(2)}/Account/Login")]
[Route("~/{country:maxlength(2)}/{site}/{CategoryUrl?}", Name = "ResultList")]
Any one of them could match UK/Account/Login.
Additionally, using a tilde (~) is to override a route prefix (see the MSDN documentation). If your controller doesn't define one, you should just start with the first segment or placeholder.

Why mvc attribute routing on HttpGet action also effect HttpPost without a routing attribute, is it a bug?

I have two actions, one for HttpGet with this signature:
[Route("NewsLetter/SelectEmail/{page?}")]
[HttpGet]
public ActionResult SelectEmail(int? page, string priCat, string secCat)
{
...
}
And one for HttpPost with this signature:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectEmail(int id)
{
...
}
After setting the aforementioned route for HttpGet method, I've noticed that the other method with HttpPost has stopped working, after digging around I've realized that the route for HttpGet also set itself for HttpPost, and it didn't work until I explicitly set a routing attribute for it:
[Route("NewsLetter/SelectEmail/{id}")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectEmail(int id)
{
...
}
I wanted to know, is it a bug?, if it's not, is there anyway to set a routing attribute for a [HttpGet] without also effecting the corresponding [HttpPost]?
You can't using POST and GET at the same time, because your Action will accept requests with any HTTP methods.
Try use AcceptVerbsAttribute to restrict HTTP methods in your RouteTable.
https://msdn.microsoft.com/en-us/library/system.web.mvc.acceptverbsattribute(v=vs.118).aspx

Get and post methods with different names

I am using ASP.NET MVC 3.
I have an action method called New. When form validation succeeds then I want Create to handle the request.
public ActionResult New()
{
// Code
}
[HttpPost]
public ActionResult Create()
{
// Code
}
I have 2 questions regarding this. Firstly, how do I modify my Html.BeginForm to handle the above? I tried the following but I get an error, it is looking for the physical file Create (News is my controller name):
#using (Html.BeginForm("Create", "News"))
{
<!-- Code -->
}
Secondly, how do I prevent a user from typing in /News/Create in the URL. Create should handle only my post requests coming from New.
UPDATE:
I managed to get something working. The original URL looks like this:
http://localhost:33947/News/New
After I click the submit button and validation fails then the URL looks like:
http://localhost:33947/News/Create
Why does it do this? I want it to stay:
http://localhost:33947/News/New
Here is my action method code:
public ActionResult New()
{
return View();
}
[HttpPost]
public ActionResult Create(NewsViewModel newsViewModel)
{
if (!ModelState.IsValid)
{
return View("New", newsViewModel);
}
return View("Index");
}
#using (Html.BeginForm("Create", "News", FormMethod.Post))
You cannot prevent user from typing address manually, but you can add another Create action marked with [HttpGet] attribute which will show user the error page. Anyway, your current Create action method will not handle such requests. Probably user will get standard File not found error in this case.
UPDATE: Html.BeginForm("Create", "News") means to submit the form to action "Create" of the controller "News", so it works as it should. If you want to submit to /News/New, replace it with Html.BeginForm("New", "News").
Regarding your second question, instead of:
if (!ModelState.IsValid)
{
return View("New", newsViewModel);
}
you should use :
if (!ModelState.IsValid)
{
return RedirectToAction("new");
}
Now this has the undesired side affect that your Modelstate is lost. (no validation errors are shown in your form.
To fix this add the ModelStateToTempData attribute to both your new and create action.
This attribute come as part of http://mvccontrib.codeplex.com/ .

Resources