2017-03-09 1 views
2

Ich habe eine .net-Core-API, die verschiedene dbcontexts mit verschiedenen Datenbanken verwenden.eingepackte Scoped-Klasse mit mehreren dbcontexts

Ich habe geschrieben eine Klasse, die alle dbcontexts Wraps:

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();    
    } 
} 

In der Startklasse I es als scoped Instanz definiert haben:

services.AddScoped((_) => new BoundedContext(Configuration["Data:Ecommerce:ConnectionString"], 
                Configuration["Data:Security:ConnectionString"], 
                Configuration["Data:CRM:ConnectionString"])); 

Controller Aktionen sind eine statische Klasse aufrufen ein Passieren oder mehrere "Befehle", so dass diese Klasse dafür verantwortlich ist, sie auszuführen und die Änderungen zu bestätigen

Ich habe ein .net Kernnetz, das diese API mit einem sdk aufruft, das von swagger erzeugt wird. Die Controller der Bahn haben einen Filter, um die Eigenschaften des angemeldeten Benutzers zu erhalten:

public override void OnActionExecuting(ActionExecutingContext context) 
{ 
    if (User.Identity.IsAuthenticated) 
     { 
      if (_currentUser == null) 
      { 
       _currentUser = ApiHandler.GetCurrentUser(_applicationId, _accessToken); 
      } 

      return _currentUser; 
     } 

     return null; 
} 

und eine Probe einer Aktion:

// 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); 
    } 

Wir nennen diese Aktionen mit einem Jquery Ajax-Aufruf. Das Problem ist, dass wir manchmal eine System.ObjectDisposedException in der "OnActionExecuting" erhalten, aber ich weiß nicht warum, weil die Klasse, die die dbcontexts verwaltet, mit der Bereichsoption injiziert wird.

Glauben Sie, dass diese Architektur schlecht ist oder fehlt mir etwas?

Antwort

0

Ich fand, wer die System.ObjectDisposedException provoziert. Ich habe eine Middleware, die das Zugriffstoken überprüft, und in der Methode invoke erstelle ich eine neue Instanz eines Kontext, da dieser Kontext eine Datenbank pro Mandant ist. Dies ist der Code, den ich in BoundedContext Klasse

public void ChangeReportConnection(string connnectionSring) 
    { 
     if (_PowerBIContext == null) 
     { 
      _PowerBIContext = new PowerBIContext(connnectionSring); 
     } 
    } 

Und der Teil der Aufrufmethode der Middleware, die den Kontext

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 });    
    } 

Also habe ich diese Methode entfernt ändern und ich nicht nennen es von der Invoke der Middleware-Klasse. Ich setze die Änderung in die powerbicontext-Eigenschaft der gebundenen Klasse wie folgt.

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

Und es scheint, dass der Fehler

gegangen
Verwandte Themen