Here are a few of my tips. And I'd like to hear yours.
Create extension methods of UrlHelper
public static class UrlHelperExtensions
{
// for regular pages:
public static string Home(this UrlHelper helper)
{
return helper.Content("~/");
}
public static string SignUp(this UrlHelper helper)
{
return helper.RouteUrl("SignUp");
}
// for media and css files:
public static string Image(this UrlHelper helper, string fileName)
{
return helper.Content("~/Content/Images/{0}".
FormatWith(fileName));
}
public static string Style(this UrlHelper helper, string fileName)
{
return helper.Content("~/Content/CSS/{0}".
FormatWith(fileName));
}
public static string NoAvatar(this UrlHelper helper)
{
return Image(helper, "NoAvatar.png");
}
}
Use Bootstrapper in Global.asax
If you're doing lots of things in Application_Start, it's better to encapsulate that logic using bootstrapper design pattern.
Decorate your action methods with proper AcceptVerbs
(and CacheControl
for some actions) attributes
[HttpPost, OutputCache(CacheProfile = "Products")]
public ActionResult Products(string category)
{
// implementation goes here
}
Use Dependency Injection pattern
This will make your application loosely coupled and more testable.
Use typed views
Avoid passing data to views via ViewData, create custom models instead for your data and typed views.
Async Controllers
Here is an example:
public Func<ActionResult> Foo(int id) {
AsyncManager.RegisterTask(
callback => BeginGetUserByID(id, callback, null),
a => {
ViewData["User"] = EndGetUserByID(a);
});
AsyncManager.RegisterTask(
callback => BeginGetTotalUsersOnline(callback, null),
a => {
ViewData["OnlineUsersCount"] = EndGetTotalUsersOnline(a);
});
return View;
}
What is happening here is that the MVC system executes both BeginGetUserByID and BeginGetTotalUsersOnline in parallel and when both complete, it will then process the View (display the web page). Simple, clean, efficient.
Security considerations
Don't forget to set [AcceptVerbs(HttpVerbs.Post)], [AntiForgeryToken] and [Authorize] attributes for your submit action methods. Example:
[Authorize("Clients"), HttpPost, ValidateAntiForgeryToken]
public ActionResult SendMoney(int accountID, int amount) {
// your code here
}
And also put this into your form view:
<%= Html.AntiForgeryToken() %>
Avoid having a huge list of route registrations in Global.asax.cs file
Consider using this approach: http://maproutes.codeplex.com/
[Url("store/{?category}")]
public ActionResult Products(string category = null)
{
return View();
}