ASP.Net MVC url design & structure guidelines - asp.net-mvc

I wanted to get some expert suggestions on designing urls for our web app. This is not a public domain website, it is a supplychain intranet based web-app used only by a group of authenticated users.
Here're some examples -
/Claim/12/Manage
FORMAT: controller/{ID}/action
The url that points to a "Claim Entry" wizard. Here "12" is the ClaimID. It is further divided into tabs for sub-data entry.
Example: /Claim/12/Print, /Claim/12/FileDetails, ...
/Users/List
FORMAT: controller/action
Display's a list of existing users in Grid. Shud this be shortened to "/Users" ? Likewise we've some other entities as well like "Roles, Organizations, etc..."
/Master/Manage/FileType
FORMAT: controller/action/{argument}
We've a page which allows he user to manage different master table data. Need to know which master table is selected (i.e. sent as argument). Is it better to simplify it as "/Manage/{argument}" instead and then map that url as required above?
Is it sensible in MVC to hide default actions like "Claim/21/Manage" shud be "Claim/21", "/Users/List" shud be "/Users" ...
Arguments - are they better as embedded in url or good to append as query-string
Any generic guidelines or references would also be great.
Ref: Web services url - (Section: Designing the URI Templates)
http://msdn.microsoft.com/en-us/library/dd203052.aspx

You can use Regular Expressions to represent various routes you have. For example
protected void Application_Start()
{
RouteTable
.Routes
.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL template
new { controller="Mycontroller", action="Myaction", id=UrlParameter.Optional },
new { action = #"\d{2}-\d{2}-\d{4}" }
);
}

Well, I conclude that this one is the best (and probably the most detailed) explanation I can find on MSDN - http://msdn.microsoft.com/en-us/library/dd203052.aspx
And that shud be sufficient :-)

Related

Organizing (splitting?) controller while maintaining URL

We have a large web application that is a mix of WebForms and MVC. The URLs we work with look as such www.something.com/Secure/Module/SomeAction. When we used to work with Webforms Module was a folder, as we had as many ASPXs as we needed under that folder. With MVC we're taking a similar approach, where Module translates to a controller, containing all the action. The problem that we're running into is that if the Module has something like 20 - 30 actions it's getting really messy. For example if we have a PersonReport, that usually translates to several actions dedicated to serving that report alone (to facilitate ajax calls etc). Our actions are fairly thin, they populate the model (usually calling WCF services) and that's about it. Nevertheless it can easily creep up to 1500 lines of codes, and we start utilizing regions to organize sections of the controller. Creating a new controller (by default) will obviously stray away from our URL pattern. Any suggestions on how to better organize this mess?
You can use attribute routing if you plan to use MVC 5. This will allow you to specify custom routes for each Action method with attribute
The previous versions allow you to override the default routes through RouteConfig.cs file. Example would be
routes.MapRoute(
name: “ProductPage”,
url: “{productId}/{productTitle}”,
defaults: new { controller = “Products”, action = “Show” },
constraints: new { productId = “\\d+” }
);
See this link for more info.
Hope this helps.

ASP.NET MVC Web.Api Routing - Real world example

I have been looking at routing in the Web.Api and looking at various ways of representing endpoints. I came across Instagrams REST endpoints. (which has some lovely documentation) Using the Web.Api what would be the best way to set up the routing and controllers for a sitution like Instagrams user endpoints?
User Endpoints
GET/users/user-id Get basic information about a user.
GET/users/self/feed See the authenticated user's feed.
GET/users/user-id/media/recent Get the most recent media published by a user.
GET/users/self/media/liked See the authenticated user's list of liked media.
GET/users/search Search for a user by name.
If I wanted to replicate these endpoints in my app, how would I go about it. Would I just need one controller 'Users' with 5 methods, what kind of routing would I need to direct the REST calls to those methods?
I would structure this in a different way.
GET/user
GET/user/user-id
GET/user?q=user-name
GET/media
GET/media/user-id
GET/media/user-id?selection=recent
GET/media/user-id?selection=liked
GET/feed
GET/feed/user-id
This way you keep your Controllers for a specific target, much like keeping your classes for a single responsibility.
User
Media
Feed
When you use this approach it's much easier for a user to 'guess' the path. And I think you could already guess what each path does without any explanation. For me that's the most important when I'm designing a API.
GET/controller - always returns a item list
GET/controller/id - always returns a specific item
GET/controller?q= - always queries the controller
GET/controller?selection= - always selects a subset from the list off items
Ofcourse this is open for interpretation but it gives you an idea about how I would solve this particular problem and maybe some ideas to think about. Also have a look at this great book from Apigee - Web Api Designs
http://info.apigee.com/Portals/62317/docs/web%20api.pdf
Edit:
To make the routes you named I think you've got 2 (not very ideal) options.
Map a specific route for each url
Make a wildcard route
Option 1
I have not tried, or used this myself but you can find more info here:
Single controller with multiple GET methods in ASP.NET Web API
Option 2
If you go the wildcard route all requests with additional parameters will be routed to your default Get() method. In your get you have to look at the parameters using ControllerContext.Request.RequestUri.AbsolutePath or something like it and choose your actions on it.
config.Routes.MapHttpRoute(
name: "MyApi",
routeTemplate: "api/{controller}/{id}/{*wildcard}",
defaults: new { controller = "index", id = RouteParameter.Optional }
);

Suggestions for supporting multilingual routes in ASP.NET MVC

There were questions about multilingual apps in MVC here on SO but they were mostly answered by giving details about implementing Resource files and then referencing those Resource strings in Views or Controller. This works fine for me in conjunction with the detection of user's locale.
What I want to do now is support localized routes. For instance, we have some core pages for each website like the Contact Us page.
What I want to achieve is this:
1) routes like this
/en/Contact-us (English route)
/sl/Kontakt (Slovenian route)
2) these two routes both have to go to the same controller and action and these will not be localized (they will be in English because they are hidden away from the user since they are part of the site's core implementation):
My thought is to make the Controller "Feedback" and Action "FeedbackForm"
3) FeedbackForm would be a View or View User control (and it would use references to strings in RESX files, as I said before, I already have set this up and it works)
4) I have a SetCulture attribute attached to BaseController which is the parent of all of my controllers and this attribute actually inherits FilterAttribute and implements IActionFilter - but what does it do? Well, it detects browser culture and sets that culture in a Session and in a cookie (forever) - this functionality is working fine too. It already effects the Views and View User Controls but at this time it does not effect routes.
5) at the top of the page I will give the user a chance to choose his language (sl|en). This decision must override 4). If a user arrives at our website and is detected as Slovenian and they decide to switch to English, this decision must become permanent. From this time on SetCulture attribute must somehow loose its effect.
6) After the switch, routes should immediately update - if the user was located at /sl/Kontakt
he should immediately be redirected to /en/Contact-us.
These are the constraints of the design I would like. Simply put, I do not want English routes while displaying localized content or vice-versa.
Suggestions are welcome.
EDIT:
There's some information and guidance here - Multi-lingual websites with ASP.NET MVC, but I would still like to hear more thoughts or practices on this problem.
Translating routes (ASP.NET MVC and Webforms)
How about this?
Create custom translate route class.
Localization with ASP.NET MVC using Routing
Preview:
For my site the URL schema should look
like this in general:
/{culture}/{site}
Imagine there is a page called FAQ,
which is available in different
languages. Here are some sample URLs
for these pages:
/en-US/FAQ /de-DE/FAQ /de-CH/FAQ
Why not create the action names desired and simply RedirectToAction for the single, real implementation?
public ActionResult Kontakt() {
return RedirectToAction("Contact");
}
public ActionResult Contact() {
return View();
}
I just used a simple solution with "Globalization Resources", like this:
routes.MapRoute(
"nameroute", // Route name
App_GlobalResources.Geral.Route_nameroute+"/{Obj}", // URL with parameters
new { controller = "Index", action = "Details", Obj = UrlParameter.Optional } // Parameter defaults
);
But, you could customize as needed.

URLs the asp.net mvc way

In the conventional website a url displayed as:
http://www.mySite.com/Topics
would typically mean a page sits in a subfolder below root named 'Topics' and have a page named default.htm (or similar).
I'm trying to get my head in gear with the MVC way of doing things and understand just enough of routing to know i should be thinking of URLs differently.
So if i have a db-driven page that i'd typically script in a physical page located at /Topics/index.aspx - how does this look in an MVC app?
mny thx
--steve...
It sounds like you are used to breaking down your website in terms of resources(topics, users etc) to structure your site. This is good, because now you can more or less think in terms of controllers rather than folders.
Let's say you have a structure like this in WebForms ASP.NET.
-Topics
-index.aspx
-newtopic.aspx
-topicdetails.aspx
-Users
-index.aspx
-newuser.aspx
-userdetails.aspx
The structure in an MVC app will be pretty much the same from a users point of view, but instead of mapping a url to a folder, you map a url to a controller. Instead of the folder(resource) having files inside it, it has actions.
-TopicController
-index
-new
-details
-UserController
-index
-new
-details
Each one of these Actions will then decide what view (be this html, or json/xml) needs to be returned to the browser.
Actions can act differently depending on what HTTP verb they're repsonding to. For example;
public class UserController : Controller
{
public ActionResult Create()
{
return View(new User());
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(User user)
{
// code to validate /save user
if (notValid)
return new View(user);
else
return new View("UserCreatedConfirmation");
}
}
This is sort of a boiled down version of RESTful URLs, which I recommend you take a look at. They can help simplify the design of your application.
It looks just like you want it to be.
Routing enables URL to be quite virtual. In asp.net mvc it will end at specified controller action method which will decide what to do further (i.e. - it can return specified view wherever it's physical location is, it can return plain text, it can return something serialized in JSON/XML).
Here are some external links:
URL routing introduction by ScottGu
ASP.NET MVC tutorials by Stephan Walther
You would have an default view that is associated with an action on the Topics controller.
For example, a list page (list.aspx) with the other views that is tied to the list action of the Topics controller.
That is assuming the default routing engine rules, which you can change.
Read more here:
http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx
IMHO this is what you need for your routes.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Topics", action = "Index", id = "" } // Parameter defaults
);
You would need a TopicsController that you build the View (topics) on.

Url routing with database lookup?

I want to build a ASP.NET MVC site so that the controller for a specific url is stored in the database instead of the URL.
The reason for that is that i'm building a CMS system and the users should be able to change the template (controller) without changing the URL. I also think that the name of the controller is not relevant for the end users and i want clean URL:s.
I realise that i could just add all routes at application start, but for a system with like 100 000 pages it feels like a bad idea.
Is it possible to store the url:s in the database and make a lookup for each request and then map that request to a specific controller?
Basically you'll have to implement your own IRouteHandler.
Part of the answer and some example code is in Option 3 of this question's answer:
ASP.NET MVC custom routing for search
More information:
http://weblogs.asp.net/fredriknormen/archive/2007/11/18/asp-net-mvc-framework-create-your-own-iroutehandler.aspx
Why couldn't you just do something like this:
-- Global.asax.cs --
routes.MapRoute(null, // Route name
"content/{id}", // URL with parameters
new { Controller = "Content", Action = "Show", Id = (string) null }); // Parameter defaults
-- /Controllers/ContentController.cs --
public class ContentController : Controller
{
public ActionResult Show(string id)
{
// Lookup the 'content' (article, page, blog post, etc) in the repository (database, xml file, etc)
ContentRepository repository = new ContentRepository();
Content content = repository.FindContent(id);
return View(content);
}
}
Such that a request to your site www.yoursite.com/content/welcome-to-my-first-blog-post would call ContentController.Show("welcome-to-my-first-blog-post").
I suppose ASP.NET can do many of the same things as PHP. If so there is a simple approach.
With rewrite rules you can easily send any traffic to any URL of the 100K to the same place. On that destination you could simply use the server variables containing the URL requested by the client and extract the location. Look it up in the DB and send the corresponding data for that URL back to the client on-the-fly.
"for a system with like 100,000 pages it feels like a bad idea."
It is a bad idea if you are creating a routing system that cannot be reused. The basic {controller}/{action}/{id} schema points you in the direction of reuse. This schema can be extended/revamped/recreated according to your needs.
Instead of thinking about how many pages you have think about how your resources can be grouped.
Instead of creating a heavy routing system why not create an anchor link control (ascx) which allows user to only add valid internal links. Keep a table in the db of your templates and their controllers to populate the control with it.

Resources