Reputation: 7448
First of all, I've already scoured the web and SO for a solution, couldn't find anything.
I'm working on a highly decoupled solution, with all classes designed for a DI approach (asking interfaces as dependencies of course). We use Automapper in the MVC layer to transform server side POCOs in the flattened ViewModels. So far nothing strange.
The complexity is given by the fact that some properties of the ViewModels must be created using some services that are registered in the IoC container (ninject) and are not available during application start, where automapper is configured. Telling automapper what method to use to resolve types was easy, just one line of configuration as per documentation.
For simple cases, where a single property needs this behaviour, we create a custom ValueResolver for that property, expose the dependencies in the constructor and use them to return the desired value.
The problem arises when we have, let's say, 20 properties which need the same behaviour, but different output values, while all other ViewModel properties are fine with the default "automapping".
I can't find a way to tell automapper "to resolve those properties, use this class, for all the others just use your convention".
I tried several approaches, including putting the desired properties on an interface and then use Inheritance mapping as described on the wiki. It works as long as I don't use a TypeConverter, which is pointless, because I need it (or something like it) to get the services needed through DI/IoC.
An example:
public interface IMyInterface
{
string MyUrl1 {get;set;}
//snip with many other urls
}
public class MyViewModel : IMyInterface
{
public string MyUrl1 {get;set;}
//snip with many other urls
public string MyAutomapperProperty1 {get;set;}
//snip with many other properties where I want to use the conventions
}
What I need is something like this
public class MyTypeConverter : TypeConverter<MyPoco, IMyInterface>
{
// here in the overridden method return an instance of MyViewModel
// with just the properties exposed by the interface
}
Then in automapper config:
Automapper.CreateMap<MyPoco, IMyInterface>()
.Include<MyPoco, MyViewModel>()
.ConvertUsing<MyTypeConverter>();
Automapper.CreateMap<MyPoco, MyViewModel>();
This doesn't work. If I remove the call to ConvertUsing and add inline mappings with the ForMember method everything works, and the ForMember declarations are correctly inherited by the second mapping, but just not the ConvertUsing. But I can't have DI with the ForMember method (as I am in the application start, which is static, plus that would mean to instantiate those object at application level and keep them alive for all the application, instead of creating and disposing them when needed).
I know a solution is putting the related properties in a separate object and create a TypeConverter straight for that object and use it, but refactoring of those POCOs is not an option right now, and besides, it seems strange there isn't a way to make inheritance and DI work together.
Hoping that someone can help me out, thanks for reading.
UPDATE As requested, I'll try to be more clear as what I want to achieve.
We have some "services", known at application level only through their interfaces. Something like:
public interface IUrlResolver { }
Which exposes a bunch of methods to get URLs related to our application, based on some parameters that we pass, and other stuff. The implementation might as well expose a dependency to other services (interfaces) and so on. Thus we use DI and let the IoC container resolver the chain of dependencies.
Now let's say my ViewModel has 50 properties, of which 30 are fine to go with the convention based mapping of automapper, while the other 20 need all to be resolved by different methods of my IUrlResolver interface. To get the facts straight:
I don't have a "sample syntax" to post because the closest way I tried is the one I posted before. I'm open to a complete different approach if it exists, providing it allows me to keep things decoupled and doesn't involve refactoring those properties in a separate class.
Upvotes: 0
Views: 1973
Reputation: 20992
I can't have DI where I configure automapper because it happens in Application_Start (or some static method called by application start)
That sounds like a rather artificial constraint. Both DI container wire-up and AutoMapper configuration are presumably happening early in the application launch phase. It should be at least theoretically feasible to run your AutoMapper configuration after your DI container is configured. If there are practical reasons why this is not the case, could you please elaborate?
Addendum: If the core problem is that you want to enable resolution of dependencies from your IoC container at mapping time, AutoMapper does provide hooks for this. See https://github.com/AutoMapper/AutoMapper/wiki/Custom-value-resolvers#custom-constructor-methods and https://github.com/AutoMapper/AutoMapper/wiki/Containers for two candidate approaches that you could use.
Upvotes: 0