Почему Mediatr не разрешает метод, когда энтиты находятся в разных проектах? - PullRequest
4 голосов
/ 25 марта 2019

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

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

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

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

Project structure represented as a tree view

Для уточнения приведем следующие коды:

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());
        }
    }
}

Итак, если я MOVE TokenQueryHandler с MyInfra до MyApi, это работает, но я должен быть в состояниипоставь ссылку на проект, да?

1 Ответ

4 голосов
/ 25 марта 2019

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

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

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

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

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

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

Чтобы решить эту проблему, у вас есть несколько вариантов, я назову пару ниже:

Вы можете вручную загрузить вашу сборку до , вызывая AddMediatR в вашем файле startup.cs.

Или

Вы можете вызвать какую-то функциональность, которая находится в вашем MyInfra проекте до вызова AddMediatR в вашем файле startup.cs.

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

...