2017-03-09 3 views
2

다른 데이터베이스와 다른 dbcontext를 사용하는 .net 코어 API가 있습니다.여러 개의 dbcontext가 포함 된 범위 클래스가 랩핑되었습니다.

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

컨트롤러 행동 하나를 통과하는 정적 클래스를 호출 : 내가 범위의 경우로 정의 된 시작 클래스에서

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와 아약스 호출이 작업을 호출 웹의 컨트롤러는 로그인 한 사용자의 등록 정보를 얻을 수있는 필터가 있습니다. 문제는 "OnActionExecuting"에서 System.ObjectDisposedException을받는 경우가 있지만 dbcontexts를 관리하는 클래스가 범위 옵션과 함께 주입 되었기 때문에 이유를 알 수 없다는 것입니다.

이 아키텍처가 좋지 않다고 생각하나요, 아니면 누락 되었습니까?

답변

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

그리고 오류가 간 것 같다