Sunday, 31 July 2016
MVC - Exception Handling
04:46
In ASP.NET, error handling is done using the standard try catch approach or using application events. ASP.NET MVC comes with built-in support for exception handling using a feature known as exception filters. We are going to learn two approaches here: one with overriding the onException method and another by defining the HandleError filters.
Override OnException method
This approach is used when we want to handle all the exceptions across the Action methods at the controller level.
To understand this approach, create an MVC application (follow the steps covered in previous chapters). Now add a new Controller class and add the following code which overrides the onException method and explicitly throws an error in our Action method:
Now let us create a common View named Error which will be shown to the user when any exception happens in the application. Inside the Views folder, create a new folder called Shared and add a new View named Error.
Copy the following code inside the newly created Error.cshtml:
If you try to run the application now, it will give the following result. The above code renders the Error View when any exception occurs in any of the action methods within this controller.
The advantage of this approach is that multiple actions within the same controller can share this error handling logic. However, the disadvantage is that we cannot use the same error handling logic across multiple controllers.
HandleError Attribute
The HandleError Attribute is one of the action filters that we studied in Filters and Action Filters chapter. The HandleErrorAttribute is the default implementation of IExceptionFilter. This filter handles all the exceptions raised by controller actions, filters and views.
To use this feature, first of all turn on the customErrors section in web.config. Open the web.config and place the following code inside system.web and set its value as On.
<customErrors mode="On"/>
We already have the Error View created inside the Shared folder under Views. This time change the code of this View file to the following to strongly-type it with the HandleErrorInfo model (which is present under System.Web.MVC):
@model System.Web.Mvc.HandleErrorInfo
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Error</title>
</head>
<body>
<h2>
Sorry, an error occurred while processing your request.
</h2>
<h2>Exception details</h2>
<p>
Controller: @Model.ControllerName <br>
Action: @Model.ActionName
Exception: @Model.Exception
</p>
</body>
</html>
Now place the following code in your controller file which specifies [HandleError] attribute at the Controller file.
using System;
using System.Data.Common;
using System.Web.Mvc;
namespace ExceptionHandlingMVC.Controllers
{
[HandleError]
public class ExceptionHandlingController : Controller
{
public ActionResult TestMethod()
{
throw new Exception("Test Exception");
return View();
}
}
}
If you try to run the application now, you will get an error similar to shown below:
As you can see, this time the error contains more information about the Controller and Action related details. In this manner, the HandleError can be used at any level and across controllers to handle such errors.
MVC- Bundling
04:45
Bundling and Minification are two performance improvement techniques that improves the request load time of the application. Most of the current major browsers limit the number of simultaneous connections per hostname to six. It means that at a time, all the additional requests will be queued by the browser.
Enabling Bundling and Minification
To enable bundling and minification in your MVC application, open the Web.config file inside your solution. In this file search for compilation settings under system.web:
<system.web> <compilation debug = "true" /> </system.web>
By default, you will see the debug parameter set to true which means that bundling and minification is disabled. Set this parameter to false.
Bundling
To improve the performance of the application, ASP.NET MVC provides inbuilt feature to bundle multiple files into a single file which in turn improves the page load performance because of fewer HTTP requests.
Bundling is a simple logical group of files that could be referenced by unique name and loaded with a single HTTP request.
By default, the MVC application's BundleConfig (located inside App_Start folder) comes with the following code −
public static void RegisterBundles(BundleCollection bundles) { // Following is the sample code to bundle all the css files in the project // The code to bundle other javascript files will also be similar to this bundles.Add(new StyleBundle("~/Content/themes/base/css").Include( "~/Content/themes/base/jquery.ui.core.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")); }
The above code basically bundles all the CSS files present in Content/themes/base folder into a single file.
Minification
Minification is another such performance improvement technique in which it optimizes the javascript, css code by shortening the variable names, removing unnecessary white spaces, line breaks and comments, etc. This in turn reduces the file size and helps the application to load faster.
Minification with Visual Studio and Web Essentials Extension
For using this option, you will have to first install the Web Essentials Extension in your Visual Studio. After that, when you will right click on any css or javascript file, it will show you the option to create a minified version of that file.
So if you had a css file named Site.css, it will create its minified version as Site.min.css.
Now when the next time your application will run in the browser, it will bundle and minify all the css and js files, hence improving the application performance.
MVC - Ajax Support
04:43
Introduction
As you might be knowing, Ajax is a shorthand for Asynchronous JavaScript and XML. The MVC Framework contains built-in support for unobtrusive Ajax by which you can use the helper methods to define your Ajax features without adding code throughout all the views. This feature in MVC is based on the jQuery features.
To enable the unobtrusive AJAX support in the MVC application, open the Web.Config file and set the UnobtrusiveJavaScriptEnabled property inside the appSettings section using the following code. If the key is already present in your application, you can ignore this step.
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
After this, open the common layout file _Layout.cshtml file located under Views/Shared folder. We will add references to the jQuery libraries here using the following code:
<script src="~/Scripts/jquery-ui-1.8.24.min.js" type="text/javascript"></script> <script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
Creating an Unobtrusive Ajax Application
In the example that follows, we will create a form which will display the list of users in the system. We will place a dropdown having three options: Admin, Normal and Guest. When you will select one of these values, it will display the list of users belonging to this category using unobtrusive AJAX setup.
Step 1:
Create a Model file Model.cs and copy the following code:
using System; namespace MVCAjaxSupportExample.Models { public class User { public int UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public DateTime BirthDate { get; set; } public Role Role { get; set; } } public enum Role { Admin, Normal, Guest } }
Step 2:
Create a Controller file named UserController.cs and create two action methods inside that as shown below:
using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using MVCAjaxSupportExample.Models; namespace MVCAjaxSupportExample.Controllers { public class UserController : Controller { private readonly User[] userData = { new User {FirstName = "Edy", LastName = "Clooney", Role = Role.Admin}, new User {FirstName = "David", LastName = "Sanderson", Role = Role.Admin}, new User {FirstName = "Pandy", LastName = "Griffyth", Role = Role.Normal}, new User {FirstName = "Joe", LastName = "Gubbins", Role = Role.Normal}, new User {FirstName = "Mike", LastName = "Smith", Role = Role.Guest} }; public ActionResult Index() { return View(userData); } public PartialViewResult GetUserData(string selectedRole = "All") { IEnumerabledata = userData; if (selectedRole != "All") { var selected = (Role) Enum.Parse(typeof (Role), selectedRole); data = userData.Where(p => p.Role == selected); } return PartialView(data); } public ActionResult GetUser(string selectedRole = "All") { return View((object) selectedRole); } } }
Step 3:
Now create a partial View named GetUserData with the following code. This view will be used to render list of users based on the selected role from the dropdown.
@model IEnumerable<MVCAjaxSupportExample.Models.User> <table> <tr> <th> @Html.DisplayNameFor(model => model.FirstName) </th> <th> @Html.DisplayNameFor(model => model.LastName) </th> <th> @Html.DisplayNameFor(model => model.BirthDate) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.FirstName) </td> <td> @Html.DisplayFor(modelItem => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.BirthDate) </td> <td> </td> </tr> } </table>
Step 4:
Now create a View GetUser with the following code. This view will asynchronously get the data from previously created controller's GetUserData Action.
@using MVCAjaxSupportExample.Models @model string @{ ViewBag.Title = "GetUser"; AjaxOptions ajaxOpts = new AjaxOptions { UpdateTargetId = "tableBody" }; } <h2>Get User</h2> <table> <thead><tr><th>First</th><th>Last</th><th>Role</th></tr></thead> <tbody id="tableBody"> @Html.Action("GetUserData", new {selectedRole = Model }) </tbody> </table> @using (Ajax.BeginForm("GetUser", ajaxOpts)) { <div> @Html.DropDownList("selectedRole", new SelectList( new [] {"All"}.Concat(Enum.GetNames(typeof(Role))))) <button type="submit">Submit</button> </div> }
Step 5:
Finally just change the Route.config entries to launch the User Controller.
defaults: new { controller = "User", action = "GetUser", id = UrlParameter.Optional }
Step 6:
Finally, run the application which will look like the below screenshot:
If you select Admin from the dropdown, it will go and fetch all the users with Admin type. This is happening via AJAX and does not reload the entire page.
MVC - Advanced Example
04:42
In the First MVC Tutorialchapter, we learnt how Controllers and Views interact in MVC. In this tutorial, we are going to take a step forward and learn how to use Models and create an advanced application to create, edit, delete and view list of users in our application.
Steps to create advanced MVC Application
Step 1: Select File->New->Project->ASP.NET MVC Web Application. Name it as AdvancedMVCApplication. Click Ok. In the next window, select Template as Internet Application and View Engine as Razor. Observe that we are using a template this time instead of an Empty application.
This will create a new solution project as shown below. Since we are using the default ASP.NET theme, it comes with sample Views, Controllers, Models and other files.
Build the solution and run the application to see its default output as this:
Step 2: We will add a new model which will define the structure of users data. Right click on Models folder and click Add->Class. Name this as UserModel and click Add.
Step 3: Now copy the following code in the newly created UserModel.cs:
using System; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Web.Mvc.Html; namespace AdvancedMVCApplication.Models { public class UserModels { [Required] public int Id { get; set; } [DisplayName("First Name")] [Required(ErrorMessage = "First name is required")] public string FirstName { get; set; } [Required] public string LastName { get; set; } public string Address { get; set; } [Required] [StringLength(50)] public string Email { get; set; } [DataType(DataType.Date)] public DateTime DOB { get; set; } [Range(100,1000000)] public decimal Salary { get; set; } } }
In the above code, we have specified all the parameters that the User model has, their data types and validations such as required fields and length.
Step 4: Now that we have our User Model ready to hold the data, we will create a class file Users.cs which will contain methods for viewing users, adding, editing and deleting users. Right click on Models and click Add->Class. Name it as Users. This will create users.cs class inside Models.
Copy the following code in the users.cs class.
using System; using System.Collections.Generic; using System.EnterpriseServices; namespace AdvancedMVCApplication.Models { public class Users { public ListUserList = new List (); //action to get user details public UserModels GetUser(int id) { UserModels usrMdl = null; foreach (UserModels um in UserList) if (um.Id == id) usrMdl = um; return usrMdl; } //action to create new user public void CreateUser(UserModels userModel) { UserList.Add(userModel); } //action to udpate existing user public void UpdateUser(UserModels userModel) { foreach (UserModels usrlst in UserList) { if (usrlst.Id == userModel.Id) { usrlst.Address = userModel.Address; usrlst.DOB = userModel.DOB; usrlst.Email = userModel.Email; usrlst.FirstName = userModel.FirstName; usrlst.LastName = userModel.LastName; usrlst.Salary = userModel.Salary; break; } } } //action to delete exising user public void DeleteUser(UserModels userModel) { foreach (UserModels usrlst in UserList) { if (usrlst.Id == userModel.Id) { UserList.Remove(usrlst); break; } } } } }
Step 5: Once we have our UserModel.cs and Users.cs, we will add Views to our model for viewing users, add, edit and delete users. First let us create a View to create user. Right click on the Views folder and click Add->View.
In the next window, select the View Name as UserAdd, View Engine as Razor and select the Create a strongly-typed view checkbox.
Click Add. This will create the following CSHML code by default as shown below:
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "UserAdd"; } <h2>UserAdd</h2> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>UserModels</legend> <div class="editor-label"> @Html.LabelFor(model => model.FirstName) </div> <div class="editor-field"> @Html.EditorFor(model => model.FirstName) @Html.ValidationMessageFor(model => model.FirstName) </div> <div class="editor-label"> @Html.LabelFor(model => model.LastName) </div> <div class="editor-field"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> <div class="editor-label"> @Html.LabelFor(model => model.Address) </div> <div class="editor-field"> @Html.EditorFor(model => model.Address) @Html.ValidationMessageFor(model => model.Address) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.DOB) </div> <div class="editor-field"> @Html.EditorFor(model => model.DOB) @Html.ValidationMessageFor(model => model.DOB) </div> <div class="editor-label"> @Html.LabelFor(model => model.Salary) </div> <div class="editor-field"> @Html.EditorFor(model => model.Salary) @Html.ValidationMessageFor(model => model.Salary) </div> <p> <input type="submit" value="Create" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
As you can see, this view contains view details of all the attributes of the fields including their validation messages, labels, etc. This View will look like this in our final application:
Similar to UserAdd, now we will add four more Views given below with the given code:
Index.cshtml
This View will display all the users present in our system on the Index page.
@model IEnumerable<AdvancedMVCApplication.Models.UserModels> @{ ViewBag.Title = "Index"; } <h2>Index</h2> <p> @Html.ActionLink("Create New", "UserAdd") </p> <table> <tr> <th> @Html.DisplayNameFor(model => model.FirstName) </th> <th> @Html.DisplayNameFor(model => model.LastName) </th> <th> @Html.DisplayNameFor(model => model.Address) </th> <th> @Html.DisplayNameFor(model => model.Email) </th> <th> @Html.DisplayNameFor(model => model.DOB) </th> <th> @Html.DisplayNameFor(model => model.Salary) </th> <th></th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.FirstName) </td> <td> @Html.DisplayFor(modelItem => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.Address) </td> <td> @Html.DisplayFor(modelItem => item.Email) </td> <td> @Html.DisplayFor(modelItem => item.DOB) </td> <td> @Html.DisplayFor(modelItem => item.Salary) </td> <td> @Html.ActionLink("Edit", "Edit", new { id=item.Id }) | @Html.ActionLink("Details", "Details", new { id=item.Id }) | @Html.ActionLink("Delete", "Delete", new { id=item.Id }) </td> </tr> } </table>
This View will look this in our final application:
Details.cshtml:
This View will display details of a specific user when we click on user record.
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "Details"; } <h2>Details</h2> <fieldset> <legend>UserModels</legend> <div class="display-label"> @Html.DisplayNameFor(model => model.FirstName) </div> <div class="display-field"> @Html.DisplayFor(model => model.FirstName) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.LastName) </div> <div class="display-field"> @Html.DisplayFor(model => model.LastName) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.Address) </div> <div class="display-field"> @Html.DisplayFor(model => model.Address) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.Email) </div> <div class="display-field"> @Html.DisplayFor(model => model.Email) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.DOB) </div> <div class="display-field"> @Html.DisplayFor(model => model.DOB) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.Salary) </div> <div class="display-field"> @Html.DisplayFor(model => model.Salary) </div> </fieldset> <p> @Html.ActionLink("Edit", "Edit", new { id=Model.Id }) | @Html.ActionLink("Back to List", "Index") </p>
This View will look like this in our final application:
Edit.cshtml:
This View will display the edit form to edit the details of an existing user.
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.ValidationSummary(true) <fieldset> <legend>UserModels</legend> @Html.HiddenFor(model => model.Id) <div class="editor-label"> @Html.LabelFor(model => model.FirstName) </div> <div class="editor-field"> @Html.EditorFor(model => model.FirstName) @Html.ValidationMessageFor(model => model.FirstName) </div> <div class="editor-label"> @Html.LabelFor(model => model.LastName) </div> <div class="editor-field"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName) </div> <div class="editor-label"> @Html.LabelFor(model => model.Address) </div> <div class="editor-field"> @Html.EditorFor(model => model.Address) @Html.ValidationMessageFor(model => model.Address) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </div> <div class="editor-label"> @Html.LabelFor(model => model.DOB) </div> <div class="editor-field"> @Html.EditorFor(model => model.DOB) @Html.ValidationMessageFor(model => model.DOB) </div> <div class="editor-label"> @Html.LabelFor(model => model.Salary) </div> <div class="editor-field"> @Html.EditorFor(model => model.Salary) @Html.ValidationMessageFor(model => model.Salary) </div> <p> <input type="submit" value="Save" /> </p> </fieldset> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
This View will look like this in our application:
Delete.cshtml:
This View will display the form to delete the existing user.
@model AdvancedMVCApplication.Models.UserModels @{ ViewBag.Title = "Delete"; } <h2>Delete</h2> <h3>Are you sure you want to delete this?</h3> <fieldset> <legend>UserModels</legend> <div class="display-label"> @Html.DisplayNameFor(model => model.FirstName) </div> <div class="display-field"> @Html.DisplayFor(model => model.FirstName) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.LastName) </div> <div class="display-field"> @Html.DisplayFor(model => model.LastName) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.Address) </div> <div class="display-field"> @Html.DisplayFor(model => model.Address) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.Email) </div> <div class="display-field"> @Html.DisplayFor(model => model.Email) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.DOB) </div> <div class="display-field"> @Html.DisplayFor(model => model.DOB) </div> <div class="display-label"> @Html.DisplayNameFor(model => model.Salary) </div> <div class="display-field"> @Html.DisplayFor(model => model.Salary) </div> </fieldset> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <p> <input type="submit" value="Delete" /> | @Html.ActionLink("Back to List", "Index") </p> }
This View will look like this in our final application:
Step 6: We have already added the Models and Views in our application. Now finally we will add a controller for our view. Right click on the Controllers folder and click Add->Controller. Name it as UserController.
By default, your Controller class will be created with the following code:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using AdvancedMVCApplication.Models; namespace AdvancedMVCApplication.Controllers { public class UserController : Controller { private static Users _users = new Users(); public ActionResult Index() { return View(_users.UserList); } } }
In the above code, the Index method will be used while rendering the list of users on the Index page.
Step 6: Right click on the Index method and select Create View to create a View for our Index page (which will list down all the users and provide options to create new users).
Step 7: Now add the following code in the UserController.cs. In this code, we are creating action methods for different user actions and returning corresponding views that we created earlier.
We will add two methods for each operation: GET and POST. HttpGet will be used while fetching the data and rendering it. HttpPost will be used for creating/updating data. For example, when we are adding a new user, we will need a form to add a user which is a GET operation. Once we fill the form and submit those values, we will need the POST method.
//Action for Index View public ActionResult Index() { return View(_users.UserList); } //Action for UserAdd View [HttpGet] public ActionResult UserAdd() { return View(); } [HttpPost] public ActionResult UserAdd(UserModels userModel) { _users.CreateUser(userModel); return View("Index", _users.UserList); } //Action for Details View [HttpGet] public ActionResult Details(int id) { return View(_users.UserList.FirstOrDefault(x => x.Id == id)); } [HttpPost] public ActionResult Details() { return View("Index", _users.UserList); } //Action for Edit View [HttpGet] public ActionResult Edit(int id) { return View(_users.UserList.FirstOrDefault(x=>x.Id==id)); } [HttpPost] public ActionResult Edit(UserModels userModel) { _users.UpdateUser(userModel); return View("Index", _users.UserList); } //Action for Delete View [HttpGet] public ActionResult Delete(int id) { return View(_users.UserList.FirstOrDefault(x => x.Id == id)); } [HttpPost] public ActionResult Delete(UserModels userModel) { _users.DeleteUser(userModel); return View("Index", _users.UserList); } sers.UserList); }
Step 8: Last thing to do is go to RouteConfig.cs file in App_Start folder and change the default Controller to User.
defaults: new { controller = "User", action = "Index", id = UrlParameter.Optional }
Step 9: That's all we need to get our advanced application up and running. Now run the application. You will be able to see an application like this and you can perform all the functionalities of adding, viewing, editing, deleting users as we saw in the earlier screenshots.
Subscribe to:
Comments (Atom)