IServiceProvider.GetService тихий сбой - PullRequest
0 голосов
/ 10 июля 2019

У меня есть проект с пользовательским набором картографических карт, которые сопоставляют модели и модели. Каждый картограф может получить доступ к 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(), после чего приложение зависло. Почему поставщик утилизируется? Почему не исключение поймано?

...