![](/img/trans.png)
[英]How to handle the exception thrown by the async method with observable?
[英]How to handle exception thrown from Controller's Initialize method?
题:
如何处理从Controller的Initialize方法引发的异常?
背景故事:
我们拥有用于单个数据库的.NET MVC应用程序。 我们有许多控制器在构造函数中创建数据库上下文作为成员,然后在操作中使用它。 连接字符串存储在Web.config中。 新的要求是我们要在同一应用程序实例( 多租户 )中支持多个客户端,每个客户端都具有单独的数据库。 我们不希望控制器知道多个数据库的存在。 我们有目录数据库,可以从该数据库获取给定的客户端连接字符串。 最初的方法是为覆盖Controller的控制器创建通用基础。由于这是我们可以获取用户身份和查询目录数据库的客户端连接字符串并初始化数据库上下文的第一个位置,因此请进行初始化。 直到我们发现需要不将用户连接到任何特定数据库为止,它的工作效果都很好。 然后的想法是在Initialize中引发异常,并在异常过滤器中捕获该异常,以将用户重定向到页面,通知此页面功能需要分配给数据库。 不幸的是,初始化不是动作,并且从它引发的异常对于过滤器不可用。
根据您的问题,我了解到您正在为要构建的应用程序启用承租人数据库模型。 在这种情况下,您应该有一家从事以下工作的工厂
简而言之,您应该拥有类似下面的内容
public interface ITenantShardResolver
{
/// <summary>
/// Gets the tenant specific shard based connection from the metadata
/// </summary>
/// <param name="tenantId">The tenant identifier</param>
/// <param name="connectionStringName">The Connection string name</param>
/// <returns>
/// The DbConnection for the specific shard per tenant
/// <see cref="DbConnection"/>
/// </returns>
DbConnection GetConnection(Guid tenantId, string connectionStringName);
}
上面是一个通用接口,可用于基于已建立的租户上下文获取连接字符串。
基本数据库上下文看起来类似于以下内容,
public abstract class EntitiesContext : DbContext, IEntitiesContext
{
/// <summary>
/// Constructs a new context instance using conventions to create the name of
/// the database to which a connection will be made. The by-convention name is
/// the full name (namespace + class name) of the derived context class. See
/// the class remarks for how this is used to create a connection.
/// </summary>
protected EntitiesContext() : base()
{
}
/// <summary>
/// Initializes the entity context based on the established user context and the tenant shard map resolver
/// </summary>
/// <param name="userContext">The user context</param>
/// <param name="shardResolver">The Tenant Shard map resolver</param>
/// <param name="nameorConnectionString">The name or the connection string for the entity</param>
protected EntitiesContext(MultiTenancy.Core.ProviderContracts.IUserContextDataProvider userContext, ITenantShardResolver shardResolver, string nameorConnectionString)
: base(shardResolver.GetConnection(userContext.TenantId, nameorConnectionString), true)
{
}
}
示例上下文如下所示,
public class AccommodationEntities : EntitiesContext
{
public AccommodationEntities(IUserContextDataProvider userContextProvider, ITenantShardResolver shardResolver)
: base(userContextProvider, shardResolver, "AccommodationEntities")
{ }
// NOTE: You have the same constructors as the DbContext here. E.g:
public AccommodationEntities() : base("AccommodationEntities") { }
public IDbSet<Country> Countries { get; set; }
public IDbSet<Resort> Resorts { get; set; }
public IDbSet<Hotel> Hotels { get; set; }
}
可以与上述上下文对话的基础服务看起来像下面的那种
public abstract class MultiTenantServices<TEntity, TId>
where TEntity : class, IMultiTenantEntity<TId>
where TId : IComparable
{
private readonly IMultiTenantRepository<TEntity, TId> _repository;
/// <summary>
/// Initializes a new instance of the <see cref="MultiTenantServices{TEntity, TId}"/> class.
/// </summary>
/// <param name="repository">The repository.</param>
protected MultiTenantServices(IMultiTenantRepository<TEntity, TId> repository)
{
_repository = repository;
}
样本实体服务如下图所示,
public class CountryService : MultiTenantServices<Country, int>
{
IMultiTenantRepository<Country, int> _repository = null;
public CountryService(IMultiTenantRepository<Country, int> repository) : base(repository)
{
_repository = repository;
}
上面的代码段说明了一种经过良好测试的好方法,可以组织/构建用于多租户的应用程序。
HTH
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.