This controller:
public class TestController <T> : Controller
{
public string Index()
{
return "123";
}
}
This definition of the routes:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new
{
controller = "Test<T>",
action = "Index",
id = ""
});
This is the error I get:
The IControllerFactory 'Yad2.Web.Mvc.UI.Infrastructure.NinjectControllerFactory' did not return a controller for the name 'Test'.
public class TestController <T> : Controller
{
public string Index( )
{
return "123";
}
}
List of things wrong here:
Controllers cannot be generic abstract classes, you need to define T.
All actions need to return ActionResult derived objects.
"Test" in your route definition is absolutely incorrect. Never going to work.
You never showed your Ninject registration.
Related
I am creating a project in C# MVC and was using actions. Due to the requirements, now I am using Route to hide the controller name and display just the page name.
route config
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Law",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Law", action = "Home", id = UrlParameter.Optional }
);
controller 1 (to access this : http://localhost:17920/dashboard) and (http://localhost:17920/alert)
public class LawController : Controller
{
[Route("dashboard")]
[ActionName("Home")]
public ActionResult Home()
{
return View();
}
[Route("alert")]
[ActionName("alert-list")]
public ActionResult AlertList()
{
return View();
}
controller 2 (to access this : http://localhost:17920/list)
public class ListController : Controller
{
[Route("list")]
[ActionName("list-of-return")]
public ActionResult listOfReturn()
{
return View();
}
What I am trying is when I enter this http://localhost:17920 as a default URL, then http://localhost:17920/dashboard should be displayed by default.
Thanks.
You need to define RoutePrefix over the Controller like below. Also update your Route("dashboard") to Route("Home") because that is your default action name on route configuration.
[RoutePrefix("Law")]
public class LawController : Controller
{
[Route("Home")]
[ActionName("Home")]
public ActionResult Home()
{
return View();
}
// Other action methods
}
Please also refer https://devblogs.microsoft.com/aspnet/attribute-routing-in-asp-net-mvc-5/ for more details.
Edit As per edit in your question it is more clear what you want. From your existing code you just need to add one more Route over LawController's Home action as below, so it could match http://localhost:17920/ & http://localhost:17920/dashboard to that action method.
public class LawController : Controller
{
[Route("")]
[Route("dashboard")]
[ActionName("Home")]
public ActionResult Home()
{
return View();
}
[Route("alert")]
[ActionName("alert-list")]
public ActionResult AlertList()
{
return View();
}
I know how to send data to controller's action method as parameter from URL. Here I wonder how can I send data from URL to controller's field?
public MyAwesomeController : Controller {
public string SectionCode { get;set; }
}
and let's define Routes :
routes.MapRoute(
name : "AwesomeRouter",
url : "{code}/{action}",
defaults: new {controller = "MyAwesome", action = "Index", /* What to do here?*/}
);
I want SectionCode be filled with the {code} from URL. Is it possible to implement?
Yes it is, you can create inherited class from basic Controller class and override OnActionExecuting method where you can read url, route or any form data and store them in session or directly fill any field you need. Then create an inherited class of your controller.
public class MyAwesomeController : MyControllerBase
{
public ActionResult Index()
{
//this.SectionCode is available populated here
return View();
}
}
public class MyControllerBase : Controller
{
public string SectionCode
{
get;
private set;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
this.SectionCode = filterContext.RequestContext.RouteData.Values["code"].ToString();
base.OnActionExecuting(filterContext);
}
}
Each time you hit any action in this controller using route definition you provided, field will be automatically populated. But when you will have more than one route defined they it could get easily into conflicts eg. when code will match to any controller name. Normal website should not work this way.
Your route should look like this:
routes.MapRoute(
name: "AwesomeRouter",
url: "{code}/{action}",
defaults: new { controller = "MyAwesome", action = "Index" }
);
The code should then be passed on to the action as a parameter. I am storing it in the view bag for explanation purposes:
public class MyAwesomeController : Controller
{
public ActionResult Index(string code)
{
ViewBag.Code = code;
return View();
}
}
Using this URL then:
http://somehost/4567/Index
If you access the Viewbag property in your view:
#ViewBag.Code
You should see:
4567
Currently I'm trying to implement some sub-controller mechanism. I've the following structure:
/Controller/Admin/UserController.cs
/Views/Admin/User/Index.cshtml
I'm registering the route like this:
routes.MapRoute(
name: "Admin",
url: "Admin/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
My controller looks like this:
public class UserController : Controller
{
// GET: Administration
public ActionResult Index()
{
return View("~/Views/Admin/User/Index.cshtml"); // <---
}
}
My problem is, that this only works when I return the exact view. When
I pass no View, the automatic resolving of the path does not work. For example this does not work:
public class UserController : Controller
{
// GET: Administration
public ActionResult Index()
{
return View(); // <--- Not working
}
}
Why does this is not working with sub-controller?
Thanks a lot!
I defined two controller with same controller name in different namespaces. And got an exception. How to uer parameter "dataTokens" to define namespace of controller like mvc-4?
Exception below:
AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:
Alice.Controllers.TestController.Index
Alice.Controllers.Api.TestController.Index
Microsoft.AspNet.Mvc.Infrastructure.DefaultActionSelector.SelectAsync(RouteContext context)
Controllers/Api/TestController.cs :
namespace Alice.Controllers.Api
{
//[Route("api/[controller]")]
public class TestController : Controller
{
//[Route("[action]")]
public string Index()
{
return "this is controller at Alice.Controllers.Api"; ;
}
}
}
Controllers/TestController.cs :
namespace Alice.Controllers
{
//[Route("[controller]")]
public class TestController : Controller
{
//[Route("[action]")]
public string Index()
{
return "this is controller at Alice.Controllers";
}
}
}
Startup.cs
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}",
defaults: null,
constraints: null,
dataTokens: new { Namespaces = new[] { "Alice.Controllers" } });
routes.MapRoute(
name: "api",
template: "api/{controller}/{action}",
defaults: null,
constraints: null,
dataTokens: new { Namespaces = new[] { "Alice.Controllers.Api" } });
});
If more details need please ask.
Unfortunately by default you cannot have duplicate controller names in ASPNET MVC Areas (or between an Area and the root of the application). Fortunately, the fix for this is pretty simple, and the exception describes the step you need to take. Once you’ve added an Area, you will have two different places (by default) where routes are defined: one in your root application and one in your area registration. You will want to adjust both of them to specify a namespace parameter.
more details check here
Namespaces are not an MVC feature. Controllers are simply classes. If you need two controllers that are basically the same, then derive them from a common class and put them in whatever namespace you want.
startUp.cs
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areaRoute",
template: "{area:exists:regex(^(?!Main$).)}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}",
defaults: new { area = "Main"});
});
Areas:Main// area default : localhost/home/index
namespace Exzen.Areas.Main.Controllers
{
[Area("Main")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
Areas:Test// area plus: localhost/test/home/index
namespace Exzen.Areas.Test.Controllers
{
[Area("Test")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
iam having controller like below which is not registered in routes table
public class InternalController : Controller
{
/*this controller is not registered in routes table*/
public ActionResult Foo()
{
return Content("Text from foo");
}
}
From another controller which is registered in Routes table i want to call/redirect action of previous controller, one which is not registered in routes table.
public class AjaxController : Controller
{
/*this controller is registered in routes table*/
public ActionResult Foo()
{
/*FROM HERE HOW DO I RETURN CONTENTS OF
controller=InternalController, action = Foo
*/
/*
i tried below piece of code but that doesnt seem to work
*/
return RedirectToAction("Foo", "InternalController ");
}
}
Defined Routes (only one item added)
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Ajax","ajax/{action}",new {
controller="Ajax",
action="Index"
});
}
If you are choosing not to register a route... then you probably have the file/controller in a specific location that will not change.
In that event, just use the "Redirect" method, instead of "RedirectToAction".
For example:
return Redirect("~/Internal/Foo");
Now that you have shown your routes definition, it is obvious that you can never invoke any other controller than AjaxController. You simply forbid them in your routes, so InternalController could never be served. You will have to change your route definition.
Depending on what you want to achieve and how you want your urls to look like you have a couple of possibilities:
Leave the default route
Modify your existing route definition like so:
routes.MapRoute(
"Ajax",
"{controller}/{action}",
new { controller = "Ajax", action = "Index" }
);
You can create RedirectController for redirecting more Url and pages:
public class RedirectController : Controller
{
public ActionResult Index()
{
var rd = this.RouteData.Values;
string controller = rd["controller2"] as string;
string action = rd["action2"] as string;
rd.Remove("controller2");
rd.Remove("action2");
rd.Remove("controller");
rd.Remove("action");
return RedirectToActionPermanent(action, controller, rd);
}
}
And then you can define redirect from old url in routing tables:
routes.MapRoute(
null, // Name
"ajax/foo",
new { controller = "Redirect",
action = "Index",
controller2 = "InternalController",
action2 = "Foo"}
);
This pattern is also useful if you redirect old url to new one. For example:
routes.MapRoute(
null, // Name
"default.aspx", // redirect from old ASP.NET
new { controller = "Redirect",
action = "Index",
controller2 = "Home",
action2 = "Index" }
);