SimpleInjector `Controller 注册为瞬态,但实现了 ApiController 的 IDisposable` 错误
SimpleInjector `Controller is registered as transient, but implements IDisposable` Error for ApiController
因此,正如我在研究中看到的那样,这个错误多年来一直给其他用户带来麻烦。 他们的建议解决方案另一方面,对我的项目不起作用 不知何故。
所以,我的创业公司 class 是;
public class Startup
{
private Container container = new Container();
public IConfigurationRoot Configuration { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
this.Configuration = new ConfigurationBuilder().SetBasePath(
Directory.GetCurrentDirectory()).AddJsonFile($"appsettings.{environmentName}.json").Build();
services.AddCors(options =>
{
options.AddPolicy(
"CorsPolicy",
builder => builder.WithOrigins(new[] { "http://localhost" })
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
services.AddControllers(); // ERR 1
services.AddSimpleInjector(container, options => /// ERR 2
{
options
.AddAspNetCore()
.AddControllerActivation();
});
services.AddCors();
InitializeContainer();
}
private void InitializeContainer()
{
// Register services
ConnectionConfig conf = new ConnectionConfig();
AppSettings settings = new AppSettings();
PathConfig path = new PathConfig();
Configuration.GetSection("AppSettings").Bind(settings);
Configuration.GetSection("ConnectionConfig").Bind(conf);
Configuration.GetSection("PathConfig").Bind(path);
container.RegisterInstance<ConnectionConfig>(conf);
container.RegisterInstance<PathConfig>(path);
container.RegisterInstance<AppSettings>(settings);
new CoreModule().RegisterServices(container);
new DataModule().RegisterServices(container);
new ServiceModule().RegisterServices(container);
}
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseCors(
options => options
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSimpleInjector(container);
container.Verify(); /// ERR 3
}
}
ERR 3
的错误是;
建议的解决方案说,我应该使用 Scoped
的 LifestyleScope 注册这些控制器,但是当我尝试这样做时,它在 ERR 2
处出现错误。
ERR 2
:
A registration for the Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartManager is missing from the ASP.NET Core configuration system. This is most likely caused by a missing call to services.AddMvcCore() or services.AddMvc() as part of the ConfigureServices(IServiceCollection) method of the Startup class. A call to one of those methods will ensure the registration of the ApplicationPartManager.
at SimpleInjector.SimpleInjectorAspNetCoreBuilderMvcCoreExtensions.GetApplicationPartManager(IServiceCollection services, String methodName)
at SimpleInjector.SimpleInjectorAspNetCoreBuilderMvcCoreExtensions.AddControllerActivation(SimpleInjectorAspNetCoreBuilder builder)
at ....Startup.<>c.<ConfigureServices>b__5_1(SimpleInjectorAddOptions options) in C:\Projects\...\Startup.cs:line 48
at SimpleInjector.SimpleInjectorServiceCollectionExtensions.AddSimpleInjector(IServiceCollection services, Container container, Action`1 setupAction)
at ....Startup.ConfigureServices(IServiceCollection services) in C:\Projects\...\Startup.cs:line 46
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(Object instance, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass12_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at ....Program.Main(String[] args) in C:\Projects\...\Program.cs:line 16
我的问题的根源是,我从 BaseApiController
返回 IHttpAction
的意愿不佳。我这样做的原因是,要确保我的 API 的客户在发生错误时始终了解正在发生的事情。如果不返回 InternalServerError
或 Ok()
等,我就很难向客户解释我的错误。
这是BaseApiController
:
// When I use `ControllerBase` here for the inheritance, API works like a charm
// after getting rid of the `IHttpActionResult` and writing `T` instead.
public class BaseApiController : ApiController
{
private readonly LogModule _logModule;
public BaseApiController(LogModule logModule)
{
_logModule = logModule;
}
public IHttpActionResult ExecuteAction<T>(Func<BaseResponse<T>> func)
{
try
{
return Ok(func());
}
catch (Exception ex)
{
var requestScope = Request.GetDependencyScope();
var logModule = requestScope.GetService(typeof(LogModule)) as LogModule;
StackTrace stackTrace = new StackTrace();
var description = "API." + this.GetType().Name + "." + stackTrace.GetFrame(1).GetMethod().Name;
logModule.Error(description, ex);
return InternalServerError();
}
}
}
这是我使用的控制器;
[Route("api/foo")]
[ApiController]
public class FooController : BaseApiController
{
private readonly FooService _fooService;
public FooController(FooService fooService, LogModule logModule) : base(logModule)
{
_fooService = fooService;
}
[HttpPost]
[Route("create_foo")]
public System.Web.Http.IHttpActionResult GetFoo([FromBody] FooRequest request)
{
var baseResponse = ExecuteAction(() =>
{
return _fooService.AddFoo(request);
});
return baseResponse;
}
}
总而言之,如何将 SimpleInjector 与 ApiController
一起使用?
要将您的控制器注册为 Scoped
,您可以使用以下代码:
// inside ConfigureServices or Startup ctor
this.container.Options.LifestyleSelectionBehavior = new ApiControllersAsScopedBehavior();
// behavior
internal class ApiControllersAsScopedBehavior : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type implementationType) =>
typeof(ApiController).IsAssignableFrom(implementationType)
? Lifestyle.Scoped
: Lifestyle.Transient;
}
因此,正如我在研究中看到的那样,这个错误多年来一直给其他用户带来麻烦。 他们的建议解决方案另一方面,对我的项目不起作用 不知何故。
所以,我的创业公司 class 是;
public class Startup
{
private Container container = new Container();
public IConfigurationRoot Configuration { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
this.Configuration = new ConfigurationBuilder().SetBasePath(
Directory.GetCurrentDirectory()).AddJsonFile($"appsettings.{environmentName}.json").Build();
services.AddCors(options =>
{
options.AddPolicy(
"CorsPolicy",
builder => builder.WithOrigins(new[] { "http://localhost" })
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
});
services.AddControllers(); // ERR 1
services.AddSimpleInjector(container, options => /// ERR 2
{
options
.AddAspNetCore()
.AddControllerActivation();
});
services.AddCors();
InitializeContainer();
}
private void InitializeContainer()
{
// Register services
ConnectionConfig conf = new ConnectionConfig();
AppSettings settings = new AppSettings();
PathConfig path = new PathConfig();
Configuration.GetSection("AppSettings").Bind(settings);
Configuration.GetSection("ConnectionConfig").Bind(conf);
Configuration.GetSection("PathConfig").Bind(path);
container.RegisterInstance<ConnectionConfig>(conf);
container.RegisterInstance<PathConfig>(path);
container.RegisterInstance<AppSettings>(settings);
new CoreModule().RegisterServices(container);
new DataModule().RegisterServices(container);
new ServiceModule().RegisterServices(container);
}
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseCors(
options => options
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSimpleInjector(container);
container.Verify(); /// ERR 3
}
}
ERR 3
的错误是;
建议的解决方案说,我应该使用 Scoped
的 LifestyleScope 注册这些控制器,但是当我尝试这样做时,它在 ERR 2
处出现错误。
ERR 2
:
A registration for the Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartManager is missing from the ASP.NET Core configuration system. This is most likely caused by a missing call to services.AddMvcCore() or services.AddMvc() as part of the ConfigureServices(IServiceCollection) method of the Startup class. A call to one of those methods will ensure the registration of the ApplicationPartManager.
at SimpleInjector.SimpleInjectorAspNetCoreBuilderMvcCoreExtensions.GetApplicationPartManager(IServiceCollection services, String methodName)
at SimpleInjector.SimpleInjectorAspNetCoreBuilderMvcCoreExtensions.AddControllerActivation(SimpleInjectorAspNetCoreBuilder builder)
at ....Startup.<>c.<ConfigureServices>b__5_1(SimpleInjectorAddOptions options) in C:\Projects\...\Startup.cs:line 48
at SimpleInjector.SimpleInjectorServiceCollectionExtensions.AddSimpleInjector(IServiceCollection services, Container container, Action`1 setupAction)
at ....Startup.ConfigureServices(IServiceCollection services) in C:\Projects\...\Startup.cs:line 46
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(Object instance, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass12_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at ....Program.Main(String[] args) in C:\Projects\...\Program.cs:line 16
我的问题的根源是,我从 BaseApiController
返回 IHttpAction
的意愿不佳。我这样做的原因是,要确保我的 API 的客户在发生错误时始终了解正在发生的事情。如果不返回 InternalServerError
或 Ok()
等,我就很难向客户解释我的错误。
这是BaseApiController
:
// When I use `ControllerBase` here for the inheritance, API works like a charm
// after getting rid of the `IHttpActionResult` and writing `T` instead.
public class BaseApiController : ApiController
{
private readonly LogModule _logModule;
public BaseApiController(LogModule logModule)
{
_logModule = logModule;
}
public IHttpActionResult ExecuteAction<T>(Func<BaseResponse<T>> func)
{
try
{
return Ok(func());
}
catch (Exception ex)
{
var requestScope = Request.GetDependencyScope();
var logModule = requestScope.GetService(typeof(LogModule)) as LogModule;
StackTrace stackTrace = new StackTrace();
var description = "API." + this.GetType().Name + "." + stackTrace.GetFrame(1).GetMethod().Name;
logModule.Error(description, ex);
return InternalServerError();
}
}
}
这是我使用的控制器;
[Route("api/foo")]
[ApiController]
public class FooController : BaseApiController
{
private readonly FooService _fooService;
public FooController(FooService fooService, LogModule logModule) : base(logModule)
{
_fooService = fooService;
}
[HttpPost]
[Route("create_foo")]
public System.Web.Http.IHttpActionResult GetFoo([FromBody] FooRequest request)
{
var baseResponse = ExecuteAction(() =>
{
return _fooService.AddFoo(request);
});
return baseResponse;
}
}
总而言之,如何将 SimpleInjector 与 ApiController
一起使用?
要将您的控制器注册为 Scoped
,您可以使用以下代码:
// inside ConfigureServices or Startup ctor
this.container.Options.LifestyleSelectionBehavior = new ApiControllersAsScopedBehavior();
// behavior
internal class ApiControllersAsScopedBehavior : ILifestyleSelectionBehavior
{
public Lifestyle SelectLifestyle(Type implementationType) =>
typeof(ApiController).IsAssignableFrom(implementationType)
? Lifestyle.Scoped
: Lifestyle.Transient;
}