I'm trying to understand how the route config works in the MVC 5.
I have the following structure for my application:
BaseCRUDController
public class BaseCRUDController<TEntity, TEntityViewModel> : Controller
where TEntity : class
where TEntityViewModel : class
{
private readonly IBaseService<TEntity> baseService;
public BaseCRUDController(IBaseService<TEntity> service)
{
this.baseService = service;
}
[HttpGet]
public virtual ActionResult Index()
{
IList<TEntityViewModel> entities = baseService.FindFirst(10).To<IList<TEntityViewModel>>();
return View(entities);
}
}
CountriesController
[RouteArea("management")]
[RoutePrefix("countries")]
public class CountriesController : BaseCRUDController<Country, CountryViewModel>
{
private readonly ICountryService service;
public CountriesController(ICountryService service)
: base(service)
{
this.service = service;
}
}
What I'm trying to do is simple: http://myapplication.com/management/countries.
I have many others controllers that the superclass is the base controller. I'm doing this way to avoid code repetition, since that the controllers have similar structure.
The problems are:
I can't reach the url that I want (/management/countries)
I don't know how to configure my Home Controller, because I want that it could be reached by http://myapplication.com
How could I fix these problems?
My route config is like that:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
After a little playing around I managed to get it to work.
The problem is when you are using attribute routing there are no default route parameters assigned.
For example in your Default route the defaults are controller = "Home", action = "Index". So if you were to call http://myapplication.com/ the routing engine will automatically default to /Home/Index/ and so on.
However the attribute route has no way of knowing you want to default to the Index action (or any other action for that matter).
To solve the issue add the Route attribute to the CountriesController like this:
[RouteArea("management")]
[RoutePrefix("countries")]
[Route("{action=Index}")] // this defines the default action as Index
public class CountriesController : BaseCRUDController<Country, CountryViewModel>
{
private readonly ICountryService service;
public CountriesController(ICountryService service)
: base(service)
{
this.service = service;
}
}
Also for future reference Phil Haack's Route Debugger is extremely helpful for figuring out routing issues.
Have you defined Area (management) for your controllers?
if you try without Area, is that getting redirect properly?
Related
My controller:
public class AjaxController : Controller
{
private readonly IGenerationUnitMobileService _generationUnitMobileService;
public AjaxController(IGenerationUnitMobileService generationUnitMobileService)
{
_generationUnitMobileService = generationUnitMobileService;
}
public IActionResult MobileExistToAnotherGenerationUnit(String mobile, long generation_unit_id)
{
//ViewBag.Result = _generationUnitMobileService.MobileExistToAnotherGenerationUnit(mobile,generationUnitId);
return View();
}
}
And My view file is very simple:
#model PgcgSms.WebSite.Models.GenerationUnitMobileViewModel
#{
Layout = "~/Views/Shared/_Ajax.cshtml";
}
#ViewBag.Result
This is so much straight forward. But when I browse at: http://localhost:57216/Ajax/MobileExistToAnotherGenerationUnit/01719393045/1
I am getting the following error message:
This localhost page can’t be found
No webpage was found for the web address: http://localhost:57216/Ajax/MobileExistToAnotherGenerationUnit/01719393045/1
Search Google for localhost 57216 Ajax Mobile Exist To Another Generation Unit 01719393045
HTTP ERROR 404
I checked the view file and spellings several times. Whats wrong with my code?
In the RouteConfig.cs file you will have to specify the default route.
For Example:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "AjaxController", action = "MobileExistToAnotherGenerationUnit", id = UrlParameter.Optional }
);
}
}
I've created a new ASP.NET MVC 5 project in Visual Studio 2015 Update 3, and everything is pretty standard. I have this controller:
public class UsersController : BaseController
{
[HttpGet]
public async Task<ActionResult> Newest()
{
var newestUsers = await Database.Users.OrderByDescending(u => u.ID).Take(100).ToListAsync();
return View(newestUsers);
}
[HttpGet]
[Route("{id}")]
public async Task<ActionResult> GetUser(long id)
{
var user = await Database.Users.FindAsync(id);
return View(user);
}
}
My BaseController derives from regular MVC Controller and it contains some common properties for my app. Nothing special.
When I go to /users/newest the appropriate page loads, but when I go to /users/1 I immediately get a 404 not found error. I've tried changing the route to ~/{id} but no avail. My route configuration is the standard, auto-generated one, I haven't touched it:
public class RouteConfig
{
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 }
);
}
}
Why am not hitting the GetUser action?
UPDATE: For some reason, it started not working again. I didn't do anything. It was working after I've added routes.MapMvcAttributeRoutes();, it's still there but I started getting 404 again.
Okay I have no idea how it went away (or why it wasn't there) but I was missing the routes.MapMvcAttributeRoutes(); method in route configuration. Adding that method fixed the issue.
UPDATE: I've also needed to add RoutePrefix to get the routes working, and I have to explicitly add the correct route for any actions that have arguments. It's a pity that MVC can't map them by themselves.
Get ride of your additional Id routing above getuser - this isn't needed.
Your route is incorrect - it should be users/getuser/1
i am currently trying to generate this url "/Cloud/Hosting/RoaringPenguin/Manage/Exclusions".
Here is the area registration
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Hosting_default",
"Cloud/Hosting/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
here is the controller
public class RoaringPenguinController : PortalControllerBase
{
public ActionResult Exclusions()
{
return View("Exclusions");
}
}
i have tried added a route onto the action itself like so
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
I have also tried adding some attributes to the controller itself
[RouteArea("Hosting")]
[RoutePrefix("RoaringPenguin")]
public class RoaringPenguinController : PortalControllerBase
but that doesn't seem to work either. If i leave all the attributes off then the final url i get is "/Cloud/Hosting/RoaringPenguin/Exclusions".
Does anyone know how i can get the "Manage" in the url as well?
Just to confirm i have the following set in my RegisterRoutes method under the RouteConfig class
routes.MapMvcAttributeRoutes();
Any help is appreciated. Thanks
Your default area route doesn't allow for the "Manage/Exclusions" part on the end. If you made the URL just /Cloud/Hosting/RoaringPenguin/Exclusions (minus the Manage part of the path) it would work fine.
If you need the route to be exactly that, then attribute routing is your best bet. However, your mentioned attempts at that are all missing something or another. Your controller should be decorated with both RouteArea and RoutePrefix to compose the first part of the path:
[RouteArea("Hosting", AreaPrefix = "Cloud/Hosting")]
[RoutePrefix("RoaringPenguin")]
public class RoaringPenguinController : Controller
However, it's typical to actually implement a base controller when dealing with areas, so that you can specify RouteArea in just one place:
[RouteArea("Hosting", AreaPrefix = "Cloud/Hosting")]
public class HostingBaseController : Controller
[RoutePrefix("RoaringPenguin")]
public class RoaringPenguinController : HostingBaseController
Then, on your action:
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
As you had.
Try with this code
[RouteArea("AreaName", AreaPrefix = "Cloud/Hosting")]
[RoutePrefix("RoaringPenguin")]
public class SampleController : Controller
{
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
{
return View("Exclusions");
}
}
or
[RoutePrefix("Cloud/Hosting/RoaringPenguin")]
public class RoaringPenguinController : PortalControllerBase
{
[Route("Manage/Exclusions")]
public ActionResult Exclusions()
{
return View("Exclusions");
}
}
This will be the first line
routes.MapMvcAttributeRoutes();
After that only you have to write this line
AreaRegistration.RegistrationAllAreas();
Is it possible to customize ASP.NET Web API's routing mechanism to route all requests to the API to one controller method?
If a request comes in to
www.mysite.com/api/products/
or
www.mysite.com/api/otherResource/7
All would be routed to my SuperDuperController's Get() method?
I ran into a case where I needed to do this. (Web API 2)
I first looked into creating custom IHttpControllerSelector and IHttpActionSelectors. However, that was a bit of a murky way around. So I finally settled on this dead simple implementation. All you have to do is setup a wildcard route. Example:
public class SuperDuperController : ApiController
{
[Route("api/{*url}")]
public HttpResponseMessage Get()
{
// url information
Request.RequestUri
// route values, including "url"
Request.GetRouteData().Values
}
}
Any GET request that starts with "api/" will get routed to the above method. That includes the above mentioned URLs in your question. You will have to dig out information from the Request or context objects yourself since this circumvents automatic route value and model parsing.
The good thing about this is you can still use other controllers as well (as long as their routes don't start with "api/").
I don't konw why you would want to do this and I certainly wouldn't recommend routing everything through one controller, however you could achieve this as follows. Assuming you are only ever going to have a resource with an optional id in your calls, add this to your WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{resource}/{id}",
defaults: new { controller = "SuperDuper", id = RouteParameter.Optional }
);
}
}
Then define your controller method as follows:
public class SuperDuperController : ApiController
{
public IHttpActionResult Get(string resource, int? id = null)
{
return Ok();
}
}
You would need to decide on an appropriate IHttpActionResult to return for each different type of resource.
Alternatively using Attribute Routing, ensure that config.MapHttpAttributeRoutes() is present in your WebApiConfig and add the following attributes to your controller method:
[RoutePrefix("api")]
public class SuperDuperController : ApiController
{
[Route("{resource}/{id?}")]
public IHttpActionResult Get(string resource, int? id = null)
{
return Ok();
}
}
I have a controller defined in a library. I'd like this controller to be accessible via any of my 3 areas. At the moment, the controller (let's say "contact") is not being found when accessed via for example the "admin" area (i.e. url of /admin/contact). It does however work when accessed via "/contact".
Is there any route configuration required to Areas in order to allow the access of a common controller though these areas?
Thanks.
You could put this controller in a namespace:
namespace MvcApplication1.Controllers.MyAreas
{
public class ContactsController : Controller
{
...
}
}
and then in your area registration specify this namespace:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "SomeLibrary.Controllers.MyAreas" }
);
}
Now when you navigate to /admin/contacts/index the Index action of the ContactsController will be executed.