ASP MCV: Index action with optional string parameter - c#

I would like to have an Index action with an optional string parameter. I'm unable to make it work.
I need the following routes:
http://mysite/download
http://mysite/download/4.1.54.28
The first route will send a null model to the Index view, and the second one will send an string with the version number.
How can I define the route and the controller?
This is my route definition:
routes.MapRoute(
name: "Download",
url: "Download/{version}",
defaults: new { controller = "Download", action = "Index", version = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And this is the controller:
public ActionResult Index(string version)
{
return View(version);
}
Why does this not work? I'm not an expert in ASP MVC but this seems to be a very simple problem.
The error
When I go to http://mysite/downloads it works fine
When I go to http://mysite/downloads/4.5.6, the controller is correctly called, and the parameter is correctly passed. But then seems that the view is not found. This is the error I found:

string? will not work because string is not a value type.
You can set a default value to your parameter:
public ActionResult Index(string version="")
{
return View(version);
}

The issue is fixed passing the parameter to the view in the following way:
public ActionResult Index(string version)
{
return View((object)version);
}
Or
public ActionResult Index(string version)
{
return View("Index", version);
}
When you pass a string model to the view, if the model is a string parameter, it is interpreted as the view name due to the following overload method
View(String viewName)

Your Download route is conflicting with your Default route. Comment out the Download route and it will probably work.
BTW you can install RouteDebugger to figure out these kind of problems for yourself.

Your controller is looking for a view with the same name as the version attribute entered in the url (e.g. 4.1.54.28). Are you intentionally looking for a view with that name, in which case it should be in the Views/Download folder or your project. If however you simply want to pass it to the default view as a variable to be used on the page your best off sticking it in a model or you can just stick it in ViewBag if it's a one off.
Also you don't need to use:
Public ActionResult Index(string version)
You can use routedata instead e.g.
Public ActionResult Index()
{
string version = RouteData.Values["Version"].ToString();
ViewBag.version = version;
return View();
}
Hope this of some help

You are not set action name in url like {action}
you can try:
routes.MapRoute(
name: "Download",
url: "Download/{action}/{version}",
defaults: new { controller = "Download", action = "Index", version = UrlParameter.Optional }
);

I'm pretty sure it's because in the View you state it is an optional parameter, but your controller says that it is mandatory. Change the signature of your index method to expect a nullable param
public ActionResult Index(string? version)
{
return View(version);
}

Why not have two methods in your download controller:
public ActionResult Index()
{
return View();
}
[HttpGet, ActionName("Index")]
public ActionResult IndexWithVersion(string version)
{
return View(version);
}

Related

Route is redirecting to the wrong controller

I added these routes to RouteConfig.cs
routes.MapRoute(
name: "NewPositiveRelease",
url: "dispatch/{poNumber}/{article}",
defaults: new { controller = "PositiveReleaseItem", action = "Create"});
routes.MapRoute(
name: "Dispatch",
url: "dispatch",
defaults: new { Controller = "Dispatch", action = "Index"});
In the hopes that I could go to this url
locahost:3000/dispatch/4529707272/171112
To execute the Create action in PositiveReleaseItemController. However, when I navigate to that url, I am seeing the error:
A public action method '4529707272' was not found on controller 'MVCQCPage.Controllers.DispatchController'.
Can someone please help me understand why this doesn't work?
Here is the controller:
using SharedLibrary.Models;
using System.Web.Mvc;
namespace MVCQCPage.Controllers
{
public class PositiveReleaseItemController : Controller
{
// GET: PositiveReleaseItem
public ActionResult Index()
{
return View();
}
public ActionResult Create(string poNumber, string article)
{
return View();
}
public ActionResult Insert(PositiveReleaseItem item)
{
return View();
}
}
}
I tried changing the order of the given routes, but with the same outcome. Please let me know if I can add any details which might help.
Thanks
Shouldn't it be:
"PositiveReleaseItem/{poNumber}/{article}",
Instead of:
"dispatch/{poNumber}/{article}",
I was able to resolve this by simply placing my new route mappings at the top of Routeconfig.cs (above all the others).
Not sure why this worked, as none of my other route maps refer to the Dispatch controller, so its weird that it was complaining about that.

Routing for Particular Action Adds 'Home' In Front of Action

I'm having an odd issue with routing in a basic ASP/MVC project.
I have a bunch of nav items setup:
<li>Home</li>
<li>Fire</li>
<li>Law Enforcement</li>
<li>Forensics</li>
<li>Reconstruction</li>
They all work fine, except for the third one, labeled law-enforcement.
When I mouse over this item, the URL is: http://localhost:54003/home/law-enforcement
When I mouse over any other item, the URl is: http://localhost:54003/fire
My Controller setup is:
public ActionResult Index()
{
return View();
}
[Route("~/fire")]
public ActionResult Fire()
{
return View();
}
[Route("~/law-enforcement")]
public ActionResult Law()
{
return View();
}
[Route("~/forensics")]
public ActionResult Forensics()
{
return View();
}
[Route("~/reconstruction")]
public ActionResult Reconstruction()
{
return View();
}
And my route config is:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.LowercaseUrls = true;
routes.MapMvcAttributeRoutes();
routes.MapRoute("Default", "{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional}
);
}
When I go to the route the URL specifies, ASP responds with a 404 page not found (as it should). If I go to the route that I know it should be, such as localhost/law-enforcement then the correct View is rendered.
Any ideas why ASP is routing this one particular action incorrectly?
The Razor Url.Action(...) cannot refer to the route defined by the [RouteAttribute] on the controller action; instead it needs to refer to the action's name. So changing my Razor syntax to refer to #Url.Action("law", "home") instead of #Url.Action("law-enforcement", "home") solved the issue.
You can keep your url mapping in either of 2 ways as below:
One way is to decorate your actionresult with attribute as below:
// eg: /home/show-options
[Route("law-enforcement")] //Remove ~
public ActionResult Law()
{
return View();
}
As per docs
otherwise
Just add one more configuration in Route.config file
routes.MapRoute("SpecialRoute", "{controller}/{action}-{name}/{id}",
new {controller = "Home", action = "law-enforcement", id = UrlParameter.Optional}
);
Source

Direct route to custom search with MVC

I need to create a custom route with MVC to build a custom search:
Default Home's Index's Action:
public virtual ActionResult Index()
{
return View();
}
And I would like to read a string like this:
public virtual ActionResult Index(string name)
{
// call a service with the string name
return View();
}
For an URL like:
www.company.com/name
The problem is that I have this two routes but it's not working:
routes.MapRoute(
name: "Name",
url: "{name}",
defaults: new { controller = "Home", action = "Index", name = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", area = "", id = UrlParameter.Optional }
);
This way, any controller other then Home is redirected to Home, and if I switch the order, it can't find the Index Home Action.
You can use attribute routing for this. You can see the details about the package here. After installing the attribute routing package. Now a days it is installed by default for MVC5 application. Change your action method as below:
[GET("{name}")]
public virtual ActionResult Index(string name)
{
// call a service with the string name
return View();
}
Here's a catch for the code above:
The router will send the requests without the name also to this action method. To avoid that, you can change it as below:
[GET("{name}")]
public virtual ActionResult Index2(string name)
{
// call a service with the string name
return View("Index");
}

Redirect to Action by parameter mvc

I want to redirect to an action in other Controller but it doesn't work
here's my code in ProductManagerController:
[HttpPost]
public ActionResult RedirectToImages(int id)
{
return RedirectToAction("Index","ProductImageManeger", new { id=id });
}
and this in my ProductImageManagerController:
[HttpGet]
public ViewResult Index(int id)
{
return View("Index",_db.ProductImages.Where(rs=>rs.ProductId == id).ToList());
}
It redirect to ProductImageManager/Index without parameter very well(no error) but with above code i get this:
The parameters dictionary contains a null entry for
parameter 'ID' of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ViewResult Index(Int32)' in
'...Controllers.ProductImageManagerController'.
An optional parameter must be a reference type, a nullable type, or be
declared as an optional parameter. Parameter name: parameters
This error is very non-descriptive but the key here is that 'ID' is in uppercase. This indicates that the route has not been correctly set up. To let the application handle URLs with an id, you need to make sure that there's at least one route configured for it. You do this in the RouteConfig.cs located in the App_Start folder. The most common is to add the id as an optional parameter to the default route.
public static void RegisterRoutes(RouteCollection routes)
{
//adding the {id} and setting is as optional so that you do not need to use it for every action
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Now you should be able to redirect to your controller the way you have set it up.
[HttpPost]
public ActionResult RedirectToImages(int id)
{
return RedirectToAction("Index","ProductImageManager", new { id });
//if the action is in the same controller, you can omit the controller:
//RedirectToAction("Index", new { id });
}
In one or two occassions way back I ran into some issues by normal redirect and had to resort to doing it by passing a RouteValueDictionary. More information on RedirectToAction with parameter
return RedirectToAction("Index", new RouteValueDictionary(
new { controller = "ProductImageManager", action = "Index", id = id } )
);
If you get a very similar error but in lowercase 'id', this is usually because the route expects an id parameter that has not been provided (calling a route without the id /ProductImageManager/Index). See this so question for more information.
This should work!
[HttpPost]
public ActionResult RedirectToImages(int id)
{
return RedirectToAction("Index", "ProductImageManeger", new { id = id });
}
[HttpGet]
public ViewResult Index(int id)
{
return View(_db.ProductImages.Where(rs => rs.ProductId == id).ToList());
}
Notice that you don't have to pass the name of view if you are returning the same view as implemented by the action.
Your view should inherit the model as this:
#model <Your class name>
You can then access your model in view as:
#Model.<property_name>
Try this,
return RedirectToAction("ActionEventName", "Controller", new { ID = model.ID, SiteID = model.SiteID });
Here i mention you are pass multiple values or model also.
That's why here i mention that.
return RedirectToAction("ProductImageManager","Index", new { id=id });
Here is an invalid parameters order, should be an action first
AND
ensure your routing table is correct

Using the ASP.NET MVC Attribute Based Route Mapper

In my ASP.NET MVC application, I want to use this ASP.NET MVC Attribute Based Route Mapper, first announced here.
So far, I understand how to implement code that uses it, but I've run into a few questions that I think those who have used this attribute-based route mapper in the past will be able to answer.
How do I use it with ActionResults that are for HTTP POSTs? In other words, how does it work with form submissions and the like? Should I just put the URL of the GET method in, or should I use the GET method URL without any parameters (as in HTTP POST they aren't passed in through the URL)?
How do I use it with "URL querystring parameters"? Can the attribute be configured to map to a route such as /controller/action?id=value rather than /controller/action/{id}?
Thanks in advance.
How do I use it with ActionResults
that are for HTTP POSTs?
You decorate the action that you are posting to with the [HttpPost] attribute:
[Url("")]
public ActionResult Index() { return View(); }
[Url("")]
[HttpPost]
public ActionResult Index(string id) { return View(); }
If you decide to give the POST action a different name:
[Url("")]
public ActionResult Index() { return View(); }
[Url("foo")]
[HttpPost]
public ActionResult Index(string id) { return View(); }
You need to supply this name in your helper methods:
<% using (Html.BeginForm("foo", "home", new { id = "123" })) { %>
How do I use it with "URL querystring
parameters"?
Query string parameters are not part of the route definition. You can always obtain them in a controller action either as action parameter or from Request.Params.
As far as the id parameter is concerned it is configured in Application_Start, so if you want it to appear in the query string instead of being part of the route simply remove it from this route definition:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoutes();
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" }
);
}

Categories

Resources