在 mvc 中使用依赖注入
Working with dependency injection in mvc
在我们的一个应用程序中,我已经在使用 AppTenant
class 的依赖注入,如下所示
public void ConfigureServices(IServiceCollection services)
{
services.AddMultitenancy<AppTenant, CachingAppTenantResolver>();
services.Configure<MultitenancyOptions>(Configuration.GetSection("Multitenancy"));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMultitenancy<AppTenant>();
}
在控制器中,我可以按如下方式轻松访问它
public AccountController(AppTenant tenant)
{
this.tenant = tenant;
}
现在,我想在同一解决方案中访问其他项目 class 中的相同 AppTenant
或 HttpContext
。
所以,我试过这样
public SqlStringLocalizerFactory(
AppTenant tenant)
{
_tenant = tenant;
}
但它即将变为空,所以我需要做的是在另一个项目中获得 AppTenant
或 HttpContext
class ?
对于SqlStringLocalizerFactory
class,服务是用[=20=]方法编写的,如下
public static class SqlLocalizationServiceCollectionExtensions
{
public static IServiceCollection AddSqlLocalization(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
return AddSqlLocalization(services, setupAction: null);
}
public static IServiceCollection AddSqlLocalization(
this IServiceCollection services,
Action<SqlLocalizationOptions> setupAction)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.TryAdd(new ServiceDescriptor(
typeof(IStringExtendedLocalizerFactory),
typeof(SqlStringLocalizerFactory),
ServiceLifetime.Singleton));
services.TryAdd(new ServiceDescriptor(
typeof(IStringLocalizerFactory),
typeof(SqlStringLocalizerFactory),
ServiceLifetime.Singleton));
services.TryAdd(new ServiceDescriptor(
typeof(IStringLocalizer),
typeof(SqlStringLocalizer),
ServiceLifetime.Singleton));
if (setupAction != null)
{
services.Configure(setupAction);
}
return services;
}
}
我什至尝试过 IHttpContextAccessor
,但仍然没有成功。
感谢任何帮助!
编辑-2
新解决方案:
public SqlStringLocalizerFactory(IHttpContextAccessor _accessor)
{
_accessor= accessor;
}
public void SomeMethod()
{
var tenant = _accessor.HttpContext.RequestServices
.GetRequiredService<AppTenant>();
}
Edit : IServiceProvider
方式不符合我的预期。参见@Sock 的解决方案
首先,我假设问题的发生是由于@qujck 指出的俘虏依赖。为了避免俘虏依赖:
如果SqlStringLocalizerFactory
的生命周期必须是单例(某些情况下必须是),在这个
案例使用 IServiceProvider
:
public SqlStringLocalizerFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void SomeMethod()
{
var tenant = _serviceProvider.GetService<AppTenant>();
}
否则使用 AddScoped
对你的情况来说似乎是合理的。
你有两个选择,最好的选择,如果 SqlStringLocalizerFactory
可以是范围内的依赖项(你为每个请求获得一个新实例)那么你可以将它注册为范围内的依赖项:
services.TryAdd(new ServiceDescriptor(
typeof(IStringLocalizerFactory),
typeof(SqlStringLocalizerFactory),
ServiceLifetime.Scoped));
如果 SqlStringLocalizerFactory
必须 是单例依赖项,那么您需要确保使用 ServiceSope
解决租户的作用域依赖项:
public class SqlStringLocalizerFactory
{
private readonly IServiceProvider _serviceProvider;
public SqlStringLocalizerFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void SomeMethod()
{
using (var serviceScope = _serviceProvider
.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var tenant = serviceScope.ServiceProvider.GetService<AppTenant>();
// do something with tenant...
}
}
}
在我们的一个应用程序中,我已经在使用 AppTenant
class 的依赖注入,如下所示
public void ConfigureServices(IServiceCollection services)
{
services.AddMultitenancy<AppTenant, CachingAppTenantResolver>();
services.Configure<MultitenancyOptions>(Configuration.GetSection("Multitenancy"));
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseMultitenancy<AppTenant>();
}
在控制器中,我可以按如下方式轻松访问它
public AccountController(AppTenant tenant)
{
this.tenant = tenant;
}
现在,我想在同一解决方案中访问其他项目 class 中的相同 AppTenant
或 HttpContext
。
所以,我试过这样
public SqlStringLocalizerFactory(
AppTenant tenant)
{
_tenant = tenant;
}
但它即将变为空,所以我需要做的是在另一个项目中获得 AppTenant
或 HttpContext
class ?
对于SqlStringLocalizerFactory
class,服务是用[=20=]方法编写的,如下
public static class SqlLocalizationServiceCollectionExtensions
{
public static IServiceCollection AddSqlLocalization(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
return AddSqlLocalization(services, setupAction: null);
}
public static IServiceCollection AddSqlLocalization(
this IServiceCollection services,
Action<SqlLocalizationOptions> setupAction)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.TryAdd(new ServiceDescriptor(
typeof(IStringExtendedLocalizerFactory),
typeof(SqlStringLocalizerFactory),
ServiceLifetime.Singleton));
services.TryAdd(new ServiceDescriptor(
typeof(IStringLocalizerFactory),
typeof(SqlStringLocalizerFactory),
ServiceLifetime.Singleton));
services.TryAdd(new ServiceDescriptor(
typeof(IStringLocalizer),
typeof(SqlStringLocalizer),
ServiceLifetime.Singleton));
if (setupAction != null)
{
services.Configure(setupAction);
}
return services;
}
}
我什至尝试过 IHttpContextAccessor
,但仍然没有成功。
感谢任何帮助!
编辑-2
新解决方案:
public SqlStringLocalizerFactory(IHttpContextAccessor _accessor)
{
_accessor= accessor;
}
public void SomeMethod()
{
var tenant = _accessor.HttpContext.RequestServices
.GetRequiredService<AppTenant>();
}
Edit : IServiceProvider
方式不符合我的预期。参见@Sock 的解决方案
首先,我假设问题的发生是由于@qujck 指出的俘虏依赖。为了避免俘虏依赖:
如果SqlStringLocalizerFactory
的生命周期必须是单例(某些情况下必须是),在这个
案例使用 IServiceProvider
:
public SqlStringLocalizerFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void SomeMethod()
{
var tenant = _serviceProvider.GetService<AppTenant>();
}
否则使用 AddScoped
对你的情况来说似乎是合理的。
你有两个选择,最好的选择,如果 SqlStringLocalizerFactory
可以是范围内的依赖项(你为每个请求获得一个新实例)那么你可以将它注册为范围内的依赖项:
services.TryAdd(new ServiceDescriptor(
typeof(IStringLocalizerFactory),
typeof(SqlStringLocalizerFactory),
ServiceLifetime.Scoped));
如果 SqlStringLocalizerFactory
必须 是单例依赖项,那么您需要确保使用 ServiceSope
解决租户的作用域依赖项:
public class SqlStringLocalizerFactory
{
private readonly IServiceProvider _serviceProvider;
public SqlStringLocalizerFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void SomeMethod()
{
using (var serviceScope = _serviceProvider
.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var tenant = serviceScope.ServiceProvider.GetService<AppTenant>();
// do something with tenant...
}
}
}