我有一个.net核心api,它使用不同的dbcontexts和不同的数据库。
我写了一个包装所有dbcontexts的类:
public class BoundedContext : IDisposable
{
public EcommerceDbContext EcommerceContext { get; }
public SecurityDbContext SecurityContext { get; }
public CRMDbContext CrmContext { get; }
public BoundedContext(string EcommerceConnectionString,
string SecurityConnectionString,
string CRMConnectionString)
{
EcommerceContext = new EcommerceDbContext(EcommerceConnectionString);
SecurityContext = new SecurityDbContext(SecurityConnectionString);
CrmContext = new CRMDbContext(CRMConnectionString);
}
public void SaveChanges()
{
if (SecurityContext != null)
SecurityContext.SaveChanges();
if (CrmContext != null)
CrmContext.SaveChanges();
if (EcommerceContext != null)
EcommerceContext.SaveChanges();
}
public void Dispose()
{
if (SecurityContext != null)
SecurityContext.Dispose();
if (CrmContext != null)
CrmContext.Dispose();
if (EcommerceContext != null)
EcommerceContext.Dispose();
}
}
在启动类中,我将其定义为范围实例:
services.AddScoped((_) => new BoundedContext(Configuration["Data:Ecommerce:ConnectionString"],
Configuration["Data:Security:ConnectionString"],
Configuration["Data:CRM:ConnectionString"]));
控制器操作正在调用一个静态类,它传递一个或多个"命令"所以这个类负责执行它并提交更改
namespace Test.Business.Services
{
public static class CommandService
{
static BoundedContext _context;
public static void Process(BoundedContext context, IEnumerable<ICommand> commands)
{
_context = context;
//actions
foreach (var command in commands)
{
command.Execute(_context);
}
foreach (var command in commands)
{
if (command is IBulkInsertCommand)
{
(command as IBulkInsertCommand).BulkInsert();
}
}
//commit
_context.SaveChanges();
//post actions
foreach (var command in commands)
{
if (command is IPostCommitCommand)
{
(command as IPostCommitCommand).PostCommitAction();
_context.SaveChanges();
}
}
}
}
}
我有一个.net核心网络,用swagger生成的sdk调用此api。 Web控制器有一个过滤器来获取已登录用户的属性:
public override void OnActionExecuting(ActionExecutingContext context)
{
if (User.Identity.IsAuthenticated)
{
if (_currentUser == null)
{
_currentUser = ApiHandler.GetCurrentUser(_applicationId, _accessToken);
}
return _currentUser;
}
return null;
}
一个动作样本:
// GET: /<controller>/
[HttpGet("{All}")]
public async Task<IActionResult> Index([FromRoute]string All)
{
GetNotificationResponse result = await ControllerHandler.GetNotifications(All, _accessToken());
return PartialView("~/Views/Notifications/v1/NotificationsList.cshtml",result);
}
我们使用jquery ajax调用来调用此操作。问题是有时我们在&#34; OnActionExecuting&#34;中收到System.ObjectDisposedException,但我不知道为什么,因为管理dbcontexts的类是使用scoped选项注入的。
你认为这种架构是坏的还是我错过了什么?
答案 0 :(得分:0)
我发现谁挑起了System.ObjectDisposedException。我有一个检查访问令牌的中间件,在invoke方法中我创建了一个上下文之一的新实例,因为这个上下文是每个租户一个数据库。这是我在BoundedContext Class
中的代码public void ChangeReportConnection(string connnectionSring)
{
if (_PowerBIContext == null)
{
_PowerBIContext = new PowerBIContext(connnectionSring);
}
}
这是中间件调用方法中改变上下文的部分
public Task Invoke(HttpContext context, BoundedContext dbcontext, ILogger<MyAuthentication> logger, IMapper mapper)
{
_logger = logger;
_mapper = mapper;
_dbcontext = dbcontext;
_context = context;
StringValues headerValue;
string encodedJwt = null;
if (!_context.Request.Headers.TryGetValue("Authorization", out headerValue))
{
return _next(_context);
}
encodedJwt = headerValue.FirstOrDefault(h => h.Contains(_options.AuthentiacionOptions.AuthenticationScheme));
if (!string.IsNullOrWhiteSpace(encodedJwt))
{
encodedJwt = encodedJwt.Substring((_options.AuthentiacionOptions.AuthenticationScheme.Length + 1));
}
if (!string.IsNullOrWhiteSpace(encodedJwt))
{
var handler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = null;
SecurityToken validToken = null;
principal = handler.ValidateToken(encodedJwt, _options.tokenValidationParameters, out validToken);
_context.User = principal;
setReportConnectionString();
}
return _next(_context);
}
private void setReportConnectionString()
{
var changeDatabaseCommand = new ChangeDatabaseCommand(_mapper, _context.User);
CommandService.Process(_dbcontext, new ICommand[] { changeDatabaseCommand });
}
所以我删除了这个方法,并没有从中间件类的Invoke中调用它。我将更改放在有界类的powerbicontext属性中。就像这样。
public PowerBIContext PowerBIContext{
get
{
if (_PowerBIContext == null)
{
string ticket = GetTicket();
if (!string.IsNullOrEmpty(ticket))
{
int company = GetUserCompany(ticket);
if (company > 0)
{
string connectionString = GetPowerBIConnectionString(company);
if (!string.IsNullOrEmpty(connectionString))
{
_PowerBIContext = new PowerBIContext(connectionString);
}
}
}
}
return _PowerBIContext;
}
private set {}
}
似乎错误已经消失