2013-12-05 2 views
1

У меня есть многопользовательское веб-приложение, которое имеет несколько модулей. Я использую autofac как IOC и Automapper для сопоставления модели и объектов. В следующем коде я могу добавить профиль UserAuthenticationMapper в automapper, но не смог добавить профиль CustomerDataMapper. Autofac добавляет только один профиль карты к автопарпуру MappingEngine и игнорирует остальную часть. Что я здесь делаю?Невозможно зарегистрировать и добавить профиль automapper в Autofac

Вот мой UserAuthentication Модуль:

public class UserAuthenticationModule: Autofac.Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.RegisterType<MappingEngine>().As<IMappingEngine>(); 

     builder.Register(ctx => 
     { 
      var configStore = new ConfigurationStore 
      (new TypeMapFactory(), MapperRegistry.AllMappers()); 
      configStore.AddProfile<UserAuthenticationMapperProfile>(); 
      return configStore; 
     }) 
     .AsImplementedInterfaces() 
     .SingleInstance(); 

     var assembly = Assembly.GetExecutingAssembly(); 
     builder.RegisterAssemblyTypes(assembly) 
       .Where(t => t.Name.EndsWith("Service")) 
       .AsImplementedInterfaces() 
       .SingleInstance(); 
     } 
    } 

CustomerData Modue:

public class CustomerDataModule : Autofac.Module 
    { 
    protected override void Load(ContainerBuilder builder) 
    { 
     builder.RegisterType<CustomerDataService>() 
      .As<ICustomerDataService>() 
      .InstancePerDependency(); 

     builder.RegisterType<MappingEngine>().As<IMappingEngine>(); 

     builder.Register(ctx => 
      { 
       var configStore = new ConfigurationStore 
       (new TypeMapFactory(), MapperRegistry.AllMappers()); 
       configStore.AddProfile<CustomerDataMapperProfile>(); 
       return configStore; 
      }) 
       .AsImplementedInterfaces() 
       .SingleInstance(); 
     } 
    } 

здесь некоторые дополнительный код, чтобы показать, как я загрузке этих модулей в Global.asax

static IContainerProvider _containerProvider; 

    public IContainerProvider ContainerProvider 
    { 
     get { return _containerProvider; } 
    } 

    void Application_Start(object sender, EventArgs e) 
    { 
     RouteTable.Routes.MapHttpRoute(
      name: "ActionApi", 
      routeTemplate: "api/{controller}/{action}" 
     ); 

     RouteTable.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: new { id = System.Web.Http.RouteParameter.Optional } 
     ); 
     var builder = new ContainerBuilder(); 
     builder.RegisterModule<UserAuthenticationModule>(); 
     builder.RegisterModule<CustomerDataModule>(); 
     _containerProvider = new ContainerProvider(builder.Build()); 
    } 

Ошибка:

Исключение типа «AutoMapper.AutoMapperMappingException» произошло в AutoMapper.dll, но не было обработано в коде пользователя Отсутствует конфигурация карты типа или неподдерживаемое отображение. \ R \ n \ r \ nМашины типов: \ r \ nUser -> UserModel

+0

Можете ли вы показать нам, как вы регистрируете эти модули, как вы разрешаете ваше сопоставление (например, как вы проверяете загрузку одного профиля, а не другое) и сообщаете нам, видите ли вы какие-либо сообщения об ошибках? –

+0

Я редактировал свой вопрос с дополнительной информацией и сообщением об ошибке. Я получаю эту ошибку для «CustomerDataMapperProfile». – rajcool111

ответ

6

Я предполагаю, что проблема у вас есть то, что вы регистрации ConfigurationStore два экземпляра но MappingEngine занимает один в качестве параметра конструктора.

Когда вы регистрируете более одного объекта в Autofac, это «последний выигрыш». Поэтому, когда вы решить a MappingEngine он будет выбрать конструктор, как это:

public MappingEngine(IConfigurationProvider configurationProvider) 

Это занимает только одного поставщика конфигурации (ConfigurationStore орудия IConfigurationProvider), так что вы получите только один. Это означает, что это эквивалент:

container.Resolve<IConfigurationProvider>(); 

Вы получите только один. Если вам необходимо решить все из них, вы должны были бы разрешить IEnumerable<IConfigurationProvider> от Autofac, как:

container.Resolve<IEnumerable<IConfigurationProvider>>(); 

Но это не решит вашу проблему, он описывает только то, что я думаю, что происходит.

Что вам нужно сделать, чтобы сделать то, что вы хотите, это сломать вещи немного больше. Вместо регистрации ConfigurationStore в каждом модуле регистрируйте только профили. Как это (укороченный для удобства чтения):

public class CustomerDataModule : Autofac.Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
    builder.RegisterType<CustomerDataMapperProfile>().As<Profile>(); 
    } 
} 

public class UserAuthenticationModule : Autofac.Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
    builder.RegisterType<UserAuthenticationMapperProfile>().As<Profile>(); 
    } 
} 

Затем вам нужно, чтобы вырваться из общих регистраций AutoMapper из ваших модулей. Вы не хотите дважды регистрироваться. Создайте новый модуль, который обрабатывает регистрацию механизма отображения, а также выполняет некоторое динамическое разрешение профилей.

public class AutoMapperModule : Autofac.Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
    // Register the common thing once, not in each module. 
    builder.RegisterType<MappingEngine>().As<IMappingEngine>(); 

    // Here's where you dynamically get all the registered profiles 
    // and add them at the same time to the config store. 
    builder.Register(ctx => 
     { 
     var profiles = ctx.Resolve<IEnumerable<Profile>>(); 
     var configStore = new ConfigurationStore 
      (new TypeMapFactory(), MapperRegistry.AllMappers()); 
     foreach(var profile in profiles) 
     { 
      configStore.AddProfile(profile); 
     } 
     return configStore; 
     }) 
     .AsImplementedInterfaces() 
     .SingleInstance(); 
    } 
} 

Убедитесь, что вы зарегистрировать все модули в контейнере:

var builder = new ContainerBuilder(); 
builder.RegisterModule<UserAuthenticationModule>(); 
builder.RegisterModule<CustomerDataModule>(); 
builder.RegisterModule<AutoMapperModule>(); 
_containerProvider = new ContainerProvider(builder.Build()); 

Теперь вы должны иметь все профили зарегистрированных при разрешении IMappingEngine.

+0

Спасибо! вот что я искал. – rajcool111

+0

Я использовал этот код в своем проекте с automapper 3.3.1.0, и он работает, но я изменил одно: «MapperRegistry.AllMappers()« Я изменился на «MapperRegistry.Mappers». Чтобы построить все, просто разрешите '_containerProvider = new ContainerProvider (builder.Build()); _containerProvider.Resolve (); 'в корне. – Alezis

+0

Это выглядит неплохое решение, но в моем служении я заметил, что ctx.Resolve >() никогда не вызывается, и, следовательно, мои mappers не создаются. Любые идеи почему? – Bonomi

Смежные вопросы