I'll try to describe my problem as simple as I can. I have several controllers which are loaded dynamically at runtime. Those controllers hosts several web apis for different partners. What I want to achieve is to have a prefix in URL before accessing the controller. In other words, I have Partner1 and Partner2. Both of them has some controllers, for example
Partner1: Service1Controller, Service2Controller2.
Partner2: Api1Controller, Api2Controller etc.
Now I want to achieve the following. I want partner1's controllers to be accessible only with Partner1 prefix in the url, for example http://somehost.com/Partner1/Service1, but I don't want Api1Controller to be accessible from http://somehost.com/Partner1/Api1, but instead it should be accessible from http://somehost.com/Partner2/Api1.
Is there any way to achieve my goal?
Thanks
An inelegant solution could be to use 2 separate route mappings:
routes.MapRoute(
"partner1",
"partner1/{controller}/{action}",
new { contoller = Service1Controller, action = "Index" },
new { contoller = #"(Service1Controller)|(Service2Controller)"}
);
routes.MapRoute(
"partner2",
"partner2/{controller}/{action}",
new { controller = Api1Controller, action = "Index" },
new { contoller = #"(Api1Controller)|(Api2Controller)"}
);
Teh 4th parameter of MapRoute defines constraints as regular expressions
You could create a custom ActionFilter that looks at the Request and User and determines if the route is valid. If it's not, then you can return some ActionResult that either redirects or returns an error to the user.
Related
I have very simple question. My site, based on ASP.NET MVC, can have many urls, but all of them should bring to the one controller. How to do that?
I suppose I need some magic in Global.asax but I don't know how to create route that will redirect any url to the specific controller.
For example I have url /about, /product/id etc. but all of them should be really bring to the content/show where the parts of url will be recognized and the decision what information to show will be make. It's some like CMS when you cannot define routes in advance. Is this information enough?
Thanks
This sounds like a horrible idea, but, well, if you must;
routes.MapRoute(
"ReallyBadIdea",
"{*url}",
new { controller = "MyFatController", action = "MySingleAction" }
);
This routes everything to a single action in a single controller. There's also {*path} and other URL patterns should you want slightly more flexibility.
Ideally you should try and specific with your routes, for example if you have a URL that is /products/42 and you want it to go to a generic controller you should specify it explicitly like
routes.MapRoute(
"Poducts",
"products/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
then you would specify another route for something else like /customers/42
routes.MapRoute(
"Customers",
"customers/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
this may seem a little verbose, and creating a single route might seem cleaner, but the issue a single route is you will never get a 404 and will have to handle such things in code.
the default routing works fine
mysite.com/home/about
and i even see how to customize it to make it shorter
so i can say:
mysite.com/edit/1
instead of
mysite.com/home/edit/1
but how can i make it longer to handle url like the following
mysite.com/admin/user/1 // works
mysite.com/admin/user/details // does not work
mysite.com/admin/question/create // does not work
i cant just treat the id as an action? i need a custom route?
do i need to create new controllers for each table or can i route them all through the Admin controller
thanks a lot
As has been mentioned already, probably your best bet would be to use the new Areas feature
You can achieve this type of routing without Areas, but as the number of controllers gets large the maintainability of your site will diminish. Essentially what you do is to hard-code the controller name into the Route definition which means that you have to add new route mappings for each new Admin controller. Here's a few examples of how you might want to set up your routes without Areas.
routes.MapRoute("AdminQuestions", // Route name
"admin/question/{action}/{id}", // URL with parameters
new { controller = "AdminQuestion", action = "Index" } // Parameter defaults
);
routes.MapRoute("AdminUsers", // Route name
"admin/user/{action}/{id}", // URL with parameters
new { controller = "AdminUser", action = "Index" } // Parameter defaults
);
Alternatively you could route everything through the Admin controller, but it would quickly become very messy with your controller actions performing multiple roles.
routes.MapRoute("Admin", // Route name
"admin/{action}/{type}/{id}", // URL with parameters
new { controller = "Admin", action = "Index" } // Parameter defaults
);
With your AdminController action(s) looking like:
public virtual ActionResult Create(string type, int id)
{
switch (type)
{
case 'question':
// switch/case is code smell
break;
case 'user':
// switch/case is code smell
break;
// etc
}
}
Adding routes to global.asax is fairly straight forward. Put the more specific routes above the more general routes. The most typical pattern is controller/action/parameter/parameter... If you need something more complex, you may want to look at MVC Areas.In you example above "mysite.com/admin/user/details" is looking for a controller named "admin" and an action named "user", with everything after that being parameter on the action method (assuming a typical route setup)
I've created a website with ASP.NET MVC. I have a number of static pages that I am currently serving through a single controller called Home. This creates some rather ugly URLs.
example.com/Home/About
example.com/Home/ContactUs
example.com/Home/Features
You get the idea. I'd rather not have to create a controller for each one of these as the actions simply call the View with no model being passed in.
Is there a way to write a routing rule that will remove the controller from the URL? I'd like it to look like:
example.com/About
example.com/ContactUs
example.com/Features
If not, how is this situation normally handled? I imagine I'm not the first person to run in to this.
Here's what I've done previously, using a constraint to make sure the shortcuts don't conflict with other routing rules:
routes.MapRoute(
"HomeShortcuts",
"{action}",
new { controller = "Home", action = "Index" },
new { action = "Index|About|ContactUs|Features" }
);
Add defaults for the controller names in the new statement. You don't have to have {controller} in the url.
I have a controller call DefaultController. Inside this controller i have views for what would be the equivalent of static pages.
The URLs look like www.site.com/Default/PageName
Is it possible to create a route that would format these URL like:
www.site.com/PageName
I want to avoid creating controllers for each of these. An alternative would be to create .aspx pages in the root but can i create routes for these pages ie:
www.site.com/PageName.aspx becomes www.site.com/PageName ?
Thanks!
You can create explicit route for the PageName action on the DefaultController like this:
routes.MapRoute(
"PageName",
"pagename",
new { controller = "DefaultController", action = "PageName" }
);
You have to put this route before the default MVC route. The biggest drawback for this approach is that you have to create one route per static page.
An alternative approach would be to add an additional route after the default MVC route:
routes.MapRoute(
"DefaultController",
"{page}/{*path}",
new { controller = "DefaultController", action = "{page}" }
);
The drawback for this approach is that this rule would be handling all the URLs, even those that would normally return 404.
First approach
Create a route that catches actions:
routes.MapRoute(
"Catcher1",
"{action}",
new { controller = "Default", action = string.Empty });
But this means you'd have to create just as many controller actions on your default controller.
Second approach
If you'd like to avoid that as well and have just one controller+action instead, write a route this way:
routes.MapRoute(
"Catcher2",
"{path}",
new { controller = "Default", action = "PageName", path = string.Emtpy },
new { path = #"[a-zA-Z0-9]+" });
This route also defines a route constraint so it will catch only those routes, that actually have something in first route segment. You can define this constraint to only catch those requests that you need (ie. path = "Result|Search|Whatever")
then your DefaultController would have something like this:
public ActionResult PageName(string path)
{
// code goes here
}
Second approach seems very feasible, but I wouldn't recommend it because all logic would have to go through this controller action (for these kind of requests). It would be better to separate these actions into logical ones. Those that actually do the same thing (so they wouldn't have a bunch of switch statements or similar) would be defined with separate routes (if they couldn't be done using a single one).
I was recently asked to modify a small asp.net mvc application such that the controler name in the urls contained dashes. For example, where I created a controller named ContactUs with a View named Index and Sent the urls would be http://example.com/ContactUs and http://example.com/ContactUs/Sent. The person who asked me to make the change wants the urls to be http://example/contact-us and http://example.com/contact-us/sent.
I don't believe that I can change the name of the controller because a '-' would be an illegal character in a class name.
I was looking for an attribute that I could apply to the controller class that would let me specify the string the controller would use int the url, but I haven't found one yet.
How can I accomplish this?
Simply change the URL used in the route itself to point to the existing controller. In your Global.asax:
routes.MapRoute(
"Contact Us",
"contact-us/{action}/",
new { controller = "ContactUs", action = "Default" }
);
I don't believe you can change the display name of a controller. In the beta, the controller was created using route data "controller" with a "Controller" suffix. This may have changed in RC/RTM, but I'm not sure.
If you create a custom route of "contact-us/{action}" and specify a default value: new { controller = "ContactUs" } you should get the result you are after.
You need to configure routing. In your Global.asax, do the following:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapRoute(
"route-name", "contact-us/{action}", // specify a propriate route name...
new { controller = "ContactUs", action = "Index" }
);
...
As noted by Richard Szalay, the sent action does not need to be specified. If the url misses the .../sent part, it will default to the Index action.
Note that the order of the routes matter when you add routes to the RouteCollection. The first matched route will be selected, and the rest will be ignored.
One of the ASP.NET MVC developers covers what Iconic is talking about. This was something I was looking at today in fact over at haacked. It's worth checking out for custom routes in your MVC architecture.
EDIT: Ah I see, you could use custom routes but that's probably not the best solution in this case. Unless there's a way of dealing with the {controller} before mapping it? If that were possible then you could replace all "-" characters.