208

Everytime I'm looking for AutoMapper stuff on StackOverflow, I'm reading something about ValueInjecter.

Can somebody tell me the pros and cons between them (performance, features, API usage, extensibility, testing) ?

Rookian
  • 19,841
  • 28
  • 110
  • 180
  • 2
    Another one I see mentioned a lot is [EmitMapper](http://emitmapper.codeplex.com/). – adrianbanks Jan 12 '11 at 00:50
  • 1
    What about glue? http://glue.codeplex.com/ Looks like a great project as well, but I haven't tried it yet. I will during the next month though. I've also seen a project called EmitMapper http://emitmapper.codeplex.com/ – Trygve Apr 27 '11 at 20:20
  • See an article speaking about those two tools - http://devproconnections.com/development/two-great-solutions-object-mapping?NL=4S3A_News_DPC_UPDATE-ASP.NET_issue090414%20-%20Batch&E_ID=7710159&NLL=5209 – George Birbilis Sep 04 '14 at 22:04

4 Answers4

170

as the creator of ValueInjecter, I can tell you that I did it because I wanted something simple and very flexible

I really don't like writing much or writing lots of monkey code like:

Prop1.Ignore, Prop2.Ignore etc.
CreateMap<Foo,Bar>(); CreateMap<Tomato, Potato>(); etc.

ValueInjecter is something like mozilla with it's plugins, you create ValueInjections and use them

there are built-in injections for flattening, unflattening, and some that are intended to be inherited

and it works more in an aspect type of way, you don't have to specify all properties 1-to-1, instead you do something like:

take all the int properties from source which name ends with "Id", transform the value and set each to a property in the source object with same name without the Id suffix and it's type is inherited from Entity, stuff like that

so one obvious difference, ValueInjecter is used even in windows forms with flattening and unflattening, that's how flexible it is

(mapping from object to form controls and back)

Automapper, not usable in windows forms, no unflatenning, but it has good stuff like collections mapping, so in case you need it with ValueInjecter you just do something like:

foos.Select(o => new Bar().InjectFrom(o));

you can also use ValueInjecter to map from anonymous and dynamic objects

differences:

  • automapper create configuration for each mapping possibility CreateMap()

  • valueinjecter inject from any object to any object (there are also cases when you inject from object to valuetype)

  • automapper has flattening built it, and only for simple types or from same type, and it doesn't has unflattening

  • valueinjecter only if you need it you do target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> and if you want from Foo.Bar.Name of type String to FooBarName of type Class1 you inherit FlatLoopValueInjection and specify this

  • automapper maps properties with same name by default and for the rest you have to specify one by one, and do stuff like Prop1.Ignore(), Prop2.Ignore() etc.

  • valueinjecter has a default injection .InjectFrom() that does the properties with the same name and type; for everything else you create your custom valueinjections with individual mapping logic/rules, more like aspects, e.g. from all props of Type Foo to all props of type Bar

Omu
  • 69,856
  • 92
  • 277
  • 407
  • 5
    For the love god please tell me ValueInjector can take a deep graph ViewModel and map to/from a deep graph Business Entity and map everything that is exactly the same with no work, and that I only need to specify how to handle whats different. I've been hoping AutoMapper would add this capability but it has never materialized and I haven't had the time to write my own auto mapper. – Chris Marisic Jan 12 '11 at 20:48
  • 3
    @Chris Marisic you can use it do it, in case you mean deep cloning, I did one injection once that kinda does this recursively but doesn't work for collections properties http://valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126, or you can do a Flat ViewModel and use the flattening and unflattening, this would be easy – Omu Jan 12 '11 at 20:51
  • The ViewModel and Domain Entities would be similar but different, so not a pure clone. 90% of properties are usually exact type and name, ViewModels frequently end up with SelectLists and stuff bound to them that I would want to ignore coming back to the domain. Both are very likely to have collections of objects on them though. – Chris Marisic Jan 12 '11 at 21:00
  • @Chris Marisic there is a lot of this kind of stuff shown in the demos asp.net mvc demo, and unit tests, download it, play a bit with them and you will see how easy this is – Omu Jan 12 '11 at 21:03
  • I like the aspect way ;) But is this really only possible with ValueInjecter :o? – Rookian Jan 13 '11 at 20:24
  • @Rookian well yes, unless automapper can do something like that, but I don't know that, maybe Jimmy will answer this question – Omu Jan 13 '11 at 20:38
  • @Omu, ya that would be very interessting if he would so – Rookian Jan 13 '11 at 21:53
  • @Omu what can you say about tesing or how to know that the destination object will be correctly filled? – Rookian Jan 27 '11 at 17:34
  • @Rookian most of the time it's just obvious(always for me), but you can write a unit,a test and ensure it, automapper has a method that you can put in a unit test and ensure that your mapping configs are correct, like that you didn't forgot to specify some required configuration etc (vi doesn't require config so no method :) ) – Omu Jan 27 '11 at 18:04
  • 27
    `` Looks cool, but perhaps it should be ValueInjectOr? `` – Craig Stuntz Mar 01 '11 at 14:03
  • 1
    but for some reason it's er :) – Omu Mar 29 '11 at 07:12
  • Isn't it actually: foos.Select(o => (Bar) new Bar().InjectFrom(o)); Since the signiture is object InjectFrom(this object target, object source); An possible improvement to eliminate the need for casting would be TTarget InjectFrom(this TTarget target, object source) where TTarget : class; – Danny Varod Apr 06 '11 at 22:35
  • @Danny depending on the context it could be lots of different stuff – Omu Apr 07 '11 at 06:21
  • how do you map from one list to another list using valueinjecter? – user20358 Nov 30 '12 at 10:47
  • @user20358 you use a foreach and do InjectFrom for every single object in the list – Omu Nov 30 '12 at 19:08
  • Thanks Chuck. That is what I am doing right now. is something like this planned for the future? where I wont have to iterate through each item in the list. At the moment I am writing a data layer and I want to be able to assign the results of my 'var records = {some linQ query}.ToList()' straight away to a matching custom dtoListObject. something like dtoListObject.InjectFrom(records); Any suggestions other than what you said above? – user20358 Dec 01 '12 at 07:35
  • @user20358 you can always have your own custom class or some methods in a Utils class that do some custom mapping or add features that you need – Omu Dec 03 '12 at 09:25
  • Does VulueInjecter has anything parallel to Queryable projection support in Automapper? – Iravanchi Aug 11 '14 at 10:46
  • I'm currently looking at which one to use, one thing that I can straight away see which might be relevant is AutoMapper looks like it is being updated on a regular basis wheras ValueInjecter has not been updated for nearly 3 years on NuGet – JsonStatham Feb 05 '15 at 09:33
59

Since I've never used any of the other tools, I can only talk about AutoMapper. I had a few goals in mind for building AutoMapper:

  • Support flattening to dumb DTO objects
  • Support obvious scenarios out of the box (collections, enumerations etc.)
  • Be able to easily verify mappings in a test
  • Allow for edge cases for resolving values from other places (custom type->type mapping, individual member mapping, and some really crazy edge cases).

If you want to do these things, AutoMapper works very well for you. Things AutoMapper doesn't do well are:

  • Filling existing objects
  • Unflattening

The reason being I've never needed to do these things. For the most part, our entities don't have setters, don't expose collections, etc. so that's why it's not there. We use AutoMapper to flatten to DTOs and map from UI models to command messages and the like. That's where it works really, really well for us.

Jimmy Bogard
  • 26,045
  • 5
  • 74
  • 69
  • 1
    @Jimmy Bogard Do you see that Filling existing objects would ever make it to the feature list for AutoMapper? – Roman Aug 08 '11 at 04:40
  • I haven't tried ValueInjecter, but for what we've needed, automapper is very powerful. – richb01 May 03 '12 at 18:22
  • I think the most important thing here is the verifiability. When renaming and refactoring things this is a huge help. – Kugel Feb 13 '14 at 01:24
54

I tried both and prefer ValueInjecter because it's so simple:

myObject.InjectFrom(otherObject);

That's all there is to know for the vast majority of my injection needs. It can't possibly get more simple and elegant than this.

Adrian Grigore
  • 33,034
  • 36
  • 130
  • 210
  • 1
    `this object` extension method there? – Chris Marisic Jan 13 '11 at 13:30
  • 2
    How could I decouple my code from ValueInjecter? For me it seems like to have always a depedency to ValueInjecter i.e. in my web project, because I use ValueInjecter (extension method) on the given object DIRECTLY. – Rookian Jan 13 '11 at 20:22
  • @Rookian you could also use the IValueInjecter interface instead of the static extension, and do injecter.Inject(myObject, otherObject) http://valueinjecter.codeplex.com/documentation – Omu Jan 13 '11 at 20:40
  • 1
    @Rookian honestly this isn't a concern you should place too much thought into. You could depend on the interface like @Omu mentioned so if you ever change mappers you might save some work (probably not much). This type of a dependency is just too hard to abstract away unless you want to get into full blown AOP which is unfortunately many times just undoable since .NET doesn't help provide AOP support correctly. Now you could AOP away some of the mapping, especially if you use MVC and write Action Filters that handle ViewModel / DomainModel mapping. – Chris Marisic Jan 13 '11 at 20:58
  • @Rookian you can also create your own mapper class as a wrapper for injecting stuff – Omu Jan 14 '11 at 07:39
  • yes a wrapper would be the best option in my opinion – Rookian Jan 21 '11 at 19:35
  • 13
    why is a wrapper the best solution? The only thing you need to do if you want to switch mapper is to implement the `InjectFrom()` extension method by yourself. – jgauffin Mar 23 '11 at 08:18
  • @jgauffin yes, this is also a good option :) – Rookian Mar 28 '11 at 19:00
  • 1
    I have tried both as well and I do prefer AutoMapper. I used it for a small part of my system where I map Entities with Linq2Sql generated classes. Simple mapping as StockTotalQuantity -> stock_size_quantity or UserId -> user_id did work with AutoMapper by default. It didn't work with ValeInjecter even after adding convetion. Sticking to AutoMapper for now. – Artur Kedzior Jan 11 '12 at 14:59
27

This is a question I've been researching too, and for my use case, it seems to be valueinjecter hands down. It requires no prior setup to use (may hit performance I guess, although if smartly implemented it could cache the mappings for future invocations rather than reflecting each time), so you don't need to predefine any mappings before using them.

Most importantly however, it allows reverse mapping. Now I may be missing something here as Jimmy mentions that he sees no use case where its necessary, so maybe I have the pattern wrong, but my use case is that I'm creating a ViewModel object from my ORM. I then display this on my webpage. Once the user finishes I get the ViewModel back in as a httppost, how does this get converted back to the original ORM classes? I'd love to know the pattern with automapper. With ValueInjector it is trivial, and it will even unflatten. e.g Creating a new entity

The model created by the entityframework (model first):

public partial class Family
{ 
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public virtual Address Address { get; set; }
}

public partial class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string TownCity { get; set; }
    public string County { get; set; }
    public string Postcode { get; set; }

    public virtual Family Family { get; set; }
}

The ViewModel (which I can decorate with validators):

public class FamilyViewModel
{
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public int AddressId { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressTownCity { get; set; }
    public string AddressCounty { get; set; }
    public string AddressPostcode { get; set; }
}

The ViewController:

    //
    // GET: /Family/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Family/Create

    [HttpPost]
    public ActionResult Create(FamilyViewModel familyViewModel)
    {
        try
        {
            Family family = new Family();
            family.InjectFrom<UnflatLoopValueInjection>(familyViewModel);
            db.Families.Add(family);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

To my mind, it doesn't get much simpler than that?

(So this begs the question, whats wrong with the pattern that I run into this (and it seems many others do to), that its not seen as of value to AutoMapper?)

However, if this pattern as decscribed, is one you want to use, then my vote is valueinjecter by a country mile.

DanH
  • 3,772
  • 2
  • 27
  • 31
  • 1
    probably you should also ask this in a separate question tagged with asp.net-mvc and best-practices, ViewModel ..., atm I don't see any problem as long as it works well for you, but I'm sure that somebody might have different opinions – Omu Apr 15 '11 at 08:01
  • Well having learnt more mvc. I can now answer my question. The way to update the original model when you get a populated view model back, is to use the UpdateModel() function mvc provides. – DanH Jun 06 '11 at 10:02
  • 1
    UpdateModel() is used to populate the Model that represents the view, and is the same as doing Action(MyModelClasss model) – Omu Jun 06 '11 at 12:49
  • True, but if you want to have a seperate view model to for example a respository model, then it can be used to populate that assuming the mapping is trivial (and it often is). Of course if more complex ValueInjector comes into its own. – DanH Jun 25 '11 at 02:25
  • I think the solution that I am about to propose may not belong this thread. However here's what I would do. I would delegate this job to the business services. So the MVC knows nothing about Data Model it only knows about Domain Model. The business services talks to both data model and domain model and do the unidirectional conversions using the Automapper or ValueInjector or your own custom mapper. – activebiz Jul 11 '11 at 08:30
  • 1
    I think the argument could be made that you shouldn't simply set your properties back on your domain model - you should use methods that add meaning to it. – Mike Cole Dec 23 '11 at 04:31
  • Have to say that I've moved away from this injection pattern as I built out the tiers of my web app. So mostly using methods to change data in the backend rather than passing around objects. This may be a result of not using an ORM though... – DanH Jan 03 '12 at 17:08
  • @DanH - I think your 2nd paragrah and initial sentiment holds true regardless of the UpdateModel method if your underlying there are more than 1 underlying model class comprising your ViewModel correct? – atconway Aug 02 '12 at 18:57
  • Sure it's valid if it fits your use case. Mostly I find projection for removing fields I don't want to send to the client or compositing up data, and if going Json style then these days I find I'm using linq to select into an anon class unless it would be reused in multiple places. When round tripping data back to the server it's normally a simpler model anyway, e.g. A form rather than a complex page model coming back. So the update model/inbound binding approach is normally up to the task. – DanH Aug 03 '12 at 00:06