I have those methods, using webapi:
//Responsible for getting or updating a template and it's shifts
public class AdminTemplateDefinitionController : AdminApiController
{
public HttpResponseMessage Get()
{
}
public HttpResponseMessage Get(int Id)
{
}
public HttpResponseMessage Post([FromBody]ENTemplateDefinitions EnTemplateDefinitions)//add shifts to template
{
}
public HttpResponseMessage Put([FromBody]ENTemplateDefinitions EnTemplateDefinitions) // add skills to template.
{
}
public HttpResponseMessage Delete(ENSkillInTemplate EnSkillInTemplate)// remove skiilId from template
{
}
}
For some reason I get this error:
Multiple actions were found that match the request.
My RouteConfig is:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Any idea ?
Related
I have a controller named PaymentsController in a Payments area.
it works when I request 'localhost/payments/payments/index' but I want call with 'localhost/payments/pa/index' or just 'localhost/payments'
I need both names.
I try somthing like
using System.Web.Mvc;
namespace Execplan.MVC.Areas.Payments
{
public class PaymentsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Payments";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Payments_default",
"Payments/{controller}/{action}/{id}"
);
context.MapRoute(
"Payments_pa",
"Payments/Pa/{action}/{id}"
, new { controller = "payments", action = "Index", id = UrlParameter.Optional }
);
}
} }
Using APS.NET routing, how do you conditionally route to separate actions based on whether or not the request originated as an AJAX call?
For instance on a controller I may have two actions:
public ActionResult List() { return View(); }
and
public ActionResult ListJSON() { return Content(...); }
I'd like both actions to have the same URL, but ListJSON() should get called if the request originated as an AJAX call.
Why using 2 separate actions when the code is the same? It's the view result that differs.
How about:
public ActionResult List()
{
var model = ...
if (Request.IsAjaxRequest())
{
return View(model);
}
return Json(model);
}
Obviously if you had to do this in every controller action this would quickly become a complete nightmare.
So you could externalize this logic into a custom action filter:
[MyFilter]
public ActionResult List()
{
var model = ...
return View(model);
}
where you could define the MyFilterAttribute like so:
public class MyFilterAttribute: ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var result = filterContext.Result as ViewResultBase;
if (result != null)
{
filterContext.Result = new JsonResult
{
Data = result.Model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
}
You could also register this action filter as a global action filter to avoid the need of putting it on each controller and action that requires it.
UPDATE:
As explained in the comments section it seems that the OP requires 2 different actions. For this purpose you could use a custom route:
public class MyRoute : Route
{
public MyRoute(string url, object defaults) :
base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
{
return null;
}
if (httpContext.Request.IsAjaxRequest())
{
rd.Values["action"] = rd.GetRequiredString("action") + "json";
}
return rd;
}
}
which will be registered in Application_Start:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(
"Default",
new MyRoute(
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
)
);
}
It turns out that you can easily define your own route constraints by implementing IRouteConstraint.
Something like this:
public class AjaxRouteConstraint : IRouteConstraint {
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
return httpContext.Request.IsAjaxRequest();
}
}
Then simply use this constraint on a route. The trick is that the route with this constraint must come before the route without the constraint, otherwise the ajax route will never be called (the not-ajax route will always match).
There may be some consequences to doing this when it comes to URL generation. But I have not significantly tested those.
What do I do if I want a url like below (which is not defined by me, so I can't change it):
http://localhost/Something?cmd=Open&a=1&b=2
Maps to MyController.Open() action?
public class MyController : Controller
{
public ActionResult Open(int a, int b)
{
//.....
}
public ActionResult Close(string c)
{
//.....
}
}
Note: there are more than one possible cmd values, each mapped to an action of the same controller.
You could write a custom route:
public class MyRoute : Route
{
public MyRoute()
: base(
"something",
// TODO: replace the name of the controller with the actual
// controller containing the Open and Close actions
// What you have shown in your question is not an MVC controller.
// In ASP.NET MVC controllers must derive from the Controller class
new RouteValueDictionary(new { controller = "home" }),
new MvcRouteHandler()
)
{ }
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
{
return null;
}
var cmd = httpContext.Request.QueryString["cmd"];
if (!string.IsNullOrEmpty(cmd))
{
rd.Values["action"] = cmd;
return rd;
}
return null;
}
}
and then register this custom route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// register the custom route before the default route,
// to ensure that it handles requests to /something
routes.Add("something", new MyRoute());
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I have some area in my ASP.NET MVC3 Application:
namespace MyProject.Areas.myarea
{
public class myareaAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "myarea";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"myarea_default",
"myarea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
}
this area contains "Hello" controller with "Smile" action.
In global.asax file for whole project I have:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
So, when I request "localhost/myarea/hello/smile" it calls appropriate controller as expected.
BUT! When I request "localhost/hello/smile" it calls hello controller STILL! With that, it looks for the Views not in the myarea/Views folder, but in a ~/Views folder for "root" (non-area) level of project.
How can I fix this, so server will throw an 404 exception, that resource is not found, just like I requested non-existing controller?
UPD: Controllers in area are in namespace:
namespace MyProject.Areas.myarea.Controllers
{
public class HelloController : Controller
...
}
Controllers in "root"-level are in namespace:
namespace MyProject.Controllers
{
public class AnotherRootController : Controller
...
}
So I tried this in global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new [] { "MyProject.Controllers" } //Namespace
);
}
I thought this would restrict this route to "root"-level controllers only, since they are in MyProject.Controllers namespace. That DID NOT work. Area-controllers are still being called with request without areaname in it.
May be someone can explain, why?
You could set the UseNamespaceFallback=false datatoken when registering the default route in your Global.asax by restricting it to look only for controllers in the given namespace. You may take a look at the following blog post.
So to put that into action add a namespace restriction to your area registration:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"myarea_default",
"myarea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "MyProject.Areas.myarea.Controllers" }
);
}
and in your Global.asax set the UseNamespaceFallback data token to false when registering the default route in order to constrain it to the given namespace:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "MyProject.Controllers" }
).DataTokens["UseNamespaceFallback"] = false;
}
I didnt think this would be a problem originally, but as I keep getting exceptions thought I would post here incase im being an idiot...
I have 2 module classes, one sets up NHibernate and one sets up MVC Controllers, now the problem I have is that I have something like below:
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionManager>().To<SessionManager>();
}
}
public class ControllerModule : NinjectModule
{
public override void Load()
{
Bind<SomeController>().ToSelf()
.WithConstructorArgument("sessionManager", Kernel.Get<ISessionManager>());
}
}
Whenever I try to use the controller, it just bombs out telling me that its having problems binding the sessionManager argument. I make sure the list has the Nhibernate module in before the Controller module when I create the kernel.
Is there anything immediately stupid in what im doing above?
Assuming:
public class SomeController : Controller
{
private readonly ISessionManager _sessionManager;
public HomeController(ISessionManager sessionManager)
{
_sessionManager = sessionManager;
}
public ActionResult Index()
{
return View();
}
}
The following should be sufficient:
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionManager>().To<SessionManager>();
}
}
public class ControllerModule : NinjectModule
{
public override void Load()
{
Bind<SomeController>().ToSelf();
}
}
and in Global.asax:
public class MvcApplication : NinjectHttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
protected override void OnApplicationStarted()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var modules = new INinjectModule[]
{
new NHibernateModule(),
new ControllerModule()
};
return new StandardKernel(modules);
}
}