I have a website developed in MVC 5, I'm using route attributes for routing.
I've set the default controller and the default action for each controller using the following code
public class CompanyController : MainController
{
[Route("~/", Name = "default")]
[Route("Company/Index")]
public ActionResult Index(string filter = null)
{
//My code here
}
[Route("Company/Edit")]
public ActionResult Edit(int id)
{
//My code here
}
}
I've another controller with a default action :
[RoutePrefix("Analyst")]
[Route("{action=Index}")]
public class AnalystController : MainController
{
[Route("Analyst/Index")]
public ActionResult Index(string filter = null)
{
//My code here
}
[Route("Analyst/Edit")]
public ActionResult Edit(int id)
{
//My code here
}
}
The default controller worked perfectly, but when I navigate to the analyst controller without specifying the name of the action I get the following error:
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:
SurveyWebsite.Controllers.AnalystController
SurveyWebsite.Controllers.CompanyController
How can I correct navigate to http://localhost:61534/analyst and reach the default action ( index) ? The action also should remain accessible by http://localhost:61534/analyst/Index
Thanks for your help.
Give an empty string as the route value for index action so that it works for Analyst, which is your controller route prefix. You can decorate with a second Route attribute for it to work with "Analyst/Index" url where you will pass "Index" to it.
[RoutePrefix("Analyst")]
public class AnalystController : MainController
{
[Route("")]
[Route("Index")]
public ActionResult Index(string filter = null)
{
//My code here
}
[Route("Edit/{id}")]
public ActionResult Edit(int id)
{
//My code here
}
}
This will work for both /Analyst and /Analyst/Index
Related
Is it possible to have 2 ActionResult DeleteConfirmed in 1 controller?
I have 2 different views that I want to delete.
Thanks,
EB
[HttpPost, ActionName("DeleteLink")]
public ActionResult DeleteConfirmed(int id)
{
Link link = db.Links.Find(id);
db.Links.Remove(link);
db.SaveChanges();
return RedirectToAction("OutOfBank");
}
It seems that you want to overload DeleteConfirmed action. You can use the attribute if you want your code to do overloading.
[ActionName("MyOverloadedName")]
But, you'll have to use a different action name for the same http method.
So it's just semantics at that point. Would you rather have the name in your code or your attribute?
Code Example:
public class HomeController : Controller
{
public ActionResult GetEmpName()
{
return Content("This is the test Message");
}
[ActionName("GetEmpWithCode")]
public ActionResult GetEmpName(string EmpCode)
{
return Content("This is the test Messagewith Overloaded");
}
}
Phil has an article related to this: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx
I have a controller named HomeController, I am re-writing its all actions and even the name of controller,by decorating them with Route and Routeprefix respectively.
This is my controller with action method Index
[RoutePrefix("MyPortal")]
public class HomeController : Controller
{
[Route("Home")]
public ActionResult Index()
{
}
[Route("Index")]
public ActionResult LandingPage()
{
}
}
Its working fine,but when I type Home/Index in URL,its giving me error
A public action method 'index' was not found on controller 'Web.Controllers.HomeController'. /Home/index
I want to redirect the user to Index ActionResult,if he type Home/Index or MyPortal/Home
Similarly, he should redirect to LandingPage, if he type Home/LandingPage or MyPortal/Index.
MyPortal/Home or MyPortal/Index is working fine.
How about this one ..? But your last case (MyPortal/Index) will not work
[RoutePrefix("Home")]
[RoutePrefix("MyPortal")]
public class HomeController : Controller
{
[Route("Index")]
[Route("Home")]
public ActionResult Index()
{
}
[Route("LandingPage")]
public ActionResult LandingPage()
{
}
}
I have a partialview called search. I want to put this partial view in many view.
The target is to take the search string input from the search controller and send it to the parent controller where the search view is used.
In this way I want to make the search partial view generic so that I can re-use it.
SearchController:
[HttpPost]
public ActionResult Index(string searchString)
{
var controller = RouteData.Values.First().Value.ToString(); // this gives me "Search", which i dont want.
//here i want to take the parent controller name and redirect to that controller
return RedirectToAction("action", "controller", new { searchString = searchString });
}
can anyone help me to find the parent controller name ??
Instead of having a SearchController, you can make a base class for your controllers and write code that will be shared between them. It makes sense if your feature is needed in multiple controllers.
Let's say your have a base class for your controllers :
public class BaseController : Controller
{
[HttpPost]
public ActionResult Search(string searchString)
{
// ... some process
return RedirectToAction("SomeAction", new { searchString = searchString });
}
public virtual ActionResult SomeAction(string searchString)
{
// ... some other process
}
}
Then your specific controller :
public class MyController : BaseController
{
public override ActionResult SomeAction(string searchString)
{
// ... again some process
}
// .. some other actions
}
Your partialview "Search" will target current controller instead of "SearchController" (by not specifying controller name in your view), so your RedirectToAction will also redirect to an action of that controller, without having to get his name (that's why there's no controller name in the code snipper above).
Instead of having a virtual method, you can also pass a string variable as the action name, if you need to name it differently according to current controller (it can become another parameter, along the searchString parameter) :
public class BaseController : Controller
{
[HttpPost]
public ActionResult Search(string searchString, string targetAction)
{
// ... some process
return RedirectToAction(targetAction, new { searchString = searchString });
}
}
If you don't want to go with a base class, you can always get current controller name in your view, before triggering your search feature :
#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()
In your controller, it becomes :
[HttpPost]
public ActionResult Search(string searchString, string controllerName)
{
// ... some process
return RedirectToAction("action", controllerName, new { searchString = searchString });
}
But going for a base class is a good way to make this kind of feature generic and reusable.
I have this set of routes:
routes.MapRoute(
"IssueType",
"issue/{type}",
new { controller = "Issue", action = "Index" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Here is the controller class:
public class IssueController : Controller
{
public ActionResult Index()
{
// todo: redirect to concrete type
return View();
}
public ActionResult Index(string type)
{
return View();
}
}
why, when i request http://host/issue i get The current request for action 'Index' on controller type 'IssueController' is ambiguous between the following action methods:
I expect that first one method should act when there is no parameters, and second one when some parameter specified.
where did i made mistake?
UPD: possible duplicate: Can you overload controller methods in ASP.NET MVC?
UPD 2: due to the link above - there is no any legal way to make action overloading, is it?
UPD 3: Action methods cannot be overloaded based on parameters (c) http://msdn.microsoft.com/en-us/library/system.web.mvc.controller%28VS.100%29.aspx
I would have one Index method that looks for a valid type variable
public class IssueController : Controller
{
public ActionResult Index(string type)
{
if(string.isNullOrEmpty(type)){
return View("viewWithOutType");}
else{
return View("viewWithType");}
}
}
EDIT:
How about creating a custom attribute that looks for a specific request value as in this post StackOverflow
[RequireRequestValue("someInt")]
public ActionResult MyMethod(int someInt) { /* ... */ }
[RequireRequestValue("someString")]
public ActionResult MyMethod(string someString) { /* ... */ }
public class RequireRequestValueAttribute : ActionMethodSelectorAttribute {
public RequireRequestValueAttribute(string valueName) {
ValueName = valueName;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
return (controllerContext.HttpContext.Request[ValueName] != null);
}
public string ValueName { get; private set; }
}
I ran into a similar situation where I wanted my "Index" action to handle the rendering if I had an ID specified or not. The solution I came upon was to make the ID parameter to the Index method optional.
For example, I originally tried having both:
public ViewResult Index()
{
//...
}
// AND
public ViewResult Index(int entryId)
{
//...
}
and I just combined them and changed it to:
public ViewResult Index(int entryId = 0)
{
//...
}
You can do it using an ActionFilterAttribute that checks the parameters using reflection (I tried it) but it's a bad idea. Each distinct action should have its own name.
Why not just call your two methods "Index" and "Single", say, and live with the limitation on naming?
Unlike methods that are bound at compile time based on matching signatures, a missing route value at the end is treated like a null.
If you want the [hack] ActionFilterAttribute that matches parameters let me know and I'll post a link to it, but like I said, it's a bad idea.
All you have to do is mark your second Action with [HttpPost]. For instance:
public class IssueController : Controller
{
public ActionResult Index()
{
// todo: redirect to concrete type
return View();
}
[HttpPost]
public ActionResult Index(string type)
{
return View();
}
}
In my mvc application, i'm having a controller where many actions are their.
I'm having a property for the controller class.
In index controller i'm setting the value for the property ,
will it able to get same value in another action..
public class HomeController : BaseController
{
int sample =0;
public ActionResult Index(int query)
{
this.sample = test;
}
public ActionResult Result()
{
this.sample -------- can this 'll give the value of wat i get in index action.
}
}
Since the controller will be created and destroyed with each web request, you can't store data in private variables across web requests, which is a good thing because, different users will be making different requests, so you need to use caching.
Try this:
public class HomeController : BaseController
{
public ActionResult Index(int query)
{
ControllerContext.HttpContext.Session["query"] = query;
}
public ActionResult Result()
{
int query = (int)ControllerContext.HttpContext.Session["query"];
}
}