Monday, November 19, 2012

How to Improve ASP.Net MVC 3 View Performance ?

What is a View ?
  • Incoming browser requests are mapped to controller actions
  • A controller action might return a View
  • View handles the display of the data
  • Most often the Views are created from the ViewModel data

MVC

How to Improve View Performance ?

Tip 01 :  Run in Release Mode
  • You should always make sure that your application is Compiled in Release Mode
Compiled in Release Mode
  • Your Web.config file Must Looks Like below on Production
         <compilation debug="false" targetFramework="4.0">
         <assemblies>

        </assemblies>
     </compilation>

   Why This Needs ?

      #  MVC Will Not do any View Look-up Caching if you are running your application
            in Debug Mode

Tip 02 : Use only the View Engines that you need

  • MVC framework supports having multiple view engines
  • Can Configured simultaneously in your application
  • And will query each in turn when it is trying to find a View
  • In MVC 3 we register two view engines by default (WebForms and Razor)
  • There is no reason to pay the performance price for something you are not using
  • So make sure you specify only the view engines you need in your Global.asax file
         Global.asax  file Looks Like below :

      protected void Application_Start()
        {
          ViewEngines.Engines.Clear();
          ViewEngines.Engines.Add(new RazorViewEngine());//add razor view engine
        }

Tip 03 Avoid passing null ViewModels to Views

     When it Happens ?
  • You pass in a null ViewModel to a View that uses strongly-typed html helpers 
           Such as in the View :

              @model PawLoyalty.ViewModels.Product
          
      @{
                
              @Html.TextBoxFor(m => m.ProductName); 
       
       }
  • This frequently happens in Insert (Add) scenarios

    Why is it Bad ?
  • Strongly-typed html helpers like above,
  • Will try to emit the value of the ViewModel using the provided expression
  • However when something along the expression chain is null a NullReferenceException will be thrown,
  • When the expression gets evaluated,
  • MVC’s expression evaluator catches the exception
  • But on a page with multiple such html helpers the cost of the exception adds up
  • You can avoid that cost by always passing an instance of the ViewModel to the View

    Bad Way :

        [HttpGet]
        public ActionResult Add() //get empty data for user input operation
        {
            return View();  //here the model instance defaults to null
        }

    Best Way :

        [HttpGet]
        public ActionResult Add()//get empty data for user input operation
        {
          return View(new Product());//here the ViewModel Product has been sent
        }



Tip 04 Uninstall URL Rewrite if you don’t use it

  When it Happens :
  • Your IIS server has the URL Rewrite module installed
  • When you are running ASP.NET MVC 3,
  • None of the applications on the server are using it

            What is URL Rewrite ?

               #  Enables Web administrators to create powerful rules to implement URLs
               #  That are easier for users to remember and easier for search engines to find

Why is it Bad ?

  • When performing URL generation (e.g : Html.ActionLink)
  • MVC 3 checks to see if the currently requested URL has been rewritten by the URL Rewrite module
  • The act of checking need significant computing power to solve (because it involves checking server variables)
  • So if you are not using URL Rewrite you should Turn it Off (Uninstall)

                   How to Uninstall URL Rewrite ?

                       # Win 7 --> Controller Panel --> Programs and Features -->

Uninstall URL Rewrite


             Important Note :  MVC 2 always performs this check.So turning
                                         URL Rewrite off  (uninstall)  will not make a difference


Tip 05 Enabling Output Caching

    What is Output Caching ?

  • Enables you to cache the content returned by a controller action
  • The same content does not need to be generated each and every time the same controller action is invoked
  • Caching enables you to avoid performing redundant work on the Server
  • Can apply for either individual controller action or an entire controller class

   How to Do That ?

  • Using [OutputCache] attribute

    Lets take a simple Example

    public class HomeController : Controller
    {
      [OutputCache(Duration = 10, VaryByParam = "none")] //cached for 10 seconds
      public ActionResult Index()
      {
          return View();
      }
    }

   When to Use it ?
  • Read operations Only

  When Not to Use it ?
  • Writes operations.Such as Update,Delete and Inserts 
  • Pages which are User Specific.e.g. shopping cart page

Summery of Performance Gain Chart :

Performance Gain Chart

                        Pages/Sec - How many pages can load per second

                        Page Time (ms) - How long will it take to load a page

                        Base - Page that has not done any performance gain operations

Conclusion
  • You can see that highest performance gain can get by using OutputCache operation
  • But OutputCache having it's own Limitations
  • I will explain more about MVC caching in My future blog post
  • If your page is load under 1 second then you may not worry too much about performance gain

I hope this helps to You.Comments and feedback greatly appreciated.

Happy Coding.

MVC Related Articles


Monday, November 12, 2012

How to Use ValueInjecter with Asp.net MVC ViewModel ?

What is ValueInjecter ?
  • An Open Source Free product
  • It's a Mapper
  • It lets you define your own convention-based matching algorithms (ValueInjections)
  • In order to match up (inject) Source values to Destination values
  • With the ValueInjecter you inject values from the properties of source into properties of target object using ValueInjections
  • Each ValueInjection has it's own conventions of which properties to match and how to transform the value.
  • By Default maps the properties with the Same Name and Same Type
  • But you can override TypesMatch to change this from source to the ones in the target
  •                                                                                                                    
When To Use ?
  • When we need to Map Domain Model to ViewModel and Vice-versa

How to Download?
  • You can download the "Omu.ValueInjecter.dll" from CodePlex located Here

download

How to Set Reference for above .dll on Your Project ?
  • On your Web Project Add Reference to the "Omu.ValueInjecter.dll"

Add Reference

Let's Try with Simple Example

  • C# , MVC 3 and Visual Studio 2010 has been used.
  • Please Follow an Inline Comments on Code.
  • Simple application with Product Name text box,Retail Price text box and Save button.   
       
Our Simple View Looks Like below


Our Simple View


Our Domain Model Looks like below

 public class Product
    {
        public Product() { Id = Guid.NewGuid() //create Guid as Primary key }

        public Guid Id { get; set; }
        public string ProductName { get; set; }
        public decimal RetailerPrice { get; set; }
       
        public virtual Provider Provider { get; set; }
    }

Our ViewModel Looks like below

public class ProductViewModel
    {
        public Guid Id { get; set; }

        [Required(ErrorMessage = "required")]
        public string ProductName { get; set; }

        [Required(ErrorMessage = "required")]
        public decimal RetailerPrice { get; set; }
             
    }

Our Controller Looks like below

        [HttpPost]
        public ActionResult AddProduct(ProductViewModel productViewModel, string providerKey)
        {
            //get provider from repository
            var provider = Repository.GetProvider(providerKey);

            //create Product domain object
            var productObj = new Product();

            //usage of ValueInjecter
            //source object as productViewModel
            //target object as productObj
            //type 'FilterId' for keep target property 'Id' value
            //not overridden from source property 'Id' value (will explain later)
            productObj.InjectFrom<FilterId>(productViewModel);

            //If something missing then map as below
            productObj.Provider = provider;

            if (ModelState.IsValid) //check validation
            {
                //save for repository
                Repository.AddProduct(productObj);
                return RedirectToAction("AddProduct", new { providerKey = providerKey });
            }
            else
            {
                return View(productViewModel);
            }
        }

Our FilterId  Custom Class Looks like below

FilterId  Custom Class

using Omu.ValueInjecter;

namespace PawLoyalty.Web.Areas.Providers.ValueInjections
{
    public class FilterId : LoopValueInjection
    {
        //sourcePropName "Id" will not map to target property name "Id"
        //ie: Keep target property value as it is (not change from mapping)
        protected override bool UseSourceProp(string sourcePropName)
        {
            return sourcePropName  !=  "Id";
        }
    }
}

Why We Need 'FilterId' Custom Class ?

# It's a Custom class inherited from LoopValueInjection class

# On our Domain Model (Product) we have to Initialize property Id of type Guid when creates
   an object (inside a constructor) as a Primary Key.

# So After that generated Id will save on the Database at the end

# When we use productObj.InjectFrom(productViewModel) Line of code (default)
   Without <FilterId> then source object (productViewModel) will override the
   target  object's Id with value {00000000-0000-0000-0000-000000000000}.

# So for avoid such a situation we have to use FilterId Custom class as above

#  i.e When we need to keep without changing target property Id value (productObj).
          Because it is our Primary key.

What Says Creator of ValueInjecter ? - By Valentin Plamadeala

Another way of doing the FilterId injection would be like this:

Method 1:
     
public class FilterId : ConventionInjection
 {
   protected override bool Match(ConventionInfo c)
    {
      return c.SourceProp.Name != "Id" && c.SourceProp.Name == c.TargetProp.Name
             && c.SourceProp.Type == c.TargetProp.Type;
    }
 }

Method 2 :

public class IngnoreProps : ConventionInjection
    {
        private readonly string[] _ignores;

        public IngnoreProps()
        {
        }

        public IngnoreProps(params string[] ignores)
        {
            _ignores = ignores;
        }

        protected override bool Match(ConventionInfo c)
        {
            return (_ignores == null || !_ignores.Contains(c.SourceProp.Name)) &&
                   c.SourceProp.Name == c.TargetProp.Name
                   && c.SourceProp.Type == c.TargetProp.Type;
        }
    }

and use it like this:

    target.InjectFrom(new IgnoreProps("Id"), source);

Special Thanks

I must put special thanks for Valentin Plamadeala (Creator of ValueInjecter) who gave me a feedback for my Article and also put that on codeplex. Thanks Valentin.I hope you will create lots of this kind of value added components behalf of us in future also.Good Luck.


What are the Features of ValueInjecter ?
  • It's Simple and Very Flexible
  • It's something like mozilla with it's plugins, you create ValueInjections and use them
  • There are built-in injections for flattening, unflattering
  • Can use with MVC ,Win-Forms,Web-Forms,Silverlight,WPF and Data Access Situations
  • Can also use ValueInjecter to map from Anonymous and Dynamic objects
  • Valueinjecter has a default injection .InjectFrom() that does the properties with the Same Name and Same Type.
  • For everything else you can Create your Custom Valueinjections with individual mapping logic/rules, more like aspectse.g. from all properties of Type Foo to all properties of type Bar
                 What is Aspects - Aspect Oriented Programming (AOP) involves breaking down
                                               program logic into distinct parts.

Do you need to Dive Deep ends of  ValueInjecter ?
  • Documentation Here
  • Discussions  Here
  • Stackoverflow  Here

Conclusion
  • Above I have showed very simple usage of ValueInjecter Mapper
  • If you need to learn more about ValueInjecter then you have to follow above mentioned Links
  • This mapper is nicely fit with Asp.Net MVC ViewModel developments for very simple to very complex scenarios

I hope this helps to You.Comments and feedback greatly appreciated.

Happy Coding.

Related Article


Monday, November 5, 2012

How to Improve jQuery Selector Performance ?

What is a jQuery ?
  • jQuery is a lightweight, "Write Less, Do More", JavaScript library.
  • The purpose of jQuery is to make it much easier to use JavaScript on your website.
  • jQuery takes a lot of common tasks that requires many lines of JavaScript code to accomplish, and wraps it into methods that you can call with a single line of code.
  • jQuery also simplifies a lot of the complicated things from JavaScript, like AJAX calls and DOM manipulation.
                              What is a DOM ?
                                      - Document Object Model
                                      - is the Backbone of every webpage
                                      - web browser parses HTML and Javascript and maintains
                                        a Data Model of what should be displayed to the user 

The jQuery Library Contains the Following Features:
    jQuery
  • HTML/DOM manipulation
  • CSS manipulation
  • HTML event methods
  • Effects and animations
  • AJAX
  • Utilities
  • jQuery has plugins for almost any task out there.

What is a jQuery Selector?
  • A Selector identifies an HTML element tag that is used to manipulate with jQuery code. 
  • Selectors allow page elements to be selected

Selector Syntax 

$(Selector Expression)          OR      jQuery(Selector Expression)

What are the Types of jQuery Selectors?

1. Class Selectors
       $(".intro")  - All elements with class="intro"

2. ID Selectors
       $("#lastname")  - The element with id=lastname

3. Element Selectors
       $("p")   - All p elements

How to Caching jQuery Selectors ?

What is Happening When We use Selector ?
  • jQuery Traverses through all Elements of DOM every time

How Can Overcome this?
  • You should Always Cache your Selections to some variable
Its Like this :

      var myList = $('.myList');
      myList.text("cached");

When to Use ?
  • Using the Same Selection More than Once in your DOM Tree. 
  • e:g: Inside a jQuery Function Likes below
BAD Way

$(".myList").click( function() {
   $(".myList").hide(); 
});

BEST Way

var myList  = $(".myList");

myList.click( function() {
       myList.hide();  // No need to re-select .myList since we cached it
});

Performance of  jQuery Selector when Caching


Caching



More Tips for Optimizing jQuery Selector Performance :

1. Qualify your Selector strings when searching by class
       - give Selector's Context as 2nd Parameter
       - when the branches of your DOM tree become very deep 

                       What is a Context ?
                            - jQuery has an optional second argument called context
                            - Its Limit the search within a specific node
                            - Great when you have a very Large DOM tree and need to find
                             e.g: All the <p> tags within a specific part of the DOM tree
                            - You can check to see what is the context of Selector by using context
                               Property.
                              e.g:    $('p').context; //out put is => document

BAD Way

$(".your-class")

BEST Way

// get the node for the context
var context = $('#myContainer')[0];

$(".your-class", context )
                 
2. Don't Qualify your selector when searching by Id.
      - searching by Id uses the browsers native getElementById method (which is very fast)

BAD Way

$("div#your-id")

BEST Way

$("#your-id")

Performance of jQuery ID vs Class  Selectors

ID vs Class  Selectors


Conclusion
  • Always Try to use Id of a Selector when its possible
  • Always Do Caching for jQuery Selectors before it use
  • Always Use Context with class Selectors

I hope this helps to You.Comments and feedback greatly appreciated.

Happy Coding.