包含多个dbcontexts的作用域类

时间:2017-03-09 18:34:20

标签: c# entity-framework asp.net-core-1.0

我有一个.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选项注入的。

你认为这种架构是坏的还是我错过了什么?

1 个答案:

答案 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 {}
    }

似乎错误已经消失