Проблема многопоточности AutoMapper (отсутствует конфигурация карты типов или не поддерживается отображение)? - PullRequest
8 голосов
/ 23 марта 2012

Я не уверен, есть ли у меня проблема с потоками здесь или нет.На странице загрузки я выполняю два Ajax-запроса на загрузку некоторых дополнительных данных из стороннего API.Вот как каждый метод выглядит так:

private List<CaseCommentModel> GetCaseCommentModels(string caseId) {
    var comments = CaseService.GetAllCaseCommentsByCaseId(caseId);

    Mapper.Reset();
    Mapper.CreateMap<CrmCaseComment, CaseCommentModel>();

    var caseCommentModels = Mapper.Map<List<CrmCaseComment>, List<CaseCommentModel>>(comments);

    return caseCommentModels;
}

private List<CaseAttachmentModel> GetCaseAttachmentModels(string caseId) {
    var attachments = AttachmentService.GetAttachmentsByParentId(caseId);

    Mapper.Reset();
    Mapper.CreateMap<CrmAttachment, CaseAttachmentModel>();

    var caseAttachmentModels = Mapper.Map<List<CrmAttachment>, List<CaseAttachmentModel>>(attachments);

    return caseAttachmentModels;
}

Иногда оба ответа успешны.Но, если я обновлю страницу, иногда произойдет сбой со следующим исключением:

Missing type map configuration or unsupported mapping

Я могу перейти от обоих запросов к одному, не выполнив ни одного изменения кода;все, что нужно, это обновить страницу.Это проблема с многопоточностью или я неправильно использую маппер?

Ответы [ 4 ]

10 голосов
/ 23 марта 2012

Да, у вас есть проблема с многопоточностью, и вы неправильно используете конфигурацию Automapper.На странице начала работы с Automapper :

Если вы используете метод статического сопоставления, конфигурация должна выполняться только один раз для каждого AppDomain.Это означает, что лучшее место для размещения кода конфигурации - это запуск приложения, например, файл Global.asax для приложений ASP.NET.Как правило, класс начальной загрузки конфигурации находится в своем собственном классе, и этот класс начальной загрузки вызывается из метода запуска.

Таким образом, вы не должны иметь Mapper.CreateMap внутри действий контроллера, перемещающих их в общее местои выполните их один раз.

Или, если вам нужна конфигурация с динамическим отображением, не используйте статический Mapper вместо сборки конфигурации и механизма "вручную":

var config = 
    new ConfigurationStore(new TypeMapFactory(), MapperRegistry.AllMappers());
config.CreateMap<CrmCaseComment, CaseCommentModel>();
var engine = new MappingEngine(config);
var caseCommentModels = 
    engine.Map<List<CrmCaseComment>, List<CaseCommentModel>>(comments);
6 голосов
/ 23 марта 2012

Вы должны создать сопоставление только один раз за время жизни приложения. Итак, переместите каждый конкретный CreateMap в начало приложения.

Проблема, с которой вы столкнулись, вероятно, связана с гонкой за сопоставление до того, как другой поток вызовет Mapper.Reset()

1 голос
/ 26 апреля 2013

Я столкнулся с проблемой с потоками и хотел бы поделиться своими выводами.

В моем приложении в конструкторе служб WCF Iназывается AutoMapperRegistry.Configure () для создания сопоставлений для автоматического сопоставления.

Из контроллера MVC Я вызываю службу, вызывая одноэлементный объект служба WCF .

Актуальная проблема от веб-клиента Я на самом деле вызвал асинхронно два контроллераметоды , чтобы и общались с сервисом и возвращали результат.В тот момент, когда i изменил первый метод на Асинхронное ложное в проблеме, проблема была решена .

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

0 голосов
/ 07 июля 2017

Да, у вас есть проблема с многопоточностью, и лучшее решение (на мой взгляд) - прекратить использование статического API из AutoMapper.

Я предлагаю вам сконфигурировать autopper следующим образом: // IoC регистрация (в моем случае Autofac)

builder
    .Register(c => new MapperConfiguration(cfg => {
        cfg.AddProfile<AutoMapperProfile>();
    }))
    .SingleInstance();
builder
    .Register(c => c.Resolve<MapperConfiguration>().CreateMapper())
    .As<AutoMapper.IMapper>();

Обратите внимание, что я создаю MapperConfiguration как отдельный экземпляр. Класс AutoMapperProfile.cs содержит конфигурацию automapper:

class AutoMapperProfile : Profile
{
    public AutoMapperProfile()
    {
        CreateMap<Source, Destination>();
        // usual configurations...
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...