Injecting a specific instance of an interface using Autofac
I am using ASP.NET MVC 3 and Autofac for my dependency injection. I am using AutoMapper for my mapping.
I have an IMapper class that I use for all my model view mappings. So any any of my mapping classes can implement this interface. In the controller below the constructor receives an IMapper instance, and in my User controller it might receive a different instance, maybe userMapper. Getting back to the code below, I have a class called NewsMapper and it implements IMapper. How do I setup dependency injection so that this controller must receive an instance of NewsMapper? Please bear in mind that I might have another mapper called UserMapper.
I have the following controller:
public class NewsController
{
private INewsService newsService;
private IMapper newsMapper;
public NewsController(INewsService newsService, IMapper newsMapper)
{
if (newsService == null)
{
throw new ArgumentNullException("newsService");
}
if (newsMapper == null)
{
开发者_JS百科 throw new ArgumentNullException("newsMapper");
}
this.newsService = newsService;
this.newsMapper = newsMapper;
}
}
I have the following configuration in my global.asax.cs:
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<NewsService>().As<INewsService>();
builder.RegisterType<NewsRepository>().As<INewsRepository>();
UPDATED:
My IMapper interface:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
My NewsMapper class:
public class NewsMapper : IMapper
{
static NewsMapper()
{
Mapper.CreateMap<News, NewsViewModel>();
Mapper.CreateMap<NewsViewModel, News>();
}
public object Map(object source, Type sourceType, Type destinationType)
{
return Mapper.Map(source, sourceType, destinationType);
}
}
My controller action method where I do the mappings:
[HttpPost]
public ActionResult Create(NewsViewModel newsViewModel)
{
// Check model state
if (!ModelState.IsValid)
{
return View("Create", newsViewModel);
}
// Do mapping
var news = (News)newsMapper.Map(newsViewModel, typeof(NewsViewModel), typeof(News));
// Add to database via news service
// Redirect to list view
return RedirectToAction("List", "News");
}
The problem here is the broadness of the IMapper
contract. It is too general - the NewsController
wants to map something like News
to NewsViewModel
but IMapper
just says "maps something to something."
Instead, have a look at creating a generic variant such as IMapper<TFrom,TTo>
. Then, you can set up container so that the NewsController
receives an IMapper<News,NewsModel>
which is unambiguous and should uniquely match the NewsMapper
component (however you decide to set that up.)
Edit
For examples/variants on the generic mapper theme see:
- http://consultingblogs.emc.com/owainwragg/archive/2010/12/15/automapper-profiles.aspx
- http://lucisferre.net/2009/12/31/graphite-update-the-automapfilter-for-model-e280933e-viewmodel-mapping/
- Specifying a default Unity type mapping for a generic interface and class pair
精彩评论