I am using ASP.NET MVC 3 with Razor and Autofac for dependency injection.
I am thinking of creating a generic mapper. Currently I am using AutoMapper for the mapping between my domain and view model. It can be any mapping framework, but I am using AutoMapper .
Here is my IMapper interface:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
I then have an IBankMapper interface that implements this IMapper interface. The reason why I did it like this is because I can have many different mappers. Using dependency injection I can know what instance I can inject. So for IBankMapper I will inject BankMapper, ICategoryMapper I will inject CategoryMapper.
IBankMapper interface:
public interface IBankMapper : IMapper
{
}
BankMapper class:
public class BankMapper : IBankMapper
{
static BankMapper()
{
Mapper.CreateMap<Bank, EditBankViewModel>();
Mapper.CreateMap<EditBankViewModel, Bank>();
}
public object Map(object source, Type sourceType, Type destinationType)
{
return Mapper.Map(source, sourceType, destinationType);
}
}
As the program grows so will the mapper classes. Is there a way that I can create a generic mapper, one that can be used in the whole application? Is this possible?
There is absolutely no need for you to create any mapper classes at all.
All you need to do is be sure that you call Mapper.CreateMap at the beginning of your application. You can then use Mapper.Map to do your mapping.
Typically, I create a static class with a single method to handle the creation of my Maps. It looks something like:
public static class Transformers
{
public static void Register()
{
Mapper.CreateMap<Bank, EditBankViewModel>();
Mapper.CreateMap<EditBankViewModel, Bank>();
Mapper.CreateMap<Account, EditAccountViewModel>();
Mapper.CreateMap<EditAccountViewModel, Account>();
// And so on. You can break them up into private methods
// if you have too many.
}
}
I then call that method inside Global.asax do ensure that it runs when necessary. In any other spot in my application, I'm free to call Mapper.Map for any of the configured mappings:
protected void Application_Start()
{
Transformers.Register();
}
It looks like you are creating these interfaces to be able to mock AutoMapper in your unit tests. You can simply use IMappingEngine from AutoMapper for this purpose.
Your classes would have a dependency on IMappingEngine which would be injected. IMappingEngine has the same methods as the static class Mapper to map your objects.
In your composition root you would configure the mapper and register the mapping engine with the DI container.
Something like this:
// composition root:
Mapper.CreateMap<Bank, EditBankViewModel>();
Mapper.CreateMap<EditBankViewModel, Bank>();
builder.Register(Mapper.Engine);
// your classes:
class YourClass
{
public YourClass(IMappingEngine mappingEngine)
{
}
}
As Daniel said, Automapper is already a generic mapper. If you're worried about the direct dependency to automapper in your code, you can hide it behind a little facade, e.g.:
public interface IMapper
{
TDestination Map<TSource, TDestination>(TSource source);
}
public class MyMapper :IMapper
{
public TDestination Map<TSource, TDestination>(TSource source)
{
AutoMapper.Mapper.CreateMap<TSource, TDestination>();
return AutoMapper.Mapper.Map<TSource, TDestination>(source);
}
}
This can also help you to model the mapper as an injectable dependency
Related
I have 3 instances registered of the class Metadata. I don't have generic interface.
services.AddSingleton(new Metadata<Heartbeat1Job>(Constants.Heartbeat1JobName));
services.AddSingleton(new Metadata<Heartbeat2Job>(Constants.Heartbeat2JobName));
services.AddSingleton(new Metadata<Heartbeat3Job>(Constants.Heartbeat3JobName));
Now, I want to inject the list of all generic type instances of the class Metadata registered into the Controller...
// This may be the invalid syntax and it's
// just for the demonstration purpose...
private readonly IEnumerable<Metadata<T>> metadatas;
public TestController(IEnumerable<Metadata<T>> metadatas)
{
this.metadatas = metadatas;
}
How can I achieve this please?
You can create an interface exposing the methods you are interested in from the Metadata class. Lets name it IMetadata
public interface IMetadata
{
....
}
Your Metadata class will require some refactoring. Your Constants (based on your example) does not need to be passed as a parameter in the constructor but you can access it in the class as it is a static.
public class Metadata<T>: IMetadata
{
....
}
Then
services.AddSingleton<IMetadata, Metadata<Heartbeat1Job>>();
services.AddSingleton<IMetadata, Metadata<Heartbeat2Job>>();
services.AddSingleton<IMetadata, Metadata<Heartbeat3Job>>();
Finally in the class using the injected IMetadata you can do
private readonly IEnumerable<IMetadata> metadatas;
public TestController(IEnumerable<IMetadata> metadatas)
{
this.metadatas = metadatas;
}
In the way I described above you register a number of implementations on your IMetadata interface. When resolving IMetadata you will get an IEnumerable of the all the implementations you registered in the DI container.
I have the following situation:
an interface:
public interface ITest<T> where T:class
{
void Delete(T item);
}
the abstract implementation:
public abstract class Test<T>:ITest<T> where T:class
{
private readonly ApplicationDbContext _context;
protected Test(ApplicationDbContext context){
_context=context;
}
public void Delete(T item) { }
}
final class:
public class RepoTest:Test<FirstEntity>
{
public void DoSomething() { }
}
I have a MVC Controller, which looks like this:
public abstract class MyController<T>:Controller where T:class
{
private readonly ITest<T> _test;
protected MyController(ITest<T> test)
{
_test = test;
}
}
For each entity, I create a controller, inherited from MyController, and base on Entity I want ninject to inject the specific class.
For this I try to use this bindings:
kernel.Bind(typeof(ITest<>)).To(typeof(Test<>)).InRequestScope();
kernel.Bind(x=>x.FromAssemblyContaining(typeof(Test<>))
.SelectAllClasses()
.InheritedFrom(typeof(Test<>))
.BindToSelf());
Unfortunatly I alwasys got this kind of errors:
Error activating ITest{Tool}
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency ITest{Tool} into parameter test of constructor of type ToolsController
1) Request for ToolsController
Suggestions: 1) Ensure that you have defined a binding for
ITest{Tool}. 2) If the binding was defined in a module, ensure that
the module has been loaded into the kernel. 3) Ensure you have not
accidentally created more than one kernel. 4) If you are using
constructor arguments, ensure that the parameter name matches the
constructors parameter name. 5) If you are using automatic module
loading, ensure the search path and filters are correct.
How can I tell to Ninject, to inject the class base on the Entity type?
The code as it is written currently won't work.
You have two options:
Use generic:
Because your controller is expecting ITest<T> which is bound to an abstract class Test<T> which can't be instantiated.
You have to make a concrete but Generic class Test<T> and add a binding for ApplicationDbContext which will automatically work.
Use Reflection to find the right type at binding, e.g.:
Important!!! remove both of your kernel.Bind() calls.
// this will find classes which, like RepoTest, are derived from Test<>
var allDerivedTypes = typeof(Test<>).Assembly.GetExportedTypes().Where(x => x.BaseType.IsGenericType && x.BaseType.GetGenericTypeDefinition() == typeof(Test<>)).ToList();
// ideally, you'd find some way to constrain all your models.
// what you need for this foreach is all of the entities that can be present in things like RepoTest
foreach(var t in typeof(Tool).Assembly.GetExportedTypes())
{
// For each entity, get a runtime representation of Test<Entity>
var targetType = typeof(Test<>).MakeGenericType(t);
// Check if there is a class derived from Test<Entity>
var potentiallyPresentImplementation = allDerivedTypes.FirstOrDefault(x => targetType == x.BaseType); // here you might want to decide how to handle multiple instances of the same generic base
// Found one, so bind it
if(potentiallyPresentImplementation != null)
{
kernel.Bind(targetType ).To(potentiallyPresentImplementation ).InRequestScope();
}
}
Note: method 2 is currently assuming that all models and Test<> derivatives are in one assmebly, respecitvely. You'd need to add a little more reflection magic to inspect all referenced assemblies if this is not the case.
After this, the controller will get RepoTest injected. Although to be honest with you, approach 1. is better :)
I am basing most of my current implementation off the information provided here:
Ninject Intercept any method with certain attribute?
I use a custom planning strategy class which looks for all methods with given attributes (not ninject interceptor attributes) which will then get proxied if it matches the criteria.
An example of usage would be:
Kernel.Components.Add<IPlanningStrategy, CustomPlanningStrategy<LoggingAttribute, LoggerInterceptor>>();
This would then look for any methods which have a [Logging] attribute and will then use the logging interceptor.
However I am currently getting InvalidProxyConstructorArgumentsException from dynamic proxy when it is trying to proxy the methods with related attributes on. Now I remember reading that you need virtual methods, however I do not remember seeing that you HAD to have a parameterless constructor.
All bindings are done against interfaces, and the AOP interceptors happen via attributes and the custom proxy planning class mentioned in the link above.
So is there a way to get dynamic proxy (or the linfu version) to proxy the classes which have constructors with dependencies? (All dependencies are in the Kernel so its not like they cannot be resolved).
Looking at the proxy generating code:
https://github.com/ninject/ninject.extensions.interception/blob/master/src/Ninject.Extensions.Interception.DynamicProxy/DynamicProxyProxyFactory.cs
if (targetType.IsInterface)
{
reference.Instance = this.generator.CreateInterfaceProxyWithoutTarget(targetType, additionalInterfaces, InterfaceProxyOptions, wrapper);
}
else
{
object[] parameters = context.Parameters.OfType<ConstructorArgument>()
.Select(parameter => parameter.GetValue(context, null))
.ToArray();
reference.Instance = this.generator.CreateClassProxy(targetType, additionalInterfaces, ProxyOptions, parameters, wrapper);
}
one can see that ninject's dynamic proxy extension is only passing ConstructorArguments to the Castle Dynamic Proxy Generator.
So - without changes to the ninject extension or creating your own - you need to pass all dependencies as constructor arguments. You could also try out whether property / method injection works (see https://github.com/ninject/ninject/wiki/Injection-Patterns).
If you control the code you could add interfaces to the proxied classes and then use an "interface proxy with target". This allows to decouple proxy instantiation from target (proxied class) instantiation --> target can have dependencies ctor injected without any changes to ninject (-extensions).
Clarification:
Having the following class which should be proxied:
public interface IBar { }
public class Foo
{
public Foo(IBar bar)
{
}
}
And the following binding:
Bind<Foo>().ToSelf().Intercept().With<SomeInterceptor>();
Bind<IBar>().To<Bar>();
And then retrieving a Foo from the ninject container:
IResolutionRoot.Get<Foo>();
won't work.
Putting all constructor arguments on the ninject context to make it work
However, we can change the retrieving of Foo to make it work:
var bar = IResolutionRoot.Get<IBar>();
IResolutionRoot.Get<Foo>(new ConstructorArgument("bar", bar);
Now this is suboptimal because ninject is not doing dependency resolution automatically.
Adding interface to proxied class to make it work better
We can work around the issue by using a "interface proxy with target".
First, we add an interface to the proxied class:
public interface IFoo{ }
public class Foo : IFoo
{
public Foo(IBar bar)
{
}
}
And then we change the binding to:
Bind<IFoo>().To<Foo>().Intercept().With<SomeInterceptor>();
And then retrieving a Foo from the ninject container:
IResolutionRoot.Get<Foo>();
works.
Another, possibly easier (&uglier?) solution
According to #Daniel this works:
Add two constructor to the proxied type:
one protected constructor without parameters. This one is for DynamicProxy to create the proxy.
one public/internal constructor with the arguments, to be used by ninject to instantiate the proxied type.
Ninject will automatically pick the constructor with the most arguments it can resolve.
An alternate approach would be to use a convention based binding for all classes with a method with a [Logging] attribute. However, this means that adding a [Logging] attribute to a method will influence the binding of the object, which may be undesired.
So this is how it would work (verified to work):
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class LoggingAttribute : Attribute
{
}
public interface IClassNotToBeIntercepted
{
void DoSomething();
}
public class ClassNotToBeIntercepted : IClassNotToBeIntercepted
{
public void DoSomething() { }
}
public interface IClassToBeIntercepted
{
void DoNotLogThis();
void LogThis();
void LogThisAsWell();
}
public class ClassToBeIntercepted : IClassToBeIntercepted
{
public void DoNotLogThis() { }
[Logging]
public void LogThis() { }
[Logging]
public void LogThisAsWell() { }
}
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("interceptor before {0}", BuildLogName(invocation));
invocation.Proceed();
Console.WriteLine("interceptor after {0}", BuildLogName(invocation));
}
private static string BuildLogName(IInvocation invocation)
{
return string.Format(
"{0}.{1}",
invocation.Request.Target.GetType().Name,
invocation.Request.Method.Name);
}
}
public class DemoModule : NinjectModule
{
public override void Load()
{
this.Bind(convention => convention
.FromThisAssembly()
.SelectAllClasses()
.Where(ContainsMethodWithLoggingAttribute)
.BindDefaultInterface()
.Configure(x => x
.Intercept()
.With<LoggingInterceptor>()));
this.Bind<IClassNotToBeIntercepted>()
.To<ClassNotToBeIntercepted>();
}
private static bool ContainsMethodWithLoggingAttribute(Type type)
{
return type
.GetMethods()
.Any(method => method.HasAttribute<LoggingAttribute>());
}
}
And a test:
[Fact]
public void InterceptorTest()
{
var kernel = new StandardKernel();
kernel.Load<DemoModule>();
kernel.Get<IClassNotToBeIntercepted>()
.DoSomething();
kernel.Get<IClassToBeIntercepted>()
.LogThis();
}
Results in the following console output:
interceptor before ClassToBeIntercepted.LogThis
interceptor after ClassToBeIntercepted.LogThis
I have a controller and it receives a specific instance of an interface.
The interface looks something like this:
public interface IMyInterface
{
... implementation goes here
}
And then I have some classes that implement this interface like this:
public class MyClassA : IMyInterface
{
... implementation goes here
}
public class MyClassB : IMyInterface
{
... implementation goes here
}
In my ControllerA I have the following constructor:
private ICustomerService customerService;
private IMyInterface myInterface;
puvlic ControllerA(ICustomerService customerService, IMyInterface myInterface)
{
this.customerService = customerService;
this.myInterface = myInterface;
}
In my global.ascx:
protected void Application_Start()
{
// Autofac
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<NewsService>().As<INewsService>();
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
I specified that Autofac must supply the instance of ICustomerService. How would I specify the instance type for IMyInterface? In this case for ControllerA I would like Autofac to inject a ClassA instance. And for ControllerB I would like it to inject ClassB. How would I do this?
UPDATED 2011-02-14:
Let me give you my real life situation. I have a NewsController whose constructor looks like this:
public NewsController(INewsService newsService, IMapper newsMapper)
{
Check.Argument.IsNotNull(newsService, "newsService");
Check.Argument.IsNotNull(newsMapper, "newsMapper");
this.newsService = newsService;
this.newsMapper = newsMapper;
}
IMapper interface:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
I'm using AutoMapper. So my NewsMapper will look like this:
public class NewsMapper : IMapper
{
static NewsMapper()
{
Mapper.CreateMap<News, NewsEditViewData>();
Mapper.CreateMap<NewsEditViewData, News>();
}
public object Map(object source, Type sourceType, Type destinationType)
{
return Mapper.Map(source, sourceType, destinationType);
}
}
So how would you recommend me do this now?
IIRC:
builder.RegisterType<MyClassB>().As<IMyInterface>()
Update
Ok. Misread your question.
Actually, you should never ever do what you are asking. It's bound to give you problems. Why? Since there is no way to determine that the controllers can not work with the same interface. Amongst others, you are breaking the Liskovs Substitution Principle. It might not be a problem for you now, but let your application grow and come back in a year and try to understand why it isn't working.
Instead, create two new interfaces which derive from `IMyInterface´ and request those in the controllers.
Update 2
Qouting snowbear:
I disagree. OP doesn't says that his
controller cannot work with instance
of another type, he says that he wants
to inject instances of different
types. Let's imagine he has some
service to extract data and he has a
service which wraps this data service
and provides caching functionality. I
believe they should have the same
interface in such situation and it is
matter of DI to inject correct service
OP says just that: Controller A cannot work same class as controller B. Why would he else want to get different classes in different controllers for the same interface?
Brendan:
I personally would create a INewsMapper interface to make everything clear and sound. But if you do not want to do that: Go for a generic interface with the aggregate root as type parameter.
public interface IMapper<T> : IMapper where T : class
{
}
public class NewsMapper : IMapper<News>
{
static NewsMapper()
{
Mapper.CreateMap<News, NewsEditViewData>();
Mapper.CreateMap<NewsEditViewData, News>();
}
public object Map(object source, Type sourceType, Type destinationType)
{
return Mapper.Map(source, sourceType, destinationType);
}
}
public NewsController(INewsService newsService, IMapper<News> newsMapper)
{
}
I'm just getting started with dependency injection. I've read the Ninject wiki and its very clear on how to inject dependencies where a single instance of the dependency is required, using constructor, property or method injection. But how do you handle the case where your class needs to construct objects during its lifetime (after construction)? For example:
class AddressBook
{
private List<IContact> _contacts;
public AddContact(string name)
{
_contacts.Add(****what?****)
}
}
The only way I can think is to use constructor injection to pass in an IKernel and use that to get our IContact:
class AddressBook
{
private IKernel _kernel;
private List<IContact> _contacts;
public AddressBook(IKernel kernel){ _kernel = kernel; }
public AddContact(string name)
{
_contacts.Add(_kernel.Get<IContact>(new Parameter("name", name)));
}
}
But then how can you actually inject the kernel? What mapping would be required? Is this even the right approach?
Thanks for any help
felix
Similar to what the others have answered, we use a generic IFactory interface:
public interface IFactory<T>
{
T Get();
}
Which can be used like this:
public AddressBook(IFactory<IContact> ContactFactory)
And then implemented like this:
public class InjectorFactory : IFactory<T>
{
// we wrapped the Kernel in an Injector class
public T Get() { return Injector.Get<T>(); }
}
And bound like this:
Bind(typeof(IFactory<>)).To(typeof(InjectorFactory<>))
It has worked very well for us so far.
The answer as suggested by Benjamin Podszun:
Inject a factory:
public interface IContactFactory
{
IContact CreateContact(string name);
}
class AddressBook
{
private IContactFactory _factory;
private List<IContact> _contacts;
public AddressBook(IContactFactory factory){ _factory = factory; }
public AddContact(string name)
{
_contacts.Add(_factory.CreateContact(name));
}
}
Then you can bind the factory to whatever you want to create any specific instance of IContact.
You can do it pretty cleanly with: (exec summary of another answer re a slightly different question)
Bind<Func<IContact>>().ToMethod( context => () => Kernel.Get<Contact>() );
Your other options are:
have an IKernel injected as you did (that's supported OOTB with any special tricks), but as you allude to, this is rarely what you want - that's tantamount to Service Location.
Do a full-scale factory. See the other answer for the idiomatic Ninject way (a provider) to do more or less what your answer-to-self says. You better have a good reason to do that amount of boiler plate though.