in

Chennai .Net User Group

A platform that enables you to Learn, Share & Grow (India's first .Net user group)

Shiju Varghese's Blog

October 2008 - Posts

  • ASP.NET MVC Tip: Dependency Injection with Unity Application Block

    In my earlier post, I have explained how to use dependency injection pattern in ASP.net MVC application using StructureMap. In this post, I demonstrate how you can use dependency injection pattern using Microsoft’s Unity Application Block (Unity). If you want to develop an ASP.NET MVC application fully with Microsoft stack, you can use Unity Application Block to perform dependency injection.Unity is a cool dependency injection container and I hope that it will become more powerful in the future releases.

    Introduction to Unity

    Unity is a lightweight, extensible dependency injection container that provides the support for constructor, property, and method call injection. Unity has a service location capability that allows the ASP.NET developer to store or cache the container in the ASP.NET session, application or per Request.

    Register Dependencies

    Unity provides two methods for registering types and mappings with the container. The RegisterType method registers a type with the container and the RegisterInstance method registers with the container an existing instance of a type.

      IUnityContainer container = new UnityContainer();
      //Register Dependencies
      container.RegisterType<ICategoryRepository, CategoryRepository>();

    The above code tells the Unity Container that, to inject the instance of CategoryService when there is a request for ICategoryService and the container will create a new instance of CategoryService every time when there is request for ICategoryService. The default behavior is for the container to use a transient lifetime manager and the container will not store or cache a reference to the object. If you want singleton behavior for objects, you have to register a LifetimeManager. A lifetime manager controls how stores references to object instances and reused within the container.

     IUnityContainer container = new UnityContainer();
     container.RegisterType<ICategoryRepository,
           CategoryRepository>(new ContainerControlledLifetimeManager());
    

    The above registration specify that any time an instance of ICategoryService is requested, you will get back the same instance of CategoryService as long as the container is alive. The container will create a new instance at the time of first request and will be use the same instance for the later requests. The ContainerControlledLifeTimeManager class provides the singleton behavior for the container.

    You can create your own custom LifetimeManager class derive from LifetimeManager class. The important methods of LifetimeManager class are GetValue that returns the instance, SetValue method store the instance value and RemoveValue method reomove the instance from the container.

    public abstract class LifetimeManager : ILifetimePolicy
    {
        public abstract object GetValue();
        public abstract void SetValue(object newValue);
        public abstract void RemoveValue();
    }

     

    Use Unity with an ASP.NET MVC application

    In this tip, I show how you can use the Unity Application Block to perform Dependency Injection within an ASP.NET MVC application.  In this tip, I will show you how to perform constructor injection. Constructor Injection will push dependencies into a concrete class through constructor arguments.

    The below code listings show that a controller class and its dependent classes.

    Listing 1 – CategoryController

    public class CategoryController : Controller {
            ICategoryService _categoryService = null;
    
            public CategoryController(ICategoryService categoryService) {
                _categoryService = categoryService;
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="page"></param>
            /// <returns></returns>
            [AcceptVerbs(HttpVerbs.Get)]
            public ActionResult List(int? page) {
                var categories = _categoryService.GetCategories(page ?? 0, 10);
                return View(categories);
            }
         }


    Listing 2 – ICategoryService

     public interface ICategoryService {
            PagedList<Category> GetCategories(int pageIndex,int pageSize);
            void Save(Category category);
            Category Read(int id);
            void Delete(int id);
        }

            
    Listing 3 – CategoryService

     public class CategoryService : ICategoryService  {
             ICategoryRepository _repository = null;
            /// <summary>
             /// Creates a CategoryService based on the passed-in repository
            /// </summary>
             /// <param name="repository">An ICategoryRepository</param>
             public CategoryService(ICategoryRepository repository) {
                _repository = repository;
                if (_repository == null)
                    throw new InvalidOperationException("Repository cannot be null");
            }
    
            public PagedList<Category> GetCategories(int pageIndex,int pageSize) { 
                return _repository.GetCategories().ToPagedList<Category>(pageIndex, pageSize); 
            }
         }

    Listing 4 – ICategoryRepository

     public interface ICategoryRepository {
            IQueryable<Category> GetCategories();
            void Save(Category category);
            void Delete(int id);
            Category Read(int id);
        }

     
    Listing 5 – CategoryRepository

    public class CategoryRepository : ICategoryRepository  {
    
           myFinanceData _db;
            public CategoryRepository(myFinanceData data) {            
                _db = data;
                
            }
    
            /// <summary>
            /// Linq To Sql implementation for Categories
            /// </summary>
            /// <returns>IQueryable of Categories</returns>
            public IQueryable<Category> GetCategories() {
    
                return from c in _db.DataContext.Categories 
                       select new Category {
                           ID=c.ID,
                           Name=c.Name,
                           Description=c.Description,
                           CategoryType = c.CategoryType
                       };
            }
    }

    Listing 6 – DBData class 

    public  class myFinanceData
        {
            private myFinanceDataContext dataContext;
    
            public myFinanceDataContext DataContext {
                get {
                    if (dataContext == null) {
                        dataContext = new myFinanceDataContext();
                    }
    
                    return dataContext;
                }
            }
        }


    Depedencies

    The CategoryController has a dependency with ICategoryService. The concrete implementation of ICategoryService, i.e. CategoryService has a dependency with ICategoryRepository. The concrete implementation of ICategoryRepository, i.e. CategoryRepository has a dependency with DBData. When we calling action methods of Category controller, we need to create objects of CategoryService, CategoryRepository and DBData.

    The below steps will configure Unity to perform constructor injection in our ASP.NET MVC application.

    Step 1 – Add reference for Unity Application Block

    Add a reference to Microsoft.Practices.Unity.dll and Microsoft.Practices.ObjectBuilder2.

    You can download Unity from http://www.codeplex.com/unity

    Step 2 – Custom LifetimeManager class

    Unity provides the functionality to specify the location of instance. This functionality is very useful for the ASP.NET applications where we can store or cache the container in the HttpContext, HttpSession or HttpApplication. In this tip, I used to store the container in current HttpContext.  In the below code, I am creating a custom lifetime manager to store container in the current HttpContext.

    using Microsoft.Practices.Unity;
    
    namespace myFinance.Web {
        public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable {
            public override object GetValue() {
                return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
            }
            public override void RemoveValue() {
                HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
            }
            public override void SetValue(object newValue) {
                HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
            }
            public void Dispose() {
                RemoveValue();
            }
        }


    Step 3 – Controller Factory for Unity

    using Microsoft.Practices.Unity;
    namespace myFinance.Web.Controllers {
        public class UnityControllerFactory : DefaultControllerFactory
        {
            IUnityContainer container;
    
            public UnityControllerFactory(IUnityContainer container)
            {
                this.container = container;
            }
    
            protected override IController GetControllerInstance(Type controllerType)
            {
                try {
                    if (controllerType == null)
                        throw new ArgumentNullException("controllerType");
    
                    if (!typeof(IController).IsAssignableFrom(controllerType))
                        throw new ArgumentException(string.Format(
                            "Type requested is not a controller: {0}", controllerType.Name),
                            "controllerType");
                    return container.Resolve(controllerType) as IController;
                }
                catch { return null; }
    
            }
        }
    }


    The controller factory is responsible for creating controller instances. We extend the built in default controller factory with our own factory for working Unity with ASP.NET MVC.


    Step 4 – Register Types and Set Controller Factory

    public static class Bootstrapper {
    
    public static void ConfigureUnityContainer() {
    IUnityContainer container = new UnityContainer();
    // Registrations
     container.RegisterType<myFinanceData, myFinanceData>
         (new HttpContextLifetimeManager<myFinanceData>());
     container.RegisterType<ICategoryRepository, CategoryRepository>
        (new HttpContextLifetimeManager<ICategoryRepository>());
     container.RegisterType<ICategoryService, CategoryService>
       (new HttpContextLifetimeManager<ICategoryService>());
     ControllerBuilder.Current.SetControllerFactory(
        new myFinance.Web.Controllers.UnityControllerFactory(container));           
      }
     }


    The above Unity configuration specified in the ConfigureUnityContainer method, tells to inject CategoryService when there is a request for ICategoryService. And also inject CategoryRepository when there is a request for ICategoryRepository. The CategoryRepository class has a dependency with DBData. So we configure that inject the instance of DBData when there is request for DBData. The above code also set the controller factory for working with Unity.

    Step 5 – Modify Global.asax.cs for configure Unity container

    protected void Application_Start() {
                RegisterRoutes(RouteTable.Routes);            
                //Configure for Unity DI
                Bootstrapper.ConfigureUnityContainer();           
                
            }

    The above code will set the configuration for the Unity container when our ASP.NET MVC application is started. The Bootstrapper class is specified in the Step 4.

    Summary

    In this tip, I demonstrated how you can use the Unity Application Block to perform Dependency Injection within an ASP.NET MVC application. The Unity Application Block allows us to develop highly loosely coupled ASP.NET MVC applications using fully with Microsoft stack.

  • ASP.NET MVC for Live Applications

    ASP.NET MVC has got big attention in the community and lot of people are looking to develop production ready applications with ASP.NET MVC. When can we start production ready applications with ASP.NET MVC? Since ASP.NET MVC Beta version is available, I think this is time to start live application with ASP.NET MVC. There is already lot of live applications build with ASP.NET MVC. Stackoverflow is really a killer web application build with ASP.NET MVC.  If you are an Architect, this is the right time to develop infrastructure frameworks for ASP.NET MVC. The RTM version will be in Q4 2008 or Q1 2009. I hope that the RTM version will be release on this December. The changes from Beta to RTM version will be very minimum and the Beta release comes with an explicit "go-live" license that allows you to deploy it in production environments. Scott Guthrie wrote in his bog post ASP.NET MVC Beta Released “Today's ASP.NET MVC Beta release comes with an explicit "go-live" license that allows you to deploy it in production environments.  The previous preview releases also allowed go-live deployments, but did so by not denying permission to deploy as opposed to explicitly granting it (which was a common source of confusion).  Today's release is clearer about this in the license. The beta release is getting close to V1 feature complete, although there are still a few more features that will be added before the final "V1" release (including several VS tooling enhancements).  The team decided to call this release a "beta", though, because the quality and testing of it is higher than the previous previews (a lot of bug fixes and performance tuning work went into it), and they feel that the core features that are in it are now "baked enough" that there won't be major changes from this release to the final product”.

    I believe that breaking changes and new features will be available after the release of V1. When I asked about the SubController infrastructure, Scott Guthrie replied that “The team currently has that penciled in for the release immediately following V1.  The reason for not having it in V1 are: 1) there are a couple of approaches that could be used for it, and we want to spend a little more time investigating and exploring them (and not bake something prematurely into V1), and 2) there is a subcontroller implementation currently in the MVCContrib project that be used with the V1 release.  I'd recommend looking at using that one if you need a subcontroller pattern, and then we'll bake one into the core binary once we feel confident on a final design”.

    Our Development Attitude

    ASP.NET MVC is a great technology and you can build powerful and highly maintainable web applications with ASP.NET MVC. But please keep in mind that you can build good and bad applications with same technology. So our attitude and development approaches are very important for building great software and the most important things is that we should have a good architecture for good software. I strongly believe that the .Net developer community should be more focus on object oriented principles and practices. I believe that the ALT.NET movement is a good sign and the ALT.NET Criterion is good for building better software. The ASP.NET MVC technology is based on a loosely coupled architecture and the framework is highly testable so that it enables to build great software. When we build applications with ASP.NET MVC, we should focus on object-oriented principles and practices and take this time to change our attitude towards object-oriented way. In the past, applications have been data-centric and this has been gradually changing to object-oriented way. I would like to suggest using an ORM for data persistence, Persistence Ignorance (PI) objects for domain layer,  Repository pattern, Inversion of Control (IoC) container for dependency injection (DI) along with your ASP.NET MVC application. And I believe that Test Driven Development (TDD) gives you lot of values to your application development process.

    Learning Resources to start applications

    Stephen Walther’s blog post A Guide to Learning ASP.NET MVC Beta 1 contains lot of links that provides to learn and develop applications with ASP.NET MVC. For validations, Emad Ibrahim’s blog post Client & Server Side Validation in ASP.NET MVC is an excellent one. For dependency injection, my blog post ASP.NET MVC Tip: Dependency Injection with StructureMap provides step by step instructions to apply dependency injection into an ASP.NET MVC application using Structuremap. My blog post ASP.NET MVC Tip: Ajax and Validations using jQuery demonstrates how we can use jQuery for Ajax and validation as well as demonstrating partial rendering using user control. Steve Sanderson's ( Author of Apress' ASP.NET MVC Book) Blog is damn worth to read. And I strongly recommend to visit Rob Conery’s blog for his storefront series.  He has been building an entire ecommerce application with ASP.NET MVC
     

  • ASP.NET MVC Beta Released

    Microsoft has released the official beta for ASP.NET MVC. You can download the Beta version from here.  The Beta installer installs the ASP.NET MVC assemblies (System.Web.Mvc.dll, System.Web.Routing.dll, and System.Web.Abstractions.dll) into the GAC. In previous previews, these were not installed into the GAC. Because of this change, the default project templates do not automatically copy the assembly into the Bin directory of your application.

    If you haven't looked at ASP.NET MVC before, this is the time to start to learn ASP.NET MVC.  Below are some of my previous articles.

    ASP.net MVC Vs ASP.net Web Form

    ASP.NET MVC Grid View using MVCContrib

    ASP.NET MVC Tip: Ajax and Validations using jQuery

     ASP.NET MVC Tip: Dependency Injection with StructureMap

     

  • Kerala Microsoft Users Group (K-MUG) Launch on 25th Oct 2008

    Please visit K-Mug site for more details.

  • ASP.NET MVC Tip: Dependency Injection with StructureMap

    In this tip, I demonstrate how you can use the dependency injection with StructureMap within an MVC application. StructureMap is an open source Dependency Injection framework for the .NET platform and has been in use since 2004 .StructureMap supports both setter and constructor injection and also offers testing and diagnostic features such as logging, tracing and wiring of mock objects. For download and more details visit http://structuremap.sourceforge.net/default.htm. Jeremy D Miller’s (Creator of StructureMap) blog is a great learning resource for StructureMap and good object oriented programming thoughts.

     

    If you are not familiar with Dependency Injection (DI) and Inversion of Control (IoC), read Martin Fowler’s article Inversion of Control Containers and the Dependency Injection pattern . A Dependency Injection framework injects the dependencies into a class when the dependencies are needed. Dependency Injection enables looser coupling between classes and their dependencies and can be improve architectural qualities of an object oriented business application.

     

    Dependency Injection provides the following advantages,

     

    1) Enables looser coupling between classes and their dependencies

    2) It provides better testability of an application

    3) It removes the need for clients to know about their dependencies and how to   create them.

    4) It avoid behind the problems of creating factory classes, by moving construction responsibility to a framework.

    5) Improve the architecture quality of an object oriented system.

     

    In this tip, I show how you can use the StructureMap to perform Dependency Injection within an ASP.NET MVC application.  In this tip, I will show you how to perform constructor injection. Constructor Injection will push dependencies into a concrete class through constructor arguments.

     

    The below code listings show that a controller class and its dependent classes.

     

     

    Listing 1 – CategoryController

     

    public class CategoryController : Controller {

     ICategoryService  _categoryService = null;

     

     public CategoryController(ICategoryService categoryService) {         

        _categoryService = categoryService;

       }       

     public ActionResult List(int? page) {

      var categories = _categoryService.GetCategories(page ?? 0, 10);

        return View("CategoryList",categories);

      }


     

    Listing 2 – ICategoryService

     

    public interface ICategoryService {

      PagedList<Category> GetCategories(int pageIndex,int pageSize);       

     }

                                   

    Listing 3 – CategoryService

     

    public class CategoryService : ICategoryService  {

     ICategoryRepository _repository = null;       

     public CategoryService(ICategoryRepository repository) {

         _repository = repository;

         if (_repository == null) {

             throw new InvalidOperationException("Repository cannot be null");

            }

    public PagedList<Category> GetCategories(int pageIndex,int pageSize) {

        return _repository.GetCategories().ToPagedList<Category>(pageIndex, pageSize);

            }

        }

     

    Listing 4 – ICategoryRepository

     

    public interface ICategoryRepository {

          IQueryable<Category> GetCategories();

        }

     

    Normal 0 false false false /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    Listing 5 – CategoryRepository

     

    public class CategoryRepository : ICategoryRepository  {

      DBDataContext _db;

      public CategoryRepository(DBDataContext dataContext) {           

         _db = dataContext;           

       }

           

     public IQueryable<Category> GetCategories() {

        return from c in _db.Categories

          select new Category {

            ID=c.ID,

            Name=c.Name,

            Description=c.Description,

            CategoryType = c.CategoryType

          };

         }

        }

     

    Depedencies

     

    The CategoryController has a dependency with ICategoryService. The concrete implementation of ICategoryService, i.e. CategoryService has a dependency with ICategoryRepository. The concrete implementation of ICategoryRepository, i.e. CategoryRepository has a dependency with DBDataContext. When we calling action methods of Category controller, we need to create objects CategoryService, CategoryRepository and DBDataContext.

     

    The below steps will configure StructureMap to perform constructor injection in our ASP.NET MVC application.

     

    Step 1 – Add reference to StructureMap

     

    Add a reference to StructureMap.dll.

    Download available from http://sourceforge.net/projects/structuremap/

     

    Step 2 – Add StructureMap configuration

     

    using StructureMap;

    using StructureMap.Configuration.DSL;

    using StructureMap.Configuration;

    using StructureMap.Pipeline;

     

    public class DomainRegistry : Registry {

       protected override void configure() {

        ForRequestedType<ICategoryService>()

           .TheDefaultIsConcreteType<CategoryService>();

       ForRequestedType<ICategoryRepository>()

          .TheDefaultIsConcreteType<CategoryRepository>();

            }

        }

     

    public class DBServiceRegistry:Registry {

      protected override void configure() {

         ForRequestedType<DBDataContext >()

          .TheDefaultIs(() => new DBDataContext())

            .CacheBy(InstanceScope.Hybrid);

            }

        }

     

    The above configuration tells StructureMap to inject CategoryService when there is a request for ICategoryService. And also inject CategoryRepository when there is a request for ICategoryRepository. The CategoryRepository class has a dependency with Linq DataContext DBDataContext. So we configure that create a new instance DBDataContext when there is request for DBDataContext. we are telling the StructureMapConfiguration to make hybrid instance scope. The below are the different type of instance scoping,

     

       1. PerRequest - The default operation.  A new instance will be created for each request.

       2. Singleton - A single instance will be shared across all requests

       3. ThreadLocal - A single instance will be created for each requesting thread.  Caches the instances with ThreadLocalStorage.

       4. HttpContext - A single instance will be created for each HttpContext.  Caches the instances in the HttpContext.Items collection.

       5. Hybrid - Uses HttpContext storage if it exists, otherwise uses ThreadLocal storage

     

    Step 3 – Register with StructureMap registry

     

    The below code will add instances of DomainRegistry and DBServiceRegistry into StructureMapConfiguration registry.

     

    using StructureMap;

    public static class Bootstrapper {

     public static void ConfigureStructureMap() {

       StructureMapConfiguration.AddRegistry(new DBServiceRegistry());

       StructureMapConfiguration.AddRegistry(new DomainRegistry ());

      }

     }

     

    Step 4 – Controller Factory for StructureMap

     

    using StructureMap;

    public class StructureMapControllerFactory : DefaultControllerFactory {

      protected override IController GetControllerInstance(Type controllerType) {

       try {

          return ObjectFactory.GetInstance(controllerType) as Controller;

        }

    catch (StructureMapException) {

         System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());

          throw;

       }

      }

     

     

    The controller factory is responsible for creating controller instances. We extend the built in default controller factory with our own factory for working StructureMap with ASP.NET MVC .

     

    Step 5 – Modify Global.asax.cs

     

    protected void Application_Start() {

      RegisterRoutes(RouteTable.Routes);

       //Configure StructureMapConfiguration

       Bootstrapper.ConfigureStructureMap();

        //Set current Controller factory as StructureMapControllerFactory

        ControllerBuilder.Current.SetControllerFactory( new myFinance.Web.Controllers.StructureMapControllerFactory()

       );

     }

     

    The above code will set our controller factory and configure StructureMap configuration when our ASP.NET MVC application is started.

     

    Summary

     

    In this tip, I demonstrated how you can use the StructureMap to perform Dependency Injection through constructor injection within an ASP.NET MVC application. One of the greatest advantages of ASP.NET MVC is testability. With a Dependency Injection framework, we can make our ASP.NET MVC application is fully testable and maintainable.


  • ASP.NET MVC Tip: Ajax and Validations using jQuery

    jQuery is now part of the ASP.net development platform and it is going to ship with Visual Studio in the future and will also be the part of ASP.NET MVC installation. ASP.NET MVC will be the first product to include jQuery. Guru Gu’s blog entry has the full details regarding this. This is a great decision from Microsoft and I hope that the community would be happy about the great decision taken by Microsoft. And this is another good step for web development after the ASP.NET MVC technology. jQuery is an excellent java script library and very popular among the web developers regardless of technology. In this post, I demonstrate how to integrate jQuery with ASP.NET MVC and will be explain how to send Ajax requests and also show client side validation using jQuery. I am using a blog application for this demo and it will show how to post a comment of a blog entry using Ajax request and will also show partial rendering with the help of a user control.

    The below is the class diagram of the example I have used for this demo.  

     

    Controller

    The below is the code of BlogController. It has two action methods and first one is for getting the single blog post including all comments and another action is for post a comment for the particular blog post. I am going to call the AddComment method ( ActionName Post) using Ajax request using jQuery.

    Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    public class BlogController : Controller{

    private readonly ICommentRepository comments =new CommentRepository();

    private readonly IPostRepository posts = new PostRepository();


    [AcceptVerbs( "GET" )] 

    public ActionResult Post( int id )

    {

     return View( posts.Retrieve().Where( p => p.ID == id ).Single() );

     }


    [AcceptVerbs( "POST" )]

    [ActionName( "Post" )] 

    public ActionResult AddComment( int postId, string commentAuthor, string commentText )  {  

    var comment = new Comment{

    PostID = postId

    Author = commentAuthor

    Text = commentText,    

    DatePosted = DateTime.Now

    };

    try {  

          comments.Create( comment );

          return View("PostComment", comment);   

        } 

    catch( Exception  ex

      {  

        throw ex;   

      }  

    }


    View

    Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    <asp:Content ID="content" ContentPlaceHolderID="MainContent" runat="server">

    <h2>

    <% =Html.ActionLink( ViewData.Model.Title,"Post",

    new { id = ViewData.Model.ID } )%>

    </h2>

    <div>Posted by <strong><% =ViewData.Model.Author%>

    </strong> on <strong><% =ViewData.Model.DatePosted%></strong>

    </div>

    <p>

    <% =ViewData.Model.Text.Replace( "\n", "<br />" )%>

    </p>

    <h3>Comments</h3>

    <div id="post_comment">

    <% if( ViewData.Model.Comments.Count > 0 )

    { %>

    <%foreach( var comment in ViewData.Model.Comments )

    { %>  

     <% Html.RenderPartial("PostComment", comment); %>

     <% } %> 

    <% } %>

    </div><form id="new_comment" action="/Blog/Post" method="post">

    <input type="hidden" name="postId" id="postId" value="<% =ViewData.Model.ID%>" />

    <img id="ajaxLoader" src="../../Content/ajax-loader.gif"/>

    <fieldset> 

     <legend>Add Comment</legend>

      <ul><li>  

        <label for="author"><span class="required">Name: </span></label>

        <input id="commentAuthor" class="text required" name="commentAuthor" type="text" value="" />   

      </li> <li>

    <label for="text"><span class="required">Comment: </span></label> 

    <textarea cols="20" id="commentText" class="text required" name="commentText" rows="2"></textarea>

     </li> </ul></fieldset>

      <input type="submit" value="Add" />

      </form> </asp:Content>

    Displaying the comments

    Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    <% if( ViewData.Model.Comments.Count > 0 )

    { %>

    <%foreach( var comment in ViewData.Model.Comments )

    { %>  

     <% Html.RenderPartial("PostComment", comment); %>

     <% } %> 

    <% } %>

     

    The above code iterating through Comments collection of our ViewData and also calling the PostComment user control with comment object as ViewData for displaying a single comment.  This user control is also using for partial rendering when we send Ajax request.

     PostComment.ascx Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    <u><% =ViewData.Model.Author%> commented on

    <% =ViewData.Model.DatePosted%>:</u><p>

    <% =ViewData.Model.Text%></p

     

    Normal 0 false false false MicrosoftInternetExplorer4 st1\:*{behavior:url(#ieooui) } /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    Client Side Validation

     For client side validation, I am using jQuery Validation plugin. For more details about the jQuery plugin, visit http://bassistance.de/jquery-plugins/jquery-plugin-validation/ . This validation framework is very easy to use. You just put class="text required" for a required field validator. For an email validation, you need to put class="text email".  

    <input id="commentAuthor" class="text required" name="commentAuthor" type="text" value="" />

    <textarea cols="20" id="commentText" class="text required" name="commentText" rows="2"></textarea> 

    The validation process will be working with the jQuery method validate of form object.

    $(function() {

    // for highlight

    var elements = $("input[type!='submit'], textarea, select");

    elements.focus(function(){

    $(this).parents('li').addClass('highlight');

    });

    elements.blur(function()

    {

    $(this).parents('li').removeClass('highlight');

    });  

    $("#new_comment").validate() // for validation

    });

    You can optionally add validation rules along with validate method. The below code added validation rules included with validate method of form object.

    Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} Normal 0 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:"Table Normal"; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0in 5.4pt 0in 5.4pt; mso-para-margin:0in; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}

    $("#new_comment").validate({

                  rules: {

                        

                         commentText: "required",

                         commentAuthor: {

                               required: true,

                               minlength: 2

                         },                  

                         email: {

                               required: true,

                               email: true

                         }

                  },

                  messages: {

                    commentText: "Please enter Comment"                 

                    commentAuthor: {

                         required: "Please enter your Name"

                         minlength: "Your Name must consist of at least 2 characters"                                },                  

                         email: " Please enter a valid email address”

                  }

           });

    jQuery includes

    <script type="text/javascript" src="../../Content/jquery-1.2.5.min.js"></script>

    <script src="../../Content/jquery.validate.js" type="text/javascript"></script>

     Ajxa using jQuery 

    $(document).ready(function() { 

    $("#ajaxLoader").hide();

    $("#new_comment").submit(function()

      addComment(this);

       return false;  

    });

    });

    jQuery method $(document).ready() will executes when the DOM has been loaded and in this function we handles the onsubmit event of the form. In the onsubmit event, we calling the addComment function and then the return false statement prevent the form submit and we submit the form post using Ajax.

    addComment function

    function addComment(form)

    {

    $("#ajaxLoader").show(); 

    $.ajax(

    {type: form.method,

    url: form.action,

    data: $(form).serialize(),// Form data

    dataType: "html",

    completed: $("#ajaxLoader").hide(),

    success: function(result)  

    var domObj = $(result); // create element from result html                 $("#post_comment").append(domObj); // append to end of comment list 

    }, 

    error: function(error

      alert(error);  

    });    

    The above code sends the form data to the controller action Post using Ajax . The dataType: "html" represent that we want partial HTML result for our Ajax request.  In the success function of our Ajax request, we append the result HTML to the <div> element named post_comment. This will dynamically add the new comment to the end of the comment list. 

    success: function(result)

    {  

     var domObj = $(result);// create element from result html                 $("#post_comment").append(domObj); // append to end of comment list 

    }

    Controller Action

    [AcceptVerbs( "POST" )]

    [ActionName( "Post" )] 

    public ActionResult AddComment( int postId, string commentAuthor, string commentText )  {  

    var comment = new Comment{

    PostID = postId

    Author = commentAuthor

    Text = commentText,    

    DatePosted = DateTime.Now

    };

    try {  

          comments.Create( comment );

          return View("PostComment", comment);   

        } 

    catch( Exception  ex

      {  

        throw ex;   

      }  

    }

     }

    Our Ajax request will call the AddComment method and this will create a new comment for the given Post. After the data persist, we calling the  return View("PostComment", comment). PostComment is our user control with new added comment object as the model of our View. So that the user control will generates markup for the new comment and our Ajax request will get the output as the HTML that rendered by the user control. So we can dynamically add the new markup to the HTML element of our post comment list. User control is very powerful technique for partial rendering. You can download the jQuery from http://docs.jquery.com/Downloading_jQuery and jQuery validation pugin from http://bassistance.de/jquery-plugins/jquery-plugin-validation. You can read Rick Strahl’s excellent article about jQuery from here.

     

    Update : You can download the source code from MVCjQuery.zip

Copyright © 2002-2008 Chennai .Net User Group. All Rights Reserved. Microsoft and Microsoft logo's are trademarks of Microsoft Corporation