Tuesday, October 7, 2014

MVC Tutorial Volume I (Chauhan's)

Understanding Caching in Asp.Net MVC with example

Caching is a most important aspect of high-performance web application. Caching provides a way of storing frequently accessed data and reusing that data. Practically, this is an effective way for improving web application’s performance.

Advantage of Caching


  1. Reduce hosting server round-trips

    When content is cached at the client or in proxies, it cause minimum request to server.
  2. Reduce database server round-trips

    When content is cached at the web server, it can eliminate the database request.
  3. Reduce network traffic

    When content is cached at the client side, it it also reduce the network traffic.
  4. Avoid time-consumption for regenerating reusable content

    When reusable content is cached, it avoid the time consumption for regenerating reusable content.
  5. Improve performance

    Since cached content reduce round-trips, network traffic and avoid time consumption for regenerating reusable content which cause a boost in the performance.

Key points about Caching


  1. Use caching for contents that are accessed frequently.
  2. Avoid caching for contents that are unique per user.
  3. Avoid caching for contents that are accessed infrequently/rarely.
  4. Use the VaryByCustom function to cache multiple versions of a page based on customization aspects of the request such as cookies, role, theme, browser, and so on.
  5. For efficient caching use 64-bit version of Windows Server and SQL Server.
  6. For database caching make sure your database server has sufficient RAM otherwise, it may degrade the performance.
  7. For caching of dynamic contents that change frequently, define a short cache–expiration time rather than disabling caching.

Output Cache Filter

The OutputCache filter allow you to cache the data that is output of an action method. By default, this attribute filter cache the data till 60 seconds. After 60 sec, Asp.Net MVC will execute the action method again and cache the output again.

Enabling Output Caching

You can enable the output caching for an action method or controller by adding an [OutputCache] attribute as shown below:
  1. [OutputCache(Duration=20, VaryByParam="none")]
  2. public ActionResult Index()
  3. {
  4. ViewBag.Message = DateTime.Now.ToString();
  5. return View();
  6. }
The output of the Index() action method will be cached for 20 seconds. If you will not defined the duration, it will cached it for by default cache duration 60 sec. You can see the cache effect by applying the break point on index method as shown below.

OutputCache Filter Parameter


Parameter
Type
Description
CacheProfile
string
Specify the name of the output cache policy which is defined with in <outputCacheSettings> tag of Web.config.
Duration
int
Specify the time in sec to cache the content
Location
OutputCacheLocation
Specify the location of the output to be cached. By default location is Any.
NoStore
bool
Enable/Disable where to use HTTP Cache-Control. This is used only to protect very sensitive data.
SqlDependency
string
Specify the database and table name pairs on which the cache content depends on. The cached data will expire automatically when the data changes in the database.
VaryByContentEncoding
string
Specify the semicolon separated list of character set (Content encoding like gzip and deflate) that the output cache uses to vary the cache content
VaryByCustom
string
Specify the list of custom strings that the output cache uses to vary the cache content.
VaryByHeader
string
Specify the semicolon separated list of HTTP header names that are used to vary the cache content.
VaryByParam
string
Specify the semicolon separated list of form POST or query string parameters that are used to vary the cache content. If not specified, the default value is none.

Output Caching Location

By default, content is cached in three locations: the web server, any proxy servers, and the user's browser. You can control the content's cached location by changing the location parameter of the OutputCache attribute to any of the following values: Any, Client,Downstream, Server, None, or ServerAndClient.
By default, the location parameter has the value Any which is appropriate for most the scenarios. But some times there are scenarios when you required more control over the cached data.
Suppose you want to cache the logged in use information then you should cached the data on client browser since this data is specific to a user. If you will cached this data on the server, all the user will see the same information that is wrong.
You should cache the data on the server which is common to all the users and is sensitive.

Configure Cache Location

For configuring the cache location, you need to add the System.Web.UI namespace on your controller. You can cached the user's personal information in his browser like as below.

  1. [OutputCache(Duration = 7200, Location = OutputCacheLocation.Client, VaryByParam = "none", NoStore = true)]
  2. public ActionResult Index()
  3. {
  4. ViewBag.Message = "Welcome : " + User.Identity.Name;
  5. return View();
  6. }

How to upload a file in MVC4

Posted By : Shailendra Chauhan, 12 Jan 2013
Updated On : 11 Jun 2014
  Version Support : MVC4 & MVC3
Keywords : validate file using jquery,upload file in mvc4 with client side validation,validate file using jquery before upload in mvc4 mvc3

Uploading a file in Asp.Net MVC application is very easy. The posted file is automatically available as a HttpPostedFileBase parameters in the action of the controler. For uploading a file on the server you required to have a file input control with in html form having encoding type set to multipart/form-data. The default encoding type of a form is application/x-www-form-urlencoded and this is no sufficient for posting a large amount of data to server.

How to do it..

Step 1 : Form for uploading the file

  1. @using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
  2. {
  3. @Html.ValidationSummary();
  4. <ol>
  5. <li class="lifile">
  6. <input type="file" id="fileToUpload" name="file" />
  7. <span class="field-validation-error" id="spanfile"></span>
  8. </li>
  9. </ol>
  10. <input type="submit" id="btnSubmit" value="Upload" />
  11. }

Step 2 : Validating the file on client side

  1. <script type="text/jscript">
  2. //get file size
  3. function GetFileSize(fileid) {
  4. try
  5. {
  6. var fileSize = 0;
  7. //for IE
  8. if ($.browser.msie)
  9. {
  10. //before making an object of ActiveXObject,
  11. //please make sure ActiveX is enabled in your IE browser
  12. var objFSO = new ActiveXObject("Scripting.FileSystemObject"); var filePath = $("#" + fileid)[0].value;
  13. var objFile = objFSO.getFile(filePath);
  14. var fileSize = objFile.size; //size in kb
  15. fileSize = fileSize / 1048576; //size in mb
  16. }
  17. //for FF, Safari, Opeara and Others
  18. else
  19. {
  20. fileSize = $("#" + fileid)[0].files[0].size //size in kb
  21. fileSize = fileSize / 1048576; //size in mb
  22. }
  23. return fileSize;
  24. }
  25. catch (e)
  26. {
  27. alert("Error is :" + e);
  28. }
  29. }
  30.  
  31. //get file path from client system
  32. function getNameFromPath(strFilepath)
  33. {
  34. var objRE = new RegExp(/([^\/\\]+)$/);
  35. var strName = objRE.exec(strFilepath);
  36. if (strName == null)
  37. {
  38. return null;
  39. }
  40. else
  41. {
  42. return strName[0];
  43. }
  44. }
  45.  
  46. $("#btnSubmit").live("click", function ()
  47. {
  48. if ($('#fileToUpload').val() == "")
  49. {
  50. $("#spanfile").html("Please upload file");
  51. return false;
  52. }
  53. else
  54. {
  55. return checkfile();
  56. }
  57. });
  58.  
  59. function checkfile()
  60. {
  61. var file = getNameFromPath($("#fileToUpload").val());
  62. if (file != null)
  63. {
  64. var extension = file.substr((file.lastIndexOf('.') + 1));
  65. // alert(extension);
  66. switch (extension) {
  67. case 'jpg':
  68. case 'png':
  69. case 'gif':
  70. case 'pdf':
  71. flag = true;
  72. break;
  73. default:
  74. flag = false;
  75. }
  76. }
  77. if (flag == false)
  78. {
  79. $("#spanfile").text("You can upload only jpg,png,gif,pdf extension file");
  80. return false;
  81. }
  82. else
  83. {
  84. var size = GetFileSize('fileToUpload');
  85. if (size > 3)
  86. {
  87. $("#spanfile").text("You can upload file up to 3 MB");
  88. return false;
  89. }
  90. else
  91. {
  92. $("#spanfile").text("");
  93. }
  94. }
  95. }
  96.  
  97. $(function ()
  98. {
  99. $("#fileToUpload").change(function () {
  100. checkfile();});
  101. });
  102. </script>

Step 3 : Controller's action for receiving the posted file

  1. [HttpPost]
  2. public ActionResult FileUpload(HttpPostedFileBase file)
  3. {
  4. if (ModelState.IsValid)
  5. {
  6. if (file == null)
  7. {
  8. ModelState.AddModelError("File", "Please Upload Your file");
  9. }
  10. else if (file.ContentLength > 0)
  11. {
  12. int MaxContentLength = 1024 * 1024 * 3; //3 MB
  13. string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png", ".pdf" };
  14. if (!AllowedFileExtensions.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
  15. {
  16. ModelState.AddModelError("File", "Please file of type: " + string.Join(", ", AllowedFileExtensions));
  17. }
  18. else if (file.ContentLength > MaxContentLength)
  19. {
  20. ModelState.AddModelError("File", "Your file is too large, maximum allowed size is: " + MaxContentLength + " MB");
  21. }
  22. else
  23. {
  24. //TO:DO
  25. var fileName = Path.GetFileName(file.FileName);
  26. var path = Path.Combine(Server.MapPath("~/Content/Upload"), fileName);
  27. file.SaveAs(path);
  28. ModelState.Clear();
  29. ViewBag.Message = "File uploaded successfully";
  30. }
  31. }
  32. }
  33. return View();
  34. }

How it works...


  
 

Understanding ViewModel in ASP.NET MVC

In ASP.NET MVC, ViewModel is a class that contains the fields which are represented in the strongly-typed view. It is used to pass data from controller to strongly-typed view.

Key Points about ViewModel

  1. ViewModel contain fields that are represented in the view (for LabelFor,EditorFor,DisplayFor helpers)
  2. ViewModel can have specific validation rules using data annotations or IDataErrorInfo.
  3. ViewModel can have multiple entities or objects from different data models or data source.

ViewModel Example

Designing ViewModel

  1. public class UserLoginViewModel
  2. {
  3. [Required(ErrorMessage = "Please enter your username")]
  4. [Display(Name = "User Name")]
  5. [MaxLength(50)]
  6. public string UserName { get; set; }
  7. [Required(ErrorMessage = "Please enter your password")]
  8. [Display(Name = "Password")]
  9. [MaxLength(50)]
  10. public string Password { get; set; }
  11. }

Presenting the viewmodel in the view

  1. @model MyModels.UserLoginViewModel
  2. @{
  3. ViewBag.Title = "User Login";
  4. Layout = "~/Views/Shared/_Layout.cshtml";
  5. }
  6. @using (Html.BeginForm())
  7. {
  8. <div class="editor-label">
  9. @Html.LabelFor(m => m.UserName)
  10. </div>
  11. <div class="editor-field">
  12. @Html.TextBoxFor(m => m.UserName)
  13. @Html.ValidationMessageFor(m => m.UserName)
  14. </div>
  15. <div class="editor-label">
  16. @Html.LabelFor(m => m.Password)
  17. </div>
  18. <div class="editor-field">
  19. @Html.PasswordFor(m => m.Password)
  20. @Html.ValidationMessageFor(m => m.Password)
  21. </div>
  22. <p>
  23. <input type="submit" value="Log In" />
  24. </p>
  25. </div>
  26. }

Working with Action

  1. public ActionResult Login()
  2. {
  3. return View();
  4. }
  5. [HttpPost]
  6. public ActionResult Login(UserLoginViewModel user)
  7. {
  8. // To acces data using LINQ
  9. DataClassesDataContext mobjentity = new DataClassesDataContext();
  10. if (ModelState.IsValid)
  11. {
  12. try
  13. {
  14. var q = mobjentity.tblUsers.Where(m => m.UserName == user.UserName && m.Password == user.Password).ToList();
  15. if (q.Count > 0)
  16. {
  17. return RedirectToAction("MyAccount");
  18. }
  19. else
  20. {
  21. ModelState.AddModelError("", "The user name or password provided is incorrect.");
  22. }
  23. }
  24. catch (Exception ex)
  25. {
  26. }
  27. }
  28. return View(user);
  29. }

Some Tips for using ViewModel

  1. In ViewModel put only those fields/data that you want to display on the view/page.
  2. Since view reperesents the properties of the ViewModel, hence it is easy for rendering and maintenance.
  3. Use a mapper when ViewModel become more complex.
In this way, ViewModel help us to organize and manage data in a strongly-typed view with more flexible way than complex objects like models or ViewBag/ViewData objects.

Asp.net MVC 4 performance optimization with bundling and minification

MVC4 and .Net Framework 4.5 offer bundling and minification techniques that reduce the number of request to the server and size of requested CSS and JavaScript library, which improve page loading time.
System.Web.Optimization class offers the bundling and minification techniques that is exist with in the Microsoft.Web.Optimization dll. Using this dll you can also use this technique with Asp.Net MVC3 and .Net Framework 4.0. Refer the article Bundling and minification in MVC3 and Asp.Net 4.0for more help.

What is Bundle?

A bundle is a logical group of files that is loaded with a single HTTP request. You can create style and script bundle for css and javascripts respectively by calling BundleCollection class Add() method with in BundleConfig.cs file.

Creating Style Bundle

  1. bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
  2. "~/Content/mystyle.min.css"));

Creating Script Bundle

  1. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
  2. "~/Scripts/jquery-1.7.1.min.js",
  3. "~/Scripts/jquery.validate.min.js",
  4. "~/Scripts/jquery.validate.unobtrusive.min.js"));
Above both the bundles are defined with in BundleConfig class as shown below:
  1. public class BundleConfig
  2. {
  3. public static void RegisterBundles(BundleCollection bundles)
  4. {
  5. bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
  6. "~/Content/mystyle.min.css"));
  7. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
  8. "~/Scripts/jquery-1.7.1.min.js",
  9. "~/Scripts/jquery.validate.min.js",
  10. "~/Scripts/jquery.validate.unobtrusive.min.js"));
  11. }
  12. }

Creating Bundle using the "*" Wildcard Character

"*" wildcard character is used to combines the files that are in the same directory and have same prefix or suffix with its name. Suppose you want to add all the scripts files that exist with in "~/Script" directory and have "jquery" as prefix then you can create bundle like below:
  1. bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include("~/Scripts/jquery*.js"));
You can also add all the css that exist with in "~/Content" directory and have ".css" extension(as suffix) like below:
  1. bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/*.css"));

Registering Bundle

All bundles are registered with in Application_Start event of Global.asax file of you web application.
  1. protected void Application_Start()
  2. {
  3. BundleConfig.RegisterBundles(BundleTable.Bundles);
  4. // Other Code is removed for clarity
  5. }

Minification

Minification is technique for removing unnecessary characters (like white space, newline, tab) and comments from the JavaScript and CSS files to reduce the size which cause improved load times of a webpage. There are so many tools for minifying the js and css files. JSMin and YUI Compressor are two most popular tools for minifying the js and css files.
You can also add WebEssentials2012.vsix extension to your VS2012 for minifying the js and css files. This is a great extension for VS2012 for playing with js and css.

Minification with VS2012 and WebEssentials 2012 extension

I would like to share how can you make minify version of you css file using WebEssentials extension and VS2012. This minify version will updated automatically if you will make change in original css file.
  

Performance Optimization with Bundling and Minification

I have done a performance test on a MVC4 application with & without bundling and minification. I have noticed the below result.

Without Bundling and Minification

I have the below css and js files on the layout page and run the application in chrome browser and test no of request and loding time using chrome developer tools as shown below.
  1. <link href="~/Content/Site.css" rel="stylesheet"/>
  2. <link href="~/Content/MyStyle.css" rel="stylesheet"/>
  3. <script src="~/Scripts/jquery-1.7.1.js"></script>
  4. <script src="~/Scripts/jquery-ui-1.8.20.js"></script>
  5. <script src="~/Scripts/jquery.validate.js"></script>
  6. <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
In this test, I have seen, There are 7 request, total data size is 3.96KB and loading time is approximate 296ms.

With Bundling and Minification

I have run the above application with Bundling and Minification of css and js files and test no of request and loding time using chrome developer tools as shown below.
  1. @Styles.Render("~/Content/css")
  2. @Scripts.Render("~/bundles/jquery")
In this test, I have seen, There are only 3 request, total data size is 2.67KB and loading time is approximate 80ms. In this way by using bundling and minification you have reduced the total no of request, size and loading time.

Enabling Bundling and Minification in debug mode

Bundling and minification doesn't work in debug mode. So to enable this featues you need to add below line of code with in Application_Start event of Global.asax.
  1. protected void Application_Start()
  2. {
  3. BundleConfig.RegisterBundles(BundleTable.Bundles);
  4. //Enabling Bundling and Minification
  5. BundleTable.EnableOptimizations = true;
  6. // Other Code is removed for clarity
  7. }

Busting Browser's Cache by Bundling

As you know browsers cache resources based on URLs. When a web page requests a resource, the browser first checks its cache to see if there is a resource with the matched URL. If yes, then it simply uses the cached copy instead of fetching a new one from server. Hence whenever you change the content of css and js files will not reflect on the browser. For this you need to force the browser for refreshing/reloading.
But bundles automatically takes care of this problem by adding a hashcode to each bundle as a query parameter to the URL as shown below. Whenever you change the content of css and js files then a new has code will be generated and rendered to the page automatically. In this way, the browser will see a different url and will fetch the new copy of css and js.

No comments:

Post a Comment