Rules to Better MVC

​Since 1990, SSW has supported the developer community by publishing all our best practices and rules for everyone to see. 

If you still need help, visit ASP.NET MVC Web Application Development and book in a consultant.​

Hold on a second! How would you like to view this content?
Just the title! A brief blurb! Gimme everything!
  1. Do You Help Users By Selecting A Default Field

    ​Help your users by setting the default field when your MVC WebSite loads.​​
    By selecting a default field for your users when a page loads you can improve the usability of your web site by reducing the amount of steps needed to perform a task.

    Here is a way to do this with MVC 3 and Razor:
    1. Add a div with a class around the field you want to set focus on

    <div class="focus">
        @Html.EditorFor(model => model.FirstName)​
        @Html
        @Html.ValidationMessageFor(model => model.FirstName)
    </div>

    2. Then use jQuery to select the class and set focus​:

    $(function() {
        $('.focus :input').focus();
    });
  2. Do you understand the Enterprise MVC request process?

    inject Figure: Bad Example – The sample applications do not include the concept of a business inject Figure: Good Example – An enterprise solution should include a business layer and a data layer abstraction
  3. Do you use TryUpdateModel instead of UpdateModel?

    UpdateModel will throw an exception if validation of the model fails. Instead of managing an exception, you should use TryUpdateModel as it adds the error to the ModelState dictionary. This lets you check the ModelState.IsValid property and decide how to handle the issue from there. This is an important distinction to be made because if we had used UpdateModel then our if (ModelState.IsValid) would not be hit in the event of a failure to bind.

    public ActionResult Create()
    {
        Entity myEntity = new Entity();
        UpdateModel(myEntity);
    }
    
    Figure: Bad Example – UpdateModel may throw an exception and the ModelState dictionary won’t be updated
    public ActionResult Create()
    {
        Entity myEntity = new Entity();
        TryUpdateModel(myEntity);
    
        if (ModelState.IsValid)
        {
            // ...
        }
    }        
    Figure: Good Example – TryUpdateModel will gracefully handle validation and will add to the ModelState dictionary so we can check for validity
  4. Do you use Model Binding instead of FormCollection?

    Model binding in the ASP.NET MVC framework is simple. Your action methods need data, and the incoming HTTP request carries the data you need. The catch is that the data is embedded into POST-ed form values, and possibly the URL itself. Enter the DefaultModelBinder, which can magically convert form values and route data into objects. Model binders allow your controller code to remain cleanly separated from the dirtiness of interrogating the request and its associated environment.

    public ActionResult Create(FormCollection values)
    {
        Recipe recipe = new Recipe();
        recipe.Name = values["Name"];      
                
        // ...
                
        return View();
    }
    
    Figure: Bad Example – Manually reading form values and assigning them to properties is tedious boiler-plate code!
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Recipe newRecipe)
    {            
        // ...
        
        return View();
    }
    
    Figure: Good Example – Using MVC’s model binding allows you to work with an automatically-populated object instead
  5. Do you force SSL on sensitive methods like “Login” or “Register”?

    Any sensitive data that is sent over the wire must be protected using a secure transport such as HTTPS. MVC (version 2, Preview 2 or higher) allows you to specify that HTTPS is required for an action. It’s important that the GET method is secure as well as the POST method to avoid people sending sensitive form data over the wire.

    public ActionResult Register()
    {
       return View();
    }
    
    Figure: Bad Example – The Register method isn’t secure
    [RequireHttps]
    public ActionResult Login()
    {
       return View();
    }
    
    Figure: Good Example – The Login method is protected by HTTPS
  6. Do you use View Models instead of ViewData?

    MVC provides a ViewData collection in which you can store miscellaneous pieces of information to pass to the View.  It’s also accessible it as a Dynamic object by using the ViewBag.  However, you should avoid using ViewData or ViewBag because it isn’t type-safe and relies on Magic Strings.

    public ActionResult Index() {
      ViewData["Message"] = "Some Message";
      return View();
    }
     
    <h1><%: ViewData["Message"] &></h1>
    
    
    Figure: Bad Example – ViewData being used to pass information to the View isn’t type-safe
    public ActionResult Index() {
      var model = new IndexViewModel();
      model.Message = "Some Message";
      return View();
    }
     
    <h1><%: Model.Message %></h1>
    
    
    Figure: Good Example – Using a ViewModel is a safer way to pass data
  7. Do you use RedirectToAction instead of returning a view that’s not named the same as the action?

    Returning a view that is named differently to the action confuses the MVC process and can make the code difficult to maintain.

    In cases where data is posted, if you don't do a redirect and the user hits the refresh/reload button in the browser, the data can be is submitted more than once. This can lead to duplicate data being stored in your database.

    Redirecting after posted data has been processed is called the Post-Redirect-Get (or PRG) pattern.

    [HttpPost]
    public ActionResult Create(CreateModel model)
    {
        // ... save to DB, then:
        ViewBag.Message = "Successfully created " + model.Name;
        return View("Success");
    }
    
    
    Figure: Bad Example – Returning a different view is misleading and potentially dangerous
    [HttpPost]
    public ActionResult Create(CreateModel model)
    {
        // ... save to DB, then:
        return RedirectToAction("Success", new { message = "Successfully created " + model.Name });
    }
    
    public ActionResult Success(string message)
    {
        ViewBag.Message = message;
        return View();
    }
    
    
    Figure: Good Example – Using the PRG pattern to avoid duplicate data being posted
  8. Do you use startup tasks in the ~/App_Start folder instead of putting code in Global.asax?

    Adding code to the Application_Start method in the Global.asax file is the easiest and most straight-forward approach for executing startup logic, however,​ this code should be encapsulated in static methods outside the Global.asax file. Doing this helps provide cleaner code and encourages proper adherence to the Single Responsibility principle.

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
    
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );        }
    }
    
    
    Figure: Bad Example – Logic is implemented in the Application_Start method which breaks the Single Responsibility Principle
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
    
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }
    }
    

    Figure: Good Example – Startup tasks are called from the Application_Start method but are located in the App_Start folder​

  9. Do you use the Authorize attribute to secure actions or controllers?

    ASP.NET MVC provides the AuthorizeAt​tribute which ensures there is a logged in user before it will execute an action. You can also provide parameters to restrict actions or controllers to only be accessible to certain roles or users. This is a better solution than checking whether a logged-in user exists in code as the authorisation itself doesn’t need to be repeated.

    public ActionResult Delete(string tagName)
    {
        if (!Request.RequestContext.HttpContext.User.IsInRole("CanDeleteTags"))
        {
            return new System.Web.Mvc.HttpUnauthorizedResult();
        }
        // delete view
        return View();
    }
    
    Figure: Bad Example – Checking for an appropriate role in code leads to repetition
    [Authorize(Roles = "CanDeleteTags")]
    public ActionResult Delete(string tagName)
    {
        // ...delete tag
        return View();
    }
    
    Figure: Good Example – Using the Authorize attribute to check for appropriate roles
  10. Do you use Html Helpers and Partial Views to simplify Views?

    Repeated sections of User Interface should be encapsulated in either Html Helpers or Partial Views to avoid repetition.

    <div class="featured">
        @if (ViewData.ContainsKey("FeaturedProduct"))
        {
            <span class="ProductName">@ViewBag.FeaturedProduct.Name</span>
            <span class="ProductPrice">@ViewBag.FeaturedProduct.Price</span>
        }
    </div>
    
    
    Figure: Bad Example – The above code could be encapsulated into a Partial View for reuse
    public static class DateExtensions
    {
        public static MvcHtmlString GetTodayDate(this System.Web.Mvc.HtmlHelper helper)
        {
            return new MvcHtmlString(DateTime.Now.ToShortDateString());
        }
    }
    @Html.GetTodayDate()
    
    Figure: Good Example – Using an HTML Helper extension method for reusable code
    @Html.Partial("_FeaturedProduct")
    
    Figure: Good Example – Using a Partial View for reusable sections of UI
  11. Do you avoid hardcoding URLs (“../”, “~/”, or “/”) and use Url.Action or Html.ActionLink instead?

    Hardcoding URLs in your View can cause problems if your routes or page names need to change. Instead, you should always use the Url and Html helpers to refer to different pages in your MVC application.

    <a href="/Rule/Create">Create a Rule</a>
    
    Figure: Bad Example – Hard-coded URLs may lead to broken links if routes change
    @Html.ActionLink("Create a Rule", "Create", "Rule")
    
    Figure: Good Example – Use the Url or Html helpers to provide links
  12. Do you use Bundling to package script and css files?

    ASP.NET provides a great way to compress and package multiple script files or multiple css files. Bundling multiple files together results in fewer requests from the client and smaller payloads which leads to much faster render times.

    Rather than link to each script or css file individually, use bundling to group many together and get the advantages of minification and versioning out of the box.

    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.core.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.resizable.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.selectable.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.accordion.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.autocomplete.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.button.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.dialog.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.slider.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.tabs.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.datepicker.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.progressbar.css" />
    <link rel="stylesheet" href="~/Content/themes/base/jquery.ui.theme.css" />
    
    Figure: Bad Example – each reference will be downloaded separately and won’t be compressed
    Configuration:
    public static void RegisterBundles(BundleCollection bundles)
    {
            bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                    "~/Content/themes/base/jquery.ui.core.css",
                    "~/Content/themes/base/jquery.ui.resizable.css",
                    "~/Content/themes/base/jquery.ui.selectable.css",
                    "~/Content/themes/base/jquery.ui.accordion.css",
                    "~/Content/themes/base/jquery.ui.autocomplete.css",
                    "~/Content/themes/base/jquery.ui.button.css",
                    "~/Content/themes/base/jquery.ui.dialog.css",
                    "~/Content/themes/base/jquery.ui.slider.css",
                    "~/Content/themes/base/jquery.ui.tabs.css",
                    "~/Content/themes/base/jquery.ui.datepicker.css",
                    "~/Content/themes/base/jquery.ui.progressbar.css",
                    "~/Content/themes/base/jquery.ui.theme.css"));
    }
    
    View:
    @Styles.Render("~/Content/themes/base/css")
    
    Figure: Good Example – Define a bundle and render it in the view for maximum performance
  13. Do you use Anti Forgery Tokens on any page that takes a POST?

    To prevent cross-site request forgery (XSRF), you should use Html.AntiForgeryToken. On the action which takes the post request, place the ValidateAntiForgeryToken attribute to enable the request to validate. Doing this ensures that the post is a direct response to the page that was given to this user so only verified posts will be processed.

    @using (Html.BeginForm()) {
        @Html.ValidationSummary(true)
    
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
    
        <p>
            <input type="submit" value="Create" />
        </p>
     }
          
    Figure: Bad Example – The page is potentially vulnerable to XSRF attacks. Any post will be accepted by the server
                View:
    
    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()
        @Html.ValidationSummary(true)
    
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
    
        <p>
            
                <input type="submit" value="Create"/>
        </p>
    }
    
    Controller:
    
    [ValidateAntiForgeryToken]
    public ActionResult Create(CreateModel model)
    {
        // save data
    }
    
          
    Figure: Good Example – The page is no longer vulnerable to XSRF attacks
  14. Do you use the URL as a navigation aid (aka redirect to the correct url if it is incorrect)?

    Figure: Watch the URL working as a navigation aid

    MVC gives us great URLs, but you need to help users navigate via the URL. If the user changes a URL, and the route parameters no longer match, you should correct them with a redirect.

    public ActionResult Edit(string employeename, int id)
    {
        var model = _repository.GetEmployee(id);
    
        // check for a parameter match and redirect if incorrect
        if (string.IsNullOrEmpty(employeename) || employeename != model.EmployeeName)
        {
            return RedirectToAction(
                "Edit", new { employeename = model.EmployeeName, id });
        }
    
        return View(model);
    }
    
    Figure: Good example - the comment says it all
    Wordpress and Stack Overflow have URL formats that do this very well:

    http://tv.ssw.com/3102/business-valueGood example: If the "business-value" part of the URL changes, the page will redirect to the correct location.

    http://stackoverflow.com/questions/729921/settimeout-or-setinterval
    Figure: Good example - If the "settimeout-or-setinterval" part of th eURL changes, the page will redirect to the correct location.
  15. Do you use Thin controllers, Fat models and Dumb views?

    Thin Controllers

    You need to think of a controller as more of a coordinator than a controller.
    It is responsible for calling the business layer and passing from the business layer to the view.
    It is also responsible for process flow.

    public ActionResult Details(decimal todaysWeather)
    {
    var todaysWeatherInFarhenheit = ((9.0 / 5.0) * todaysWeather) + 32;
    return View(todaysWeatherInFarhenheit); }
    Figure: Business logic is mixed up within the controller making it fatter than it should be public ActionResult Index()
    {
    var todaysWeather = weatherDB.Today.ToList();
    return View(todaysWeather);
    }
    Figure: The controller is co-ordinating between the business layer and the view public ActionResult Details(int? id)
    {
    if (!id.HasValue)
    return RedirectToAction("Index");

    return View();
    }
    Figure: The controller is co-ordinating process flow (directing traffic)

    Dumb Views

    Views shouldn't have any flow logic, application logic or business rules.
    The only logic you should have in the view is in relation to the displaying of data.
    The view should never go out and get information from somewhere else.

    @{ var theMonth = DateTime.Now.Month; }
    <p>The numeric value of the current month: @theMonth</p>

    @{
    var outsidetempinfahrenheit = ((9.0 / 5.0) * model.outsideTemp) + 32;
    var weatherMessage = "Hello, it is " + outsidetempinfahrenheit + "
    degrees.";
    }
    <p>Today's weather: @weatherMessage</p>
    Figure: Business logic is mixed in with the view @{ var theMonth = DateTime.Now.Month; }
    <p>The numeric value of the current month: @theMonth</p>

    @{
    var weatherMessage = "Hello, it is " + model.outsideTemp + " degrees.";
    }
    <p>Today's weather: @weatherMessage</p>
    Figure: The logic is related to the displaying of data only

    Fat Model

    So where do we put all the logic? The answer of course is in the model, hence the name fat model.

  16. Do you use NuGet?

    NuGet allows you to search for, install, upgrade, configure and remove 3rd party libraries from Visual Studio projects in a consistent and easy to use manner.

    NuGet makes it easy to manage 3rd party libraries in your projects by keeping track of the library and the files needed to make it work with the concept of a package.

    The package contains all the information needed for the 3rd party library to work with your project including any dependencies it may require.

    The concept of a package makes it very easy to upgrade and remove the libraries in the future with a single click.

    NuGet Figure: Do you download a package, save it locally and then add it to your project manually? NuGet Figure: Step 1 Right click on your project in visual studio and select Manage NuGet Packages NuGet Figure: Step 2 find the package you want and click install

    Now all you need to do when you want to remove or upgrade the package is go back to the NuGet package manager.

    Read more about Do you use NuGet?
  17. Do you know the best NuGet Packages ?Unpublished

    The best NuGet packages are:

    [Todo:] Add a rule for each of these packages

  18. Do you regularly update your dependencies in NuGet?

    ASP.NET MVC makes good use of NuGet for managing its dependencies, however these dependencies can easily get out of date.

    When you begin a new MVC project, there are often many dependencies that already have updated versions.

    You should immediately update your NuGet dependencies in the NuGet Package Manager after starting an MVC project. You should also frequently check for new updates during development so you’re not working with out of date versions.

    NuGet updates screen Figure: Even after starting a brand new project, NuGet shows a lot of required updates!
  19. Do you use Glimpse?

    Glimpse allow you to easily perform diagnostics on your MVC application at runtime.
    As an ASP.NET developer (including ASP.NET MVC), you should use it all the time.

    Glimpse lets you find useful information like:

    • Routing information
    • Profiling
    • Request information
    • Parameters passed into actions
    • Model inspector

    The new version of Glimpse now also gives you a Heads Up Display (HUD) showing you important information all the time.  While developing, it's a good idea to keep Glimpse open so you can see any issues as soon they come up.

    GlimpseHeadsUpDisplay.png

    Figure: The new Glimpse Heads Up Display

    For more information on what the HUD provides, see Damian Brady's blog post​.

    Glimpse is available on NuGet, so it’s a simple matter to get it up and running on your application. You can find out more from their website.

    glimpse.png Figure: Glimpse in action - We can see which routes were chosen for this page, and the parameters used by the controller

    Securing Glimpse for production use

    Glimpse is very powerful but there are some considerations to be addressed before using it on Production.

    • 1. Security: Enabling Glimpse can reveal many details about your server – including full database connection details. Glimpse also publishes a full list of all the actions your MVC site can perform so you should thoroughly test the security on all restricted actions before you consider enabling Glimpse.
    • 2. Performance: Running Glimpse involves sending debug data with every request. This can impact site performance.

    Even with these considerations, Glimpse can provide some unique insights into production server performance so it’s worth spending the time to correctly configure Glimpse for production use.

    Glimpse on Production Level 1: Developers Only

    Install Glimpse on production so that only internal developers can enable it.This is achieved by:

    • Limiting access to an ip address range.
      <glimpse enabled="true">
          <ipAddresses>
            <add address="127.0.0.1" />
            <add addressRange="192.168.1.1/24" />
            <add address="::1" />
          </ipAddresses>
        </glimpse>
      Figure: Glimpse is now limited to localhost and the 192.168.1.x network


    • Using role-based authentication.
      If your site has role-based authentication, you can secure Glimpse usage by editing web.config to control access to the Glimpse.axd location.
      <location path="glimpse.axd">
      <system.web>
               <authorization>
                    <allow roles="Developers" />
                    <deny users="*" />
               </authorization>
      </system.web>
      </location>
      Figure: Glimpse is restricted to the Developers group

     

    Glimpse on Production Level 2: Public by invitation only

    If an end-user reports a problem on your website it can be useful to temporarily enable Glimpse for that user. Glimpse also has remote features allowing developers to see the user’s Glimpse data.

    • Create a new authentication role such as "PublicGlimpseUsers"
    • Edit web.config to control access to Glimpse.axd
      <location path="glimpse.axd">
      <system.web>
               <authorization>
                    <allow roles="Developers, PublicGlimpseUsers" />
                    <deny users="*" />
               </authorization>
      </system.web>
      </location>
      Figure: Glimpse.axd is now restricted to Developers  and PublicGlimpseUsers
    • Disable the “config” section of Glimpse so that site connection strings are not published.
      <pluginBlacklist>
            <add plugin="Glimpse.Core.Plugin.Config" />
      </pluginBlacklist>
      Figure: How to disable the Config tab
    •  

    Read more about Do you use Glimpse?
  20. Do you inject your dependencies?

    Injecting your dependency gives you:

    • Loosely coupled classes
    • Increased code reusing
    • Maintainable code
    • Testable methods
    • All dependencies are specified in one place
    • Class dependencies are clearly visible in the constructor
    inject Figure: Bad Example – A solution where each layer depends on static classes is not maintainable or testable inject Figure: Good Example – Dependencies in each layer should only be interfaces. This allows dependencies to be easily interchanged and unit tests to be written against mock/fake objects inject Figure: Bad Example – Classes should not include dependencies on database classes or business objects. Both of these classes may contain dependencies on external services like web services or databases inject Figure: Good Example – The dependencies are injected into the class. This enables alternative classes to be injected. For example, a DHLShippingCalculator should be easily substituted for a FedexShippingCalculator. A MockShippingCalculator and MockProductRepository could be injected if we wanted to run unit tests
  21. Do You Use a Dependency Injection Centric Architecture ?

    inject Figure: Bad Example – N-Tiered architectures do not inherently support dependency injection inject Figure: Good Example – The Onion Architecture promotes layers built on interfaces, and then injecting dependencies into those layers. This keeps coupling low, and therefore maintainability high

    The classes in each layer can depend on layers toward the centre.

    It emphasizes the use of interfaces for the business logic and repository layers. The repository layer corresponds to the Data Access layer in an n-Tier architecture.

    An n-Tier architecture has at its base the database.
    The core of the onion architecture is the Domain Model, and all dependencies are injected. This leads to more ​maintainable applications since it emphasizes separation of concerns.

    Further Reading:

  22. Do you know the layers of the onion architecture?

    ​​​Onion Architecture
    Figure: The layers of the onion architecture

    Application Core (the grey stuff)

    This should be the big meaty part of the application where the domain logic resides.

    Domain Model

    In the very centre we see the Domain Model, which represents the state and behaviour combination that models truth for the organization and is only coupled to itself.

    Repository Interfaces

    The first layer around the Domain Model is typically where we find interfaces that provide object saving and retrieving behaviour. 
    The object saving behaviour is not in the application core, however, because it typically involves a database.  Only the interface is in the application core.  The actual implementation is a dependency which is injected.

    Business Logic Interfaces

    Business logic is also exposed via interfaces to provide decoupling of business logic.
    Examples of where this is useful include substituting a FacebookNotificationService for an EmailNotificationService or a FedExShippingCalculator for a DHLShippingCalculator

    Clients (the red stuff)

    The outer layer is reserved for things that change often.  E.g. UI and the other applications that consume the Application Core. 
    This includes the MVC project.
    Any interface dependencies in factories, services, repositories, etc, are injected into the domain by the controller.
    This means any constructor-injected interfaces in domain classes are resolved automatically by the IoC container.

    Dependencies

    Dependencies are implementations of interfaces defined in Repository and Business Logic Interfaces and Domain.
    These classes are specific implementations and can be coupled to a particular method of data access, or specific service technology.
    e.g. this is where the EF DbContext is implemented, as well as things like logging, email sending, etc.
    These dependencies are injected into the application core.
    Because the Application core only relies on abstractions of the dependencies, it is easy to update them.
    The Onion Architecture relies heavily on the Dependency Inversion principleand other SOLID principles.

    References:

    Use SSW Data Onion to Generate your Code

    To help make this process pain free, we've developed the SSW Data Onion  to get you going and take away the boilerplate code you would normally need to write. Check out this cool video to see how it works:

     



    Further Reading:Do You Use a Dependency Injection Centric Architecture?

  23. Do you use jQuery with the Web API to build responsive UI?

    You should build a responsive UI using jQuery and a Web API.

    build responsive bad example Bad Example – Posting the whole form in a submit requires the whole page to be posted to the server build responsive Figure: Good Example - Using jQuery to call the Web API provides a great user experience. The whole page does not need to be posted to the server
  24. Do you use Twitter Bootstrap?

    Efficient programmers do not re-invent the wheel. That's why we use the best Web UI libraries.

    Twitter Bootstrap is a NuGet Package that provides a jump-start for HTML based projects. It includes the HTML, CSS and JavaScript framework used by Twitter, to build the Twitter site.

    Building your site on top of bootstrap makes it much easier to have your website look great on devices of all sizes, across many different browsers.

    Bootstrap
    Figure: This website template, along with many others is availa​ble as a starting point for building Bootstrap-based sites
    Bootstrap
    ​Figure: Bad example - Many websites built by using tables for positioning would render poorly on smaller devices, and be hard to use
    Bootstrap
    Figure: Good​ example - Twitter Bootstrap uses many techniques to help make your site look great on different browsers, on all devices

    Read our Rules to Better UI (Bootstrap)​.

    Documentation​

    Bootstrap, from Twitter

  25. Do you bundle and minify your JavaScript?

    Did you know you can improve the speed of your MVC app by using a built in feature called bundling and minification.

    Bundling allows you to:

    1. Specify the JavaScript files you want to include in your app and the order in which they are loaded
    2. Put them into one JavaScript file reducing calls to the server.

    The next part of the process is minification. This means that all the whitespace is removed from the JavaScript files and long variables names are shortened where possible to decrease the size of the package.
    All this adds up to a faster MVC app and a better user experience.

    Layout.cshtml

    <script type="text/javascript" src="/SoftwareDevelopment/RulesToBetterMVC/Pages/@Url.Content("></script>
    <script type="text/javascript" src="/SoftwareDevelopment/RulesToBetterMVC/Pages/@Url.Content("></script>
    <script type="text/javascript" src="/SoftwareDevelopment/RulesToBetterMVC/Pages/@Url.Content("></script>
    <script type="text/javascript" src="/SoftwareDevelopment/RulesToBetterMVC/Pages/@Url.Content("></script>
    <script type="text/javascript" src="/SoftwareDevelopment/RulesToBetterMVC/Pages/@Url.Content("></script>
    <script type="text/javascript" src="/SoftwareDevelopment/RulesToBetterMVC/Pages/@Url.Content("></script>
    Figure: Scripts are specified in the view

    BundleConfig.cs

    public static void RegisterBundles(BundleCollection bundles)
    {
    bundles.Add(new ScriptBundle("~/bundles/SSW").Include(
    "~/Scripts/2011.3.1115/jquery-1.6.4.min.js",
    "~/Scripts/jquery-ui-1.8.16.min.js",
    "~/Scripts/jquery.formatCurrency-1.4.0.min.js",
    "~/Scripts/date.js",
    "~/Scripts/jquery.watermark.min.js",
    "~/Scripts/jquery.cross-slide.min.js"));
    }

    Layout.cshtml

    @Scripts.Render("~/bundles/ssw")
    Figure: A bundle is created in the bundle config and then referenced in the view
  26. Do you know the best sample applications?

    Before starting a software project and evaluating a new technology, it is important to know what the best practices are. The easiest way to get up and running is by looking at a sample application. Below are a list of sample applications that we’ve curated and given our seal of approval.

    SQL Server (2014 and below)

    SQL Server 2016 and Azure SQL Database

    ASP.NET MVC + WebAPI

    SPA

    AngularJS

    Angular

  27. Do you know the best way to do printable reports?

    Making reports on websites printable can be difficult. While there are CSS media and rules to help make pages printable, there are always issues with page breaks, browser quirks and tables.  ​
    print-reports-bad-1.png
    Figure: Beautiful HTML report
    print-reports-bad-2.png
    Figure: Bad Example – The printed layout looks nothing like the HTML
    print-reports-bad-3.png
    Figure: Beautiful PowerBI HTML report
    print-reports-bad-4.png
    Figure: Bad example – PowerBI print preview scales everything down to fit on a page, you have no real control over how things flow onto multiple pages

    The best and most accurate print solution is to use SQL Server Reporting Services (SSRS). You can use SQL Server Reporting Services in MVC even though its only supported by WebForms. 

    It's great to include  SQL Server Reporting Services (SSRS) reports in your web application, which can be done with the Microsoft ReportViewer web control...however this only applies to ASP.NET WebForms.

    With an iframe and a little bit of code, your reports can also be viewed in your ASP.NET MVC application.

    In your MVC project, add a new item of type WebForm.

    16-06-2014 10-44-12 AM.png
    Figure: Add a new WebForm

    Then add the ReportViewer control to the WebForm.

    16-06-2014 10-46-58 AM.png
    Figure: Add the ReportViewer control

    In the View you want to display the report in, add an iframe pointing to your WebForm. 

    Tie them together, by getting your report parameters from the MVC page and appending them to the query string of the iframe URL.

    (The below example uses JavaScript to execute this part from user input)

    16-06-2014 10-50-55 AM.png
    Figure: Add an iframe

    Now you have your SSRS report in your MVC application.

    17-06-2014 8-33-37 AM.png
    Figure: The final report in an MVC application
    16-06-2014 10-38-51 AM.png
    Figure: Export your report with the in-build SSRS functionality

    When using Web-API the method above is difficult and time-consuming!

    2015-04-29_10-09-56-compressor.png

    The easy solution is to render the report within the API and return it to the user  as a pdf. For an example of how to implement the functionality, read the following series  of articles on 'Integrating SSRS Web-API and AngularJS' .

  28. Do you protect your MVC website from automated attack?

    ​​​Protecting your site from automated attack is easy with reCAPTCHA. 

    ​Learn how to by clicking this ​link​ and improve your site security.​​​

    Untitled2.png

    ​​​Figure: Good Example - reCAPTCHA is protecting a site from automated attack
    Untitled.png
    Figu​r​​​​​​​e: Bad Example - Older v1 reCAPTCHA.

    Untitled.png

    Figu​r​​​​​​​e: Bad Example - No protection, a robot can register tens or thousands of users...


  29. Do you update your NuGet packages?

    NuGet packages can quickly get out of date and you may miss some important updates and/or features. Therefore, it is important to keep them up-to-date by updating on a regular basis. This can be done via the Package Manager UI or via the Package Manager Console. 

    ​​nuget-update1.png
    Figure: Good example - NuGet packages via Package Manager are all up-to-date
    ​​nuget-update2.png
    Figure: Update one package at a time eg. The command 'Update-Package EntityFramework' will update the one NuGet package via the Package Manager Console. Then test​

    **WARNING**

    Some package updates may require extra care, such as packages containing content files or updated client script libraries. For example, the jQuery NuGet package update may break the UI of your web application due to some breaking changes introduced in a later version of the library (e.g. upgrading from v 1.10 to 2.0). ​​

    The impact of such upgrades can be greatly minimized by introducing Selenium or Coded UI tests into your solution. Running Selenium or Coded UI tests after performing a NuGet package update, can help to quickly identify problematic areas in your UI, which may be affected by the update. 

  30. Do you use MVC Unobtrusive Validation

    ​Validation is an important part of any data driven web application. Client-Side validation provides fast user feedback and a better UI experience but cannot be relied on for data integrity - so client-side validation should always be backed by additional server-side validation.
    With MVC Unobtrusive Validation, you can configure both client-side and server-side in one place. 

    ​Validation rules can be added to a model object via Data Annotations or using the Fluent Validation API.
    Fluent Validation is available as a Nuget package.

    DataAttributes.png

    OK Example: Data Annotation attributes decorate model properties to make them required

    FluentValidation.png

    Better Example: Fluent Validation allows validation meta data to be added to a class without modifying the original class.  This provides much more flexibility for code reuse.


    If you create a new MVC web application in VisualStudio 2013, unobtrusive validation will be enabled by default. Otherwise it's simple to install from Nuget​. To use it simply:

    1. Bind your razor views to model objects 
    2. Use Html Helpers to render the form UI​

    view.png
    Good Example: this razor view binds to a strongly​​ typed model object and uses html helpers.

    Html.png
    Figure: the HTML UI rendered for this view now has data-validation attributes that are followed by JQuery validation to provide rich client-side validation.

    SaveAction.png
    Figure: On the server-side, the same validation rules will be checked when you call ModelState.IsValid