SSW Foursquare

Rules to Better MVC - 29 Rules

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.

  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 website 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.ValidationMessageFor(model => model.FirstName)
    </div>
    1. Then use jQuery to select the class and set focus:

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

    request process bad
    inject
    Figure: Bad Example – The sample applications do not include the concept of a business
    request process good
    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

    startup task
    Figure: Good example – Startup tasks are called from the Application_Start method but are located in the App_Start folder

  9. Do you use AuthorizeAttribute to secure actions or controllers?

    ASP.NET MVC provides the AuthorizeAttribute 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 authorization 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 AuthorizeAttribute 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?

    Hard-coding 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 if URL 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

    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?

    See more about 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 coordinating 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 bad 1
    Figure: Do you download a package, save it locally and then add it to your project manually?

    NuGet good 1
    Figure: Step 1 - Right click on your project in visual studio and select Manage NuGet Packages

    NuGet good 2
    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.

  17. 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
    NuGet updates screen
    Figure: Even after starting a brand new project, NuGet shows a lot of required updates!

  18. 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
    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
    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

  19. 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 bad 1
    inject
    Figure: Bad Example – A solution where each layer depends on static classes is not maintainable or testable
    inject good 1
    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 bad 2
    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 good 2
    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

  20. Do You Use a Dependency Injection Centric Architecture?

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

    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 the separation of concerns.

    dependency injection bad
    Figure: Bad Example – N-Tiered architectures do not inherently support dependency injection

    dependency injection good
    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

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

    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 principle and other SOLID principles. (Note: Onion Architecture has been replaced by Clean Architecture)

    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?

  22. 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
    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 good
    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

  23. Do you use 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 1
    Figure: This website template, along with many others is available as a starting point for building Bootstrap-based sites

    iphonenonresponsive
    Figure: Bad example - Many websites built by using tables for positioning would render poorly on smaller devices, and be hard to use

    bootstrap 3
    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

    Tailwind

    Alternatively, TailwindCSS is also acceptable. The difference between the Tailwind and Bootstrap is a matter of how comfortable you are with CSS.

    Out of the box, Tailwind is lightweight and will get the job done simply; you can build a website without ever having to look at CSS.

    Bootstrap requires theme customization, but it’s more robust and solid once done. Read more about these differences.

  24. 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 viewBundleConfig.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

  25. 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 is a list of sample applications that we’ve curated and given our seal of approval.

    Northwind Schema

    northwind schema

    SQL Server

    SQL Server and Azure SQL Database

    .NET Core

    • SSW Clean Architecture Solution Template An example REST API build with .NET 7 following the principles of Clean Architecture.
    • SSW Northwind Traders A reference application built using Clean Architecture, Angular 8, EF Core 7, ASP.NET Core 7, Duende Identity Server 6.
    • eShopOnWeb Sample ASP.NET Core 6.0 reference application, powered by Microsoft, demonstrating a layered application architecture with monolithic deployment model. Download the eBook PDF from docs folder.
    • eShopOnContainers Cross-platform .NET sample microservices and container based application that runs on Linux Windows and macOS. Powered by .NET 7, Docker Containers and Azure Kubernetes Services. Supports Visual Studio, VS for Mac and CLI based environments with Docker CLI, dotnet CLI, VS Code or any other code editor.
    • ContosoUniversity This application takes the traditional Contoso University sample applications (of which there have been many), and try to adapt it to how our "normal" ASP.NET applications are built.

    Blazor

    UI - Angular

    • Tour of Heroes Default Angular sample app as part of the documentation
    • ngrx Example App Example application utilizing @ngrx libraries, showcasing common patterns and best practices

    UI - React

  26. 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
    Figure: Beautiful HTML report

    print reports bad 2
    Figure: Bad Example – The printed layout looks nothing like the HTML

    print reports bad 3
    Figure: Beautiful PowerBI HTML report

    print reports bad 4
    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
    Figure: Add a new WebForm

    Then add the ReportViewer control to the WebForm.

    16 06 2014 10 46 58 AM
    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
    Figure: Add an iframe

    Now you have your SSRS report in your MVC application.

    17 06 2014 8 33 37 AM
    Figure: The final report in an MVC application

    16 06 2014 10 38 51 AM
    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

    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'.

  27. 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.

    Good reCAPTCHA
    Untitled2.png

    Figure: Good Example - reCAPTCHA is protecting a site from automated attack

    abd5fe Untitled2
    Untitled.png

    Figure: Bad Example - Older v1 reCAPTCHA.

    4141c3 Untitled
    Untitled.png

    Figure: Bad Example - No protection, a robot can register tens or thousands of users...

  28. 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
    Figure: Good example - NuGet packages via Package Manager are all up-to-date

    nuget update2
    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.

  29. 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. See Do you use Fluent Validation?

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

    FluentValidation
    Figure: Better Example - Fluent Validation allows validation metadata 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
    Figure: Good Example - this razor view binds to a strongly typed model object and uses HTML helpers.

    Html
    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
    Figure: On the server-side, the same validation rules will be checked when you call ModelState.IsValid

We open source. Powered by GitHub