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


13 comments:

  1. NIce blog youhave !!!! use this plugin for coding http://dedunu.info/2012/09/24/live-writer-and-t-sql/ it will nice to your blog!!!!

    ReplyDelete
    Replies
    1. Hi Dedunu,

      Yes sure.I will try and let you know.
      Thanks for your feedback.

      Delete
  2. Hello,

    Why you don't use standard mappers like AutoMapper or AutoMapper? With profit can give your own mapper?

    -Oleg Maslovsky-

    ReplyDelete
    Replies
    1. Hi Oleg,

      I am new to the Mapper world.But I did R&D about mappers and then I have decided to use ValueInjecter as my mapping tools because of below mentioned reasons

      1. Its very simple and flexible (easy to customize)

      2. there are built-in injections
      for flattening,unflattering, and some that
      are intended to be inherited and it works
      more in an aspect type (AOP) of way

      3. ValueInjecter is used even in windows
      forms with flattening and unflattering

      > Those are the interesting points I have notice
      about ValueInjecter.
      > Some of them cannot do by using
      Auto mapper(e.g.unflattering)

      > And also ValueInjecter has been introduced
      new Injection as for Maximum performance
      with the SmartConventionInjection.

      > You can get those details from here :

      http://valueinjecter.codeplex.com/wikipage? title=SmartConventionInjection


      Delete
  3. like this.

    -Mesut Darvishian-

    ReplyDelete
    Replies
    1. Hi Mesut,

      Thanks for your response.
      Do Keep in Touch.

      Delete
  4. like this.

    -Peter Ernst-

    ReplyDelete
    Replies
    1. Hi Peter,

      Thanks for your feedback.
      Do Keep in Touch.

      Delete
  5. Hi,

    Excellent article, crystal clear explanations.

    I am new to AutoMapper and ValueInjecter.

    In my project I am handling this same scenario by using extension methods.
    But that method is more restricted one not having more features. Simply it will convert the properties from source to destination(Name and data type should be same).

    Below I mentioned the code snippet.

    public static D ConvertToAsChild(this S source, D Destination)
    {
    foreach (PropertyInfo item in source.GetType().GetProperties())
    {
    if (Destination.GetType().GetProperty(item.Name) != null &&
    Destination.GetType().GetProperty(item.Name).PropertyType.IsAssignableFrom(item.PropertyType))
    {
    Destination.GetType().GetProperty(item.Name).SetValue(Destination, item.GetValue(source, null), null);
    }
    }

    return Destination;
    }

    Surely I will explore and implement this tools in my project.

    Thanks to author.

    ReplyDelete
    Replies
    1. - Added -
      public static D ConvertTo(this T source, D Destination)
      {
      foreach (PropertyInfo item in Destination.GetType().GetProperties())
      {
      item.SetValue(Destination, source.GetType().GetProperty(item.Name).GetValue(source, null), null);
      }

      return Destination;
      }

      Delete
    2. Hi Mukesh,

      Thanks for your appreciation.

      Yes Actually you can use ValueInjecter for your project also.It's very simple and easy to customize.
      You can get lot of details by using above mentioned links
      on my article.

      They have introduced very high performance new injecter also.Please Check below mentioned link for more details.

      # Maximum performance with the SmartConventionInjection

      http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection&referringTitle=Home

      Delete
  6. --- Via G+ ---

    Good Article machan. I have use auto mapper before seems value injector much better than auto mapper. How is your experience with value injector. have u been use this in commercial project.

    -Mahesh Milinda-

    ReplyDelete
    Replies
    1. Hi Mahesh,

      Yep, ValueInjector is much better than the Auto mapper.But in my projects I have not used any of the Mapper Tools yet.I did this article as a R&D project.So I would like to recommend VI for your next project.Hence It's very easy to learn and also will give better performances.

      Delete

Thanks for your Feedback.