SOF*_*ser 0 c# webforms inversion-of-control autofac
我们有一些遗留应用程序假设我们无法更改该 SiteSettings 类,因为完整的项目编码数千行会干扰。所以我们想用 DI 解决问题。我在这里创建了 POC 应用程序,您可以在global asax评论中 看到//HOW CAN I PASS TenantId HERE so it will be same for this complete httprequest life.
遗留代码:
public class OrderController
{
public static string CompleteOrder()
{
return SiteSettings.Instance.DefaultTimeZone();
}
}
public class SiteSettings
{
public ITenantSettings TenantSettings { get; set; }
private static SiteSettings _instance;
private SiteSettings() { }
public static SiteSettings Instance => _instance ?? (_instance = new SiteSettings());
public string DefaultTimeZone()
{
return TenantSettings.DefaultTimeZone();
}
}
Run Code Online (Sandbox Code Playgroud)
新的注射类
public interface ITenantSettings
{
string DefaultTimeZone();
}
public class TenantSettings : ITenantSettings
{
private readonly int _tenantId;
public TenantSettings(int tenantId)
{
_tenantId = tenantId;
}
public string DefaultTimeZone()
{
return "USA Time For Tenant ID " + _tenantId.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
全球ASAX
public class Global : HttpApplication, IContainerProviderAccessor
{
// Provider that holds the application container.
static IContainerProvider _containerProvider;
// Instance property that will be used by Autofac HttpModules
// to resolve and inject dependencies.
public IContainerProvider ContainerProvider => _containerProvider;
protected void Application_Start(object sender, EventArgs e)
{
// Build up your application container and register your dependencies.
var builder = new ContainerBuilder();
builder.RegisterType<TenantSettings>().As<ITenantSettings>().InstancePerRequest();
_containerProvider = new ContainerProvider(builder.Build());
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
int id = 0;
int.TryParse(HttpContext.Current.Request.QueryString["id"], out id);
var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
var cp = cpa.ContainerProvider;
cp.RequestLifetime.InjectProperties(SiteSettings.Instance);
//HOW CAN I PASS TENANTID HERE so it will be same for this complete httprequest life.
}
}
Run Code Online (Sandbox Code Playgroud)
默认 ASPX
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(OrderController.CompleteOrder());
}
}
Run Code Online (Sandbox Code Playgroud)
错误 :
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'CoreLibrary.Tenants.TenantSettings' can be invoked with the available services and parameters:
Cannot resolve parameter 'Int32 tenantId' of constructor 'Void .ctor(Int32)'.
Run Code Online (Sandbox Code Playgroud)
您可以使用WithParameter,在这种情况下,我建议使用ResolvedParameter:
builder.RegisterType<TenantSettings>()
.As<ITenantSettings>()
.InstancePerRequest()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(int) && pi.Name == "tenantId",
(pi, ctx) => int.Parse(HttpContext.Current.Request.QueryString["id"])));
Run Code Online (Sandbox Code Playgroud)
实际上,您将需要一些比int.Parse(HttpContext.Current.Request.QueryString["id"])这更具弹性的东西,但这为您提供了解决方案的味道
_instance ?? (_instance = new SiteSettings())如果我们要注入依赖项,我们需要删除该行。在我的例子中SiteSettings现在有一个static Initialise方法,这个方法用于构造的值SiteSettings.Instance。
目前我们只对注入感兴趣,ITenantSettings因为我们希望ITenantSettings有一个比SiteSettings(单例)的范围更小的生命周期范围(每个请求),我们应该注入一个委托(Func<ITenantSettings>)。
public class SiteSettings
{
private static SiteSettings _instance;
private Func<ITenantSettings> _tenantSettingsFactory;
private SiteSettings(Func<ITenantSettings> tenantSettingsFactory)
{
_tenantSettingsFactory = tenantSettingsFactory;
}
public static void Initialise(Func<ITenantSettings> tenantSettingsFactory)
{
_instance = new SiteSettings(tenantSettingsFactory);
}
public ITenantSettings TenantSettings { get { return _tenantSettingsFactory(); } }
public static SiteSettings Instance
{
get {
if (_instance == null) throw new InvalidOperationException();
return _instance;
}
}
public string DefaultTimeZone()
{
return TenantSettings.DefaultTimeZone();
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个测试,演示了您的要求:
[Fact]
public void Demonstrate_TenantSettingsFactory_AlwaysResolvesCurrentTenantId()
{
int tenantId = 0;
var builder = new ContainerBuilder();
builder.RegisterType<TenantSettings>()
.As<ITenantSettings>()
.WithParameter(
new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(int) && pi.Name == "tenantId",
(pi, ctx) => tenantId));
var container = builder.Build();
SiteSettings.Initialise(container.Resolve<ITenantSettings>);
tenantId = 1;
Assert.Equal("USA Time For Tenant ID 1", SiteSettings.Instance.DefaultTimeZone());
tenantId = 2;
Assert.Equal("USA Time For Tenant ID 2", SiteSettings.Instance.DefaultTimeZone());
}
Run Code Online (Sandbox Code Playgroud)
注意我删除了InstancePerRequest,HttpContext.Current因为我正在使用单元测试项目。
| 归档时间: |
|
| 查看次数: |
361 次 |
| 最近记录: |