This article will demonstrate us about best practices which should be used when working with Asp.Net MVC application. We always try to make Asp.Net MVC application using best practices but don't know exactly where we can implement best things. So, in this demonstration, you will see best practices which should be implemented when creating MVC application.
Isolate Components
Asp.Net MVC application contains several components like Model, Controller, View, Data Access Logic, Repository Logic, Service Layer. So, best practice is that always isolate with different solutions. It makes life easy when working with different components.
Use View Model
When working with enterprise level application in Asp.Net MVC, don't work with Entity [Model] directly. We should create ViewModels which will strongly bind with Views. ViewModel is a class same as Model class but contains some extra properties which required only for business process.
Always Dispose Context Object
Generally in Asp.Net MVC we prefer to work with Custom DataContext Class which inherited DbContext. But when we perform database operations like Create, Read, Update and Delete through this context object. So, it is necessary to dispose the context object after process.
To do this, create a class which implement IDisposable interface.
public abstract class DefaultDisposable : IDisposable
{
protected readonly NextProgrammingDataContext context;
private bool _disposed;
private readonly object _disposeLock = new object();
protected DefaultDisposable()
{
context = new NextProgrammingDataContext();
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
lock (_disposeLock)
{
if (!_disposed)
{
if (disposing)
{
context.Dispose();
}
_disposed = true;
}
}
}
}
And Inherit this class with our Repository Class where context object will be destroy after completing the process.
public class CategoryRepository: DefaultDisposable, ICategoryRepository
{
public int AddNewCategory(Category categoryEntity)
{
int categoryId = 0;
if (categoryEntity != null)
{
if (CheckCategoryExists(categoryEntity.CategoryName) > 0)
{
categoryId = CheckCategoryExists(categoryEntity.CategoryName);
}
else
{
context.Categories.Add(categoryEntity);
context.SaveChanges();
categoryId = categoryEntity.CategoryId;
}
}
return categoryId;
}
}
Use Caching through Web.Config
Caching is an important feature when working with Web Development. It reduces load time when our website uses Caching feature. We can implement Caching in Asp.Net MVC using OutputCache attribute. It is part of Action Filter. OutputCacheAttribute class inherite ActionFilterAttribute class.
To implement Output Cache, just put the OutputCache attribute on Controller or Action level as following line of code showing.
OutputCache(CacheProfile = "MyCache")]
public ActionResult Index(int? pageNumber)
{
int page = pageNumber ?? 1;
return View();
}
Above code shows that we are using OutputCache attribute with action level and passing the CacheProfile. So, what CacheProfile is. Basically it is best practice to implement cache through Web.Config file, we can create n numbers of Cache Profile in Web.Config and use it as per requirment as following code.
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="MyCache" duration="100000" varyByParam="none" location="Server"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>
Use BaseController
It is recommended to use Base Controller with our controller and this Base Controller will inherit Controller class directly. It provides isolation space between our controller [InterviewController] and Controller. Using Base Controller we can write common logic which could be shared by all controllers.
public class BaseController : Controller
{
protected virtual LoginPrincipal LoggedUser
{
get { return HttpContext.User as LoginPrincipal; }
}
protected int GetUserId()
{
int userId = -1;
if (Request.IsAuthenticated)
{
userId = LoggedUser.UserId;
}
return userId;
}
}
And use it as following.
public class InterviewController : BaseController
Use Dependency Injection
It always recommended to use Dependency Injection with Asp.Net MVC application. And on the runtime, inject class dependencies. For more infor refer my article How to use Dependency Injection with Asp.Net MVC application.
public class InterviewController : BaseController
{
private const int pageSize = 10;
private readonly IInterviewPostRepository _interviewPostRepository;
private readonly IInterviewCategoryRepository _interviewCategoryRepository;
private readonly ICommentsRepository _commentsRepository;
private readonly IUserRepository _userRepository;
public InterviewController(IInterviewPostRepository interviewPostRepository, IInterviewCategoryRepository interviewCategoryRepository, ICommentsRepository commentsRepository, IUserRepository userRepository)
{
_interviewPostRepository = interviewPostRepository;
_interviewCategoryRepository = interviewCategoryRepository;
_commentsRepository = commentsRepository;
_userRepository=userRepository;
}
public ActionResult Index(int? pageNumber)
{
return View();
}
}
There are different ways to use Dependency Injection, we are using Ninject with this demonstration.
public class NinjectBindings : NinjectModule
{
public override void Load()
{
Bind<IUserRepository>().To<UserRepository>();
Bind<ICommentsRepository>().To<CommentsRepository>();
Bind<IInterviewCategoryRepository>().To<InterviewCategoryRepository>();
Bind<IInterviewPostRepository>().To<InterviewPostRepository>();
}
}
Strongly Type View
Best practice when working with View and passing data from controller using data access logic to use Strongly Type View and which map with a ViewModel directly.
@model DotnetTutorial.Data.ViewModel.ContactUsViewModel
@{
ViewBag.Title = "Contact Us - DotNet Tutorial";
Layout = "~/Views/Shared/_LayoutBase.cshtml";
}
<div class="col-md-8">
<div>
<h1 itemprop="name">CONTACT US</h1>
</div>
<hr />
<h3>Send us a Message</h3>
<br />
@if (ViewBag.ContactUsSuccess != null)
{
<b style="color: green;">
<p class="alert alert-success" style="text-align: center">@ViewBag.ContactUsSuccess</p>
</b>
}
@if (ViewBag.ContactUsFailed != null)
{
<b style="color: red;">
<p class="alert" style="text-align: center">@ViewBag.ContactUsFailed </p>
</b>
}
@using (Html.BeginForm("ContactUs", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="control-group form-group">
<div class="controls">
@Html.LabelFor(m => m.QueryType)
@Html.DropDownListFor(m => m.SelectValue, new SelectList(Model.QueryTypeList, "value", "text"), "Select Query Type", new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.SelectValue, "", new { @style = "color:red" })
</div>
</div>
<div class="control-group form-group">
<div class="controls">
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Name, "", new { @style = "color:red" })
</div>
</div>
<div class="control-group form-group">
<div class="controls">
@Html.LabelFor(m => m.EmailId)
@Html.TextBoxFor(m => m.EmailId, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.EmailId, "", new { @class = "", @style = "color:red" })
</div>
</div>
<div class="control-group form-group">
<div class="controls">
@Html.LabelFor(m => m.ContactNumber)
@Html.TextBoxFor(m => m.ContactNumber, new { @class = "form-control" })
</div>
</div>
<div class="control-group form-group">
<div class="controls">
@Html.LabelFor(m => m.QueryContent)
@Html.TextAreaFor(m => m.QueryContent, new { @class = "form-control", rows = "3" })
@Html.ValidationMessageFor(m => m.QueryContent, "", new { @class = "", @style = "color:red" })
</div>
</div>
<input type="submit" value="Send Message" id="btnSubmitQuery" class="btn btn-primary" />
}
</div>
Use HTTP Verbs
Always use HTTP verbs which suitable to action method as HttpPut or HttpGet. If you don't put it will work as HttpGet by default.
But when adding something in database using insert operation, need to use HttpPut.
[HttpPost]
public ActionResult AddNewPost(MyViewModel model, string hdnTagList)
Use Bundling and Minification
As per Asp.Net MVC application performance we should always use Bundling and Minification. Using Bundling and Minification, we can make fewer request on server and decrease the file size which will download faster. Minification is achieved to use .min file. We can do Bundiling in BundleConfig class as following.
public class BundleConfig
{
// For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Use the development version of Modernizr to develop with and learn from. Then, when you're
// ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
"~/Scripts/modernizr-*"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js"));
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
}
}
Use Area
If we are interested to create pluggable application in Asp.Net MVC then Area is the best option. Area provides separation of components. Using Area we can create multiple modules in same application where every module is working individually without affected to other functionality.
Mostly Area is used to create Backend module like Admin part in application. With following image, we can see that we have created three areas like Blog, InterviewAdmin, TutorialAdmin. Every Area component [blog] will contain own Controller folder, View folder and Models folder.
Use Request Validation
Always use Request Validation as false [ValidateInput(false)]. By default it is true and this can causes security issue because if it is true then using html control we can pass html content to server. So, best practice to use Request Validation as false.
[ValidateInput(false)]
[OutputCache(CacheProfile = "MyCache")]
public ActionResult Index(string url)
Use Validation through DataAnnotation
Validation is the important part when working with any application. In Asp.Net MVC we can implement validation on server side using DataAnnotation which will found in using System.ComponentModel.DataAnnotations namespace.
After using this, we don't need to do extra workjust pass validation as per requirements like for checking the control is not empty use [Required] attribute, for max length validation just use [MaxLength] attribute with properties.
public class PostViewModel
{
public int PostId { get; set; }
[Display(Name="Post Title")]
[Required(ErrorMessage="Post Title is required")]
[RegularExpression(@"^.{5,}$", ErrorMessage = "Minimum 3 characters required")]
[StringLength(500,MinimumLength=3, ErrorMessage="Invalid Title Lenght")]
public string PostTitle { get; set; }
[MaxLength(Int32.MaxValue, ErrorMessage = "More than max value")]
[AllowHtml]
[Display(Name = "Short Content")]
[Required(ErrorMessage = "Short Content is required")]
public string ShortPostContent { get; set; }
[AllowHtml]
[MaxLength(Int32.MaxValue, ErrorMessage = "More than max value")]
[Display(Name = "Full Content")]
[Required(ErrorMessage = "Full Content is required")]
public string FullPostContent { get; set; }
[Display(Name = "Meta keywords")]
[Required(ErrorMessage = "Meta Keywords is required")]
public string MetaKeywords { get; set; }
[Display(Name = "Meta Description")]
public string MetaDescription { get; set; }
}
Use Only Single View Engine
In Asp.Net MVC, by default there are two engines available one is aspx engine and other one is razor engine. But it prefers to use only one engine for increasing performance of the application. So, first we need to clear ViewEngines when initializing the application and then bind our preferable engine with application.
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngine());
Conclusion:
So, today we have learned Best Practices when working with Asp.Net MVC application.
I hope this post will help you. Please put your feedback using comment which helps me to improve myself for next post. If you have any doubts please ask your doubts or query in the comment section and If you like this post, please share it with your friends. Thanks
Posted Comments :
Mukesh Kumar Author Posted : 8 Years Ago
Thanks for your valuable, I will package code for this demonstration and share with you.
Amit Mishra Posted : 8 Years Ago
Very nice Article ! It would be greate if you could provide source code. It will be easy to understand by source code. Thanks a lot
boriphuth Posted : 8 Years Ago
Waiting for your source code thank you.
Asutosha Posted : 8 Years Ago
Can I have this source code ? Much appreciated
Mukesh Kumar Author Posted : 8 Years Ago
Actually all points has defined with different scenario, these all are not belong to single solution, so it is little difficult for me to gather all in one place in single solution. I can do one thing, if you required any specific solution for any points, kindly let me know.
Anand Posted : 8 Years Ago
Hi Mukesh, I really enjoy with the Explanation of the each topic In you website. Good going, Keep it Up. God Bless you
raef daood Posted : 7 Years Ago
Can you send me the source files very thanks...
Mike Posted : 7 Years Ago
Please Can you send me the source files. very thanks
Eric Posted : 7 Years Ago
Hi Mukesh. Thanks for the great article. Really helping on my conversion from WebForms to MVC. Can I bother you for the source files referenced in the article? Thanks!
a.xanthoudakis Posted : 7 Years Ago
Great Article!! Any source code file would be much appreciated!! Thanks!
sanjeewa Posted : 8 Years Ago
Can we have a downloadable source files, for these examples