2017-03-09 9 views
2

異なるデータベースで異なるdbcontextを使用する.netコアAPIがあります。複数のdbcontextを持つスコープ付きラップされたクラス

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

コントローラのアクションは1を渡し静的クラスを呼び出している:私はスコープのインスタンスとして定義されているスタートアップクラスで

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

は、私はすべてのdbcontextsをラップするクラスを書いていますまたはいくつかの "コマンド"を使用して、このクラスがそれを実行して変更をコミットする責任を負うようにします。

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

私はswaggerによって生成されたsdkでこのapiを呼び出す.netコアウェブを持っています。ウェブのコントローラは、ログインしているユーザーのプロパティを取得するフィルタを持っている:

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を管理するクラスがスコープ付きオプションで注入されているのかわかりません。

あなたはこのアーキテクチャが悪いと思うか、何か不足していますか?

答えて

0

誰がSystem.ObjectDisposedExceptionを引き起こすのかがわかりました。私はアクセストークンをチェックするミドルウェアを持っており、このコンテキストはテナントごとに1つのデータベースであるため、呼び出しメソッドではコンテキストの1つの新しいインスタンスを作成します。これは私が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 {} 
    } 

そして、エラーがなくなっているようだ

関連する問題