Почему Mediatr не разрешает метод, когда объекты находятся в разных проектах?

У меня есть простой проект, чтобы опробовать проблему с Mediatr. Когда конкретный класс моего обработчика в ЖЕСТКОМ проекте моего API, он РАБОТАЕТ. Но когда я беру этот класс обработчика в другой проект (и API ссылается на этот проект ofc), он НЕ разрешает реестр.

Я получаю такую ​​ошибку:

Обработчик не найден для запроса типа MediatR.IRequestHandler`2 [MyBiz.GetTokenModelRequest, MyBiz.TokenModel]. Зарегистрируйте свои обработчики в контейнере. См. Примеры в GitHub.

У меня есть эта структура в моем проекте, а также показано, где она работает, а где нет:

«Структура

Для подробностей вот коды:

MyApi2 -> Startup.cs:

namespace MyApi2
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddMediatR();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
        }
    }
}

MyApi2 -> ValuesController:

namespace MyApi2.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        private readonly IMediator _mediator;

        public ValuesController(IMediator mediator)
        {
            _mediator = mediator;
        }

        [HttpGet]
        public async Task<IEnumerable<string>> Get()
        {
            try
            {
                var rr = await _mediator.Send(new GetTokenModelRequest());
            }
            catch (Exception ex)
            {
                throw;
            }
            return new string[] { "value1", "value2" };
        }
    }
}

MyBiz -> GetTokenModelRequest

namespace MyBiz
{
    public class GetTokenModelRequest : LoginModel, IRequest<TokenModel>
    {
    }
    public class LoginModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
    public class TokenModel
    {
        #region Properties

        public Guid Id { get; set; }
        public string Username { get; set; }
        public string Token { get; set; }
        public DateTime Expiration { get; set; }

        #endregion
    }
}

MyInftra -> TokenQueryHandler

namespace MyInfra
{
    public class TokenQueryHandler : ITokenQueryHandler
    {
        public Task<TokenModel> Handle(GetTokenModelRequest request, CancellationToken cancellationToken)
        {
            return Task.FromResult(new TokenModel());
        }
    }
}

Итак, если я ПЕРЕМЕЩУ TokenQueryHandler с MyInfra на MyApi, это сработает, но я смогу поместить его в проект ссылок, верно?


person E-A    schedule 25.03.2019    source источник
comment
Как вы добавляете Mediatr в DI в свой файл запуска?   -  person UncleDave    schedule 25.03.2019
comment
В Startup.cs я использую services.AddMediatR(); внутри ConfigureServices(IServiceCollection services)   -  person E-A    schedule 25.03.2019


Ответы (1)


Обновлять

Начиная с версии 7.0.0 из < пакет href = "https://github.com/jbogard/MediatR.Extensions.Microsoft.DependencyInjection" rel = "noreferrer"> MediatR.Extensions.Microsoft.DependencyInjection, AppDomain больше не сканируется автоматически на предмет загрузки сборки, содержащие базовые типы MediatR для регистрации при вызове метода расширения AddMediatR().

Фактически, перегрузка указанной функции без параметров была полностью удалена из пакета, и вместо этого пользователи должны были передавать сборки (или типы) для сканирования.

Это делает регистрацию базовых типов MediatR (IRequestHandler, INotificationHandler, IRequestPreProcessor и IRequestPostProcessor) в каждой сборке, на которую указывает ссылка, явно на усмотрение пользователя.

Итак, если у нас есть некоторые базовые типы MediatR в воображаемых сборках Assembly1 и Assembly2, которые мы хотим зарегистрировать в контейнере MediatR:

Вместо того, чтобы делать: services.AddMediatR();

Вам нужно будет сделать: services.AddMediatR(typeof(Assembly1), typeof(Assembly2));

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


Оригинальный ответ

Примечание. Следующий ответ актуален только для версий ‹7.0.0 MediatR.Extensions.Microsoft .DependencyInjection.

Вызов метода расширения AddMediatR() в вашем startup.cs файле многое делает для инициализации MediatR:

  • Он сканирует домен приложения на предмет загруженных в данный момент сборок.
  • Он просматривает каждую из этих загруженных в настоящее время сборок, чтобы найти каждый класс, который наследуется от базовых типов MediatR (IRequestHandler, INotificationHandler, IRequestPreProcessor и IRequestPostProcessor).
  • Он регистрирует каждый из этих базовых типов MediatR в контейнере для последующего использования.

Помня о вышеизложенном, важно понимать, как .NET CLR загружает ссылочные сборки. Есть действительно интересный сообщение в блоге Рика Стрэла, в котором подробно рассказывается, но я резюмирую его здесь с цитатой:

Короче говоря, сборки, на которые имеются ссылки, загружаются не сразу - они загружаются «на лету» по мере необходимости. Таким образом, независимо от того, есть ли у вас ссылка на сборку в проекте верхнего уровня или зависимая сборка, сборки обычно загружаются по мере необходимости, если явно не загружены пользовательским кодом. То же самое и с зависимыми сборками.

Почему это важно знать?

Что ж, в своем MyApi2 проекте вы ссылаетесь на проект MyInfra, но фактически никоим образом не используете его. Это означает, что сборка не будет загружена средой CLR, и поэтому MediatR не сможет найти ее в загруженных в данный момент сборках домена приложения. В результате ваш IRequestHandler не будет зарегистрирован (как и любые другие базовые типы MediatR в этом проекте).

Решение этой проблемы состоит в том, чтобы гарантировать, что сборка, содержащая типы, которые вы хотите зарегистрировать в контейнере MediatR, загружается до вызова AddMediatR().

Вы можете сделать одно из следующих действий:

  • Загрузить вручную ваша ссылочная сборка
  • Ссылка на тип / функцию, которая находится в вашем MyInfra проекте, из вашего MyApi2 проекта

Последний вариант является наиболее типичным, поскольку у вас обычно будут некоторые функции, которые находятся в вашей ссылочной сборке, которую вы захотите вызвать (в отличие от простой сборки, содержащей типы).

Какой бы вариант вы ни выбрали, убедитесь, что вы сделали это до добавления MediatR. В противном случае вы столкнетесь с той же проблемой.

person Darren Ruane    schedule 25.03.2019