2017-03-09 20 views
2

我有一個.net核心api,它在不同的數據庫中使用不同的dbcontexts。包裝帶多個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。網絡的控制器有一個過濾器,以獲得登錄用戶的屬性:

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調用這個動作。問題是,有時我們在「OnActionExecuting」中收到System.ObjectDisposedException,但我不知道爲什麼,因爲管理dbcontexts的類是使用scoped選項注入的。

你認爲這個架構很糟糕還是我錯過了什麼?

回答

0

我發現誰挑起System.ObjectDisposedException。我有一箇中間件檢查訪問令牌,並在invoke方法中創建一個上下文的新實例,因爲此上下文是每個租戶的一個數據庫。這是我有BoundedContext類

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

它似乎錯誤已經