#c# #asp.net-core #asp.net-core-mvc #simple-injector
#c# #asp.net-ядро #asp.net-core-mvc #простой инжектор
Вопрос:
Я пытаюсь написать AspNet Api с использованием SimpleInjector. Однако у меня возникли проблемы с SimpleInjector. Когда я запускаю приложение AspNet после регистрации типа в контейнере, я получаю эту ошибку:
Необработанное исключение. Система.Исключение AggregateException: некоторые службы не могут быть сконструированы (ошибка при проверке дескриптора сервиса ‘ServiceType: Web.Services.Время жизни WeatherForecastController: переходный тип реализации: Web.Services.WeatherForecastController’: не удалось разрешить службу для типа ‘MediatR.IMediator’ при попытке активировать ‘Web.Services.WeatherForecastController’.) —> Система.Исключение InvalidOperationException: ошибка при проверке дескриптора сервиса ‘ServiceType: Web.Services.Время жизни WeatherForecastController: переходный тип реализации: Web.Services.WeatherForecastController’: не удалось разрешить службу для типа ‘MediatR.IMediator’ при попытке активировать ‘Web.Services.WeatherForecastController’. —> Система.Исключение InvalidOperationException: не удалось разрешить службу для типа ‘MediatR.IMediator’ при попытке активировать ‘Web.Services.WeatherForecastController’. в Microsoft.Расширения.DependencyInjection.ServiceLookup.Вызывает объект-объект.CreateArgumentCallSites(тип ServiceType, Тип implementationType, CallSiteChain callSiteChain, ParameterInfo[] параметры, логическое значение throwIfCallSiteNotFound)
Я понимаю, что в контейнере отсутствует тип, не зарегистрированный, однако я регистрирую посредника непосредственно перед созданием экземпляра сервера Aspnet
public class Program
{
public static async Task Main(string[] args)
{
var configuration = LoadConfiguration(args);
var comp = new AspNetComponent(args);
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.Options.DefaultLifestyle = Lifestyle.Scoped;
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
container.Register<IMediator, Mediator>();
comp.Configure(configuration, container);
await comp.StartAsync(CancellationToken.None);
}
В AspNetComponent.cs:
public static IHostBuilder CreateHostBuilder(
string[] args, IConfiguration configuration, Container container)
{
Startup.UseContainer(container);
return Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("https://0.0.0.0:8080");
});
}
И мой класс Startup.cs:
public class Startup
{
private static Container _container;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
internal static void UseContainer(Container container)
{
_container = container;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddApplicationPart(
Assembly.GetAssembly(typeof(WeatherForecastController)))
.AddControllersAsServices();
services.AddSimpleInjector(_container, options =>
{
options.AddAspNetCore()
.AddControllerActivation();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSimpleInjector(_container);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
Я понятия не имею, в чем проблема, я отлаживал почти 3 дня.
Комментарии:
1. Я не могу воспроизвести вашу проблему. Я советую создать новый веб-проект, используя шаблон VS по умолчанию, и добавить интеграцию Simple Injector, как описано в документации . Когда это сработает, добавляйте необходимые функции шаг за шагом, пока они не сломаются.
Ответ №1:
Я думаю, что ваш код регистрирует контроллеры дважды (один раз в контейнере по умолчанию и второй раз внутри .AddSimpleInjector
). Контейнер по умолчанию идет первым, и он не Mediatr
зарегистрирован (мы сделали это только в контейнере SimpleInjector), поэтому при создании контроллера происходит сбой — он не может разрешить IMediatr. Просто удалите первый случай регистрации контроллеров.
public void ConfigureServices(IServiceCollection services)
{
// comment out first registration of services
// we keep services.AddMvc() because it is required for simple injector container AddAspNetCore()
services.AddMvc()
.AddApplicationPart(Assembly.GetAssembly(typeof(WeatherForecastController)));
//.AddControllersAsServices();
// you are doing this in Program.cs
var container = new Container();
services.AddSimpleInjector(container, x =>
{
x.AddAspNetCore()
.AddControllerActivation();
// you are doing this in Program.cs
x.Container.BuildMediator(Assembly.GetExecutingAssembly());
});
}
Комментарии:
1. Я отменяю первую часть (удаляя AddApplicationPart), но для BuildMediator он не может найти метод? Я предполагаю, что это метод расширения, но я не могу найти пакет?
2. И где мне зарегистрировать контроллеры ?
3. вы уже регистрируете контроллеры в своем коде в simple injector (
AddControllerActivation
). И вам не нуженBuildMediator
метод, поскольку ваш регистр<IMediator, Mediator>
для контейнера снаружи4. Хорошо, теперь я понимаю. Однако контроллер находится в другой сборке, поэтому URL-адрес всегда не найден. Как я могу зарегистрировать контроллеры из другой сборки?
5. только что протестировано, похоже, что единственная строка, которую вам нужно закомментировать, это
.AddControllersAsServices()
..AddApplicationPart(Assembly.GetAssembly(typeof(WeatherForecastController)))
может остаться. SimpleInjector использует тот же механизм для обнаружения контроллера. Соответствующим образом обновил мой asnwer