У меня есть проект с пользовательским набором картографических карт, которые сопоставляют модели и модели. Каждый картограф может получить доступ к IServiceProvider
, чтобы получить соответствующие картографы для своих внутренних объектов. Что-то вроде:
public class OuterMapper : MapperBase<OuterModel, OuterViewModel>
{
public OuterMapper(IServiceProvider serviceProvider, IMyDbContext dbContext)
: base(serviceProvider, dbContext)
{}
public override async Task<OuterModel> ToModel(OuterViewModel viewModel, OuterModel existingModel)
{
var model = existingModel
?? (await base.DbContext.OuterModels.SingleAsync(x => x.Id == viewModel.Id))
?? new OuterModel();
model.SimpleProperty = viewModel.SimpleProperty;
model.InnerComplexObject = await base.ToInnerModel(viewModel.InnerComplexObject, model.InnerComplexObject);
return model;
}
public override async Task<OuterViewModel> ToViewModel(OuterModel model, OuterViewModel existingViewModel)
{
var viewModel = existingViewModel ?? new OuterViewModel();
viewModel.SimpleProperty = model.SimpleProperty;
viewModel.InnerComplexObject = await base.ToInnerViewModel(model.InnerComplexObject, viewModel.InnerComplexObject);
return viewModel;
}
}
public abstract class MapperBase<TModel, TViewModel> : IMapper<TModel, TViewModel>
{
private IServiceProvider ServiceProvider { get; set; }
protected IMyDbContext DbContext { get; private set; }
public MapperBase(IServiceProvider serviceProvider, IMyDbContext dbContext)
{
ServiceProvider = serviceProvider;
DbContext = dbContext;
}
protected async Task ToInnerModel<TInnerModel, TInnerViewModel>(TInnerViewModel viewModel, TInnerModel model)
{
var innerMapper = ServiceProvider.GetService<IMapper<TInnerModel, TInnerViewModel>>();
return await innerMapper.ToModel(viewModel, model);
}
protected async Task ToInnerViewModel<TInnerModel, TInnerViewModel>(TInnerModel model, TInnerViewModel viewModel)
{
var innerMapper = ServiceProvider.GetService<IMapper<TInnerModel, TInnerViewModel>>();
return await innerMapper.ToViewModel(model, viewModel);
}
}
Недавно мы начали рефакторинг нашего кода для перехода от синхронных к асинхронным операциям (как это уже можно видеть в примерах сопоставителей). Однако это вызвало непредсказуемую побочную проблему. При отображении очень сложного объекта с большим количеством вложенных объектов мы иногда получаем тихий сбой в строках со следующим кодом:
var innerMapper = ServiceProvider.GetService<IMapper<TInnerModel, TInnerViewModel>>();
По сути, приложение кажется замороженным и не может отвечать на новые запросы. Кажется, что где-то был неожиданный асинхронный метод, но мы не нашли ни одного. При оценке выражения (в JetBrains Rider) я получаю сообщение об ошибке тайм-аута. Я изучил IServiceProvider
и вижу, что внутри него есть экземпляр правильного преобразователя в ResolvedServices
. Более того, когда я перемещаю проблемную строку с точно такими же аргументами типа в другую часть нашего проекта (например, непосредственно в контроллер), преобразователь разрешается, как и ожидалось.
Что может быть причиной проблемы? Есть ли где-нибудь ограничение ServiceProvider
вызовов в ASP.NET Core?
Просто пара деталей: я использую .NET Core 2.2, работаю на компьютере с Windows 10 и использую JetBrains Rider для разработки.
EDIT
Я использовал функцию «Отладка внешних источников» JetBrains Rider и перекопал некоторый код .NET. Последний вызов был Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService
в строках 29-31, где this._disposed
был оценен как true
. Затем последняя строка была ThrowHelper.ThrowObjectDisposedException()
, после чего приложение зависло. Почему поставщик утилизируется? Почему не исключение поймано?