我正在写一个(C# ASP.NET API)程序,打算用作SaaS。该程序具有标准功能,但旧的(非SaaS)也为每个客户提供了一些用于连接其系统的自定义代码。导致每个客户的代码版本不同。
我对此的一个解决方案是使用松散耦合。但是,我如何才能使接口的另一个实例在运行时被调用?并且优选地没有开关盒/if树。
任何关于这个解决方案的帮助都会很好,但我也想知道这是不是可行的方法?
在其他编程语言中,例如javascript,您可以加载和运行代码JIT。另一种连接的解决方案是对需要连接到客户系统的部件使用微服务。通过这样做,我可以独立于主程序更新连接器。
发布于 2021-07-29 13:14:10
您可以将依赖项注入容器中的实现连接起来,并在运行时挑选实现。
假设您有一个IDiscountCalculator接口,每个客户需求有几个不同的实现。
您将从请求中获得当前的租户/客户信息,并决定需要运行哪个实现,然后返回适当的实现。
以这个例子为例(我将抽象级别保持在最低限度)
services.AddScoped<IDiscountCalculator>(provider =>
{
// find the tenant
var user = provider.GetRequiredService<IHttpContextAccessor>().HttpContext!.User;
var tenantId = user.FindFirstValue("tenant_id");
var tenant = provider.GetRequiredService<AppDbContext>().Tenants.Single(t => t.Id == tenantId);
// return the implementation based on tenant's preferences
return tenant.DiscountType switch
{
typeof(SpecialDiscountCalculator).Name => provider.GetRequiredService<SpecialDiscountCalculator>(),
// ... other implementations
// default to standard discount
_ => provider.GetRequiredService<StandardDiscountCalculator>();
};
});为了更好地衡量,您可能会将其抽象为工厂DiscountCalculatorFactory:
class DiscountCalculatorFactory
{
private IPrincipalAccessor _principalAccessor;
private AppDbContext _dbContext;
public DiscountCalculatorFactory(AppDbContext dbContext, IPrincipalAccessor principalAccessor)
{
_dbContext = dbContext;
_principalAccessor = principalAccessor;
}
public async Task<IDiscountCalculator> CreateAsync()
{
var user = _principalAccessor.Principal;
var tenantId = user.FindFirstValue("tenant_id");
var tenant = await _dbContext.Tenants.SingleAsync(t => t.Id == tenantId);
return tenant.DiscountType switch
{
typeof(SpecialDiscountCalculator).FullName => provider.GetRequiredService<SpecialDiscountCalculator>(),
// ... other implementations
// default
_ => provider.GetRequiredService<DefaultDiscountCalculator>();
};
}
}
public interface IPrincipalAccessor {
ClaimsPrincipal? Principal { get; }
}
public class HttpPrincipalAccessor : IPrincipalAccessor
{
private IHttpContextAccessor _httpContextAccessor;
public HttpPrincipalAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public ClaimsPrincipal? Principal => _httpContextAccessor?.HttpContext?.User;
}https://stackoverflow.com/questions/68576342
复制相似问题