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
Then use jQuery to select the class and set focus:
$(function() { $('.focus :input').focus();});
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.
Understanding the Enterprise MVC request process is crucial for ensuring smooth operations, efficient handling of requests, and alignment with organizational goals. It enables timely delivery and keeps everyone well-informed throughout the process.
Figure: Bad example – The sample applications do not include the concept of a business
Figure: Good example – An enterprise solution should include a business layer and a data layer abstraction
Understanding the Enterprise MVC request process is crucial for ensuring smooth operations, efficient handling of requests, and alignment with organizational goals. It enables timely delivery and keeps everyone well-informed throughout the process.
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.
Figure: Good example – TryUpdateModel will gracefully handle validation and will add to the ModelState dictionary so we can check for validity
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.
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.
Figure: Good example – Using MVC’s model binding allows you to work with an automatically-populated object instead
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.
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.
publicActionResultRegister(){returnView();}
Figure: Bad example – The Register method isn’t secure
Figure: Good example – The Login method is protected by HTTPS
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.
ASP.NET CORE MVC provides several ways to pass data to views:
Weakly typed data: ViewData and ViewBag
Strongly typed data: ViewModel
Both ViewData and ViewBag are dynamically resolved at runtime, which can often lead to runtime errors because they aren't type-safe and rely on Magic Strings.
Figure: Bad example – Displaying not-safe data in View
So it is better to use ViewModel to pass data to views. Because it allows to take advantage of strong type checking, and the validity of types used in a view is checked at compile time.
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.
[HttpPost]publicActionResultCreate(CreateModelmodel){// ... save to DB, then:ViewBag.Message = "Successfully created " + model.Name;returnView("Success");}
Figure: Bad example – Returning a different view is misleading and potentially dangerous
[HttpPost]publicActionResultCreate(CreateModelmodel){// ... save to DB, then:returnRedirectToAction("Success", new { message = "Successfully created " + model.Name });}publicActionResultSuccess(stringmessage){ViewBag.Message = message;returnView();}
Figure: Good example – Using the PRG pattern to avoid duplicate data being posted
Returning a view that is named differently to the action confuses the MVC process and can make the code difficult to maintain.
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.
publicclassMvcApplication : System.Web.HttpApplication{protectedvoidApplication_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
Figure: Good example – Startup tasks are called from the Application_Start method but are located in the App_Start folder
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.
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.
Figure: Good example – Using the AuthorizeAttribute to check for appropriate roles
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.
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.
<ahref="/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
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.
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.
Figure: Good example – Define a bundle and render it in the view for maximum performance
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.
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.
Figure: Good example – The page is no longer vulnerable to XSRF attacks
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.
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.
Video: Do you use the URL as a navigation aid (aka redirect to the correct url if it is incorrect)? (35 sec)
publicActionResultEdit(stringemployeename, intid){varmodel = _repository.GetEmployee(id);// check for a parameter match and redirect if incorrectif (string.IsNullOrEmpty(employeename) || employeename != model.EmployeeName) {returnRedirectToAction("Edit", new { employeename = model.EmployeeName, id }); }returnView(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
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.
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.
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.
@{vartheMonth = DateTime.Now.Month; }<p>The numeric value of the current month: @theMonth</p>;@{varoutsidetempinfahrenheit = ((9.0 / 5.0) \* model.outsideTemp) + 32;varweatherMessage = "Hello, it is " + outsidetempinfahrenheit + "degrees.";}<p>Today'sweather: @weatherMessage</p>; Figure: Businesslogicismixedinwiththeview@{vartheMonth = DateTime.Now.Month; }<p>Thenumericvalueofthecurrent month: @theMonth</p>;@{varweatherMessage = "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.
See more about Thin Controllers, Fat Models, and Dumb Views.
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.
Figure: Do you download a package, save it locally and then add it to your project manually?Figure: Step 1 - Right click on your project in visual studio and select Manage NuGet PackagesFigure: 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.
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.
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 screenFigure: Even after starting a brand new project, NuGet shows a lot of required updates!
ASP.NET MVC makes good use of NuGet for managing its dependencies, however these dependencies can easily get out of date.
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.
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.
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:
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.
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"
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.
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
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
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.
Figure: Bad example – N-Tiered architectures do not inherently support dependency injection
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 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.
The Onion Architecture is a software design approach that promotes a clear separation of concerns by organizing code into distinct layers. Each layer has a specific purpose, forming concentric circles around the core business logic, much like layers of an onion. This architecture encourages flexibility, testability, and resilience, ensuring that changes in outer layers have minimal impact on the core logic.
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.
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:
The Onion Architecture is a software design approach that promotes a clear separation of concerns by organizing code into distinct layers. Each layer has a specific purpose, forming concentric circles around the core business logic, much like layers of an onion. This architecture encourages flexibility, testability, and resilience, ensuring that changes in outer layers have minimal impact on the core logic.
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
You should build a responsive UI using jQuery and a Web API.
Bootstrap is a NuGet Package that provides a jump-start for HTML-based projects. It includes the HTML, CSS and JavaScript framework used 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.
One of the benefits of using Bootstrap over a library such as Shadcn is that it's widely supported across a large number of frontend frameworks. Take a look at the following Bootstrap integrations for example:
While you can use Bootstrap without any framework-specific integrations, using one of the libraries can save you a lot of time managing your CSS classes and writing boilerplate code while building your interface. The frontend frameworks listed above are ultimately just wrappers for using Bootstrap, which is little more than a CSS library. This means that you can use Bootstrap with any frontend framework of your choosing. You can even use it for static HTML pages provided that you include links to the required JavaScript and CSS files in your pages. This can be achieved by adding a link to Bootstrap's CDN in your pages.
Tailwind
TailwindCSS is also recommended. 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.
Note: The difference between Tailwind and Bootstrap often comes down to how comfortable you are with writing CSS. Tailwind gives you full control with utility classes, while Bootstrap provides ready-made components that require less custom styling. Read more about these differences.
Upgrading Tailwind (v3 → v4)
If you are considering an upgrade to Tailwind 4, plan ahead. The jump from version 3 to 4 is substantial, and requires careful manual QA due to breaking changes in utilities, defaults, and stricter browser support.
✅ Pros of v4
Faster builds – Up to 5× faster full builds and 100× faster incremental builds
Simpler setup – Fewer dependencies, one CSS import, zero config for most apps
Auto content detection – No need for a content array; use @source when needed
CSS-first config – Tokens defined via @theme, exposed as CSS variables for runtime theming
New core APIs – Container queries, 3D transforms, expanded gradients, not-*, @starting-style
Bootstrap is a NuGet Package that provides a jump-start for HTML-based projects. It includes the HTML, CSS and JavaScript framework used to build the Twitter site.
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.
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
Awesome Blazor Browser
A Blazor example app that links to many other useful Blazor examples
Blazor Workshop
A Blazor workshop showing how to build fast food website
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
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.
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.
Figure: Beautiful HTML report
Figure: Bad Example – The printed layout looks nothing like the HTML
Figure: Beautiful PowerBI HTML report
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.
Figure: Add a new WebForm
Then add the ReportViewer control to the WebForm.
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)
Figure: Add an iframe
Now you have your SSRS report in your MVC application.
Figure: The final report in an MVC applicationFigure: Export your report with the in-build SSRS functionality
When using Web-API the method above is difficult and time-consuming
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'.
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.
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.
Figure: Good example - NuGet packages via Package Manager are all up-to-date
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.
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.
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.
Figure: OK Example - Data Annotation attributes decorate model properties to make them requiredFigure: 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:
Bind your razor views to model objects
Use Html Helpers to render the form UI
Figure: Good Example - this razor view binds to a strongly typed model object and uses HTML helpers.
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.Figure: On the server-side, the same validation rules will be checked when you call ModelState.IsValid
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.