1

저는 리포지토리 및 UnitOfWork 패턴을 구현하는 N 계층 MVC 4 응용 프로그램을 구축하고 있으며, 내 구성 요소를 검증하고 실행하는 추상화 된 CommandProcessor 계층을 사용하여 도메인 기반 디자인을 구현하고 있습니다. CommandModels.워크 플로를 사용하는 MVC 응용 프로그램의 도메인 기반 디자인 - 디자인 결정

이제 Workflow Foundation을 배우기 시작했으며 사용자 등록을 처리하는 워크 플로 프로젝트를 추가했습니다. 모든 겪은 경우 워크 플로우의 끝에서, 워크 플로는 ApproveMembership CodeActivity를 실행합니다 : 또한 그가 유효성을 확인하지 않을 경우 일정 시간 후 사용자를 삭제하는 유사한 RemoveMembership 활동이

public sealed class ApproveMembership : CodeActivity 
{ 
    [RequiredArgument] 
    public InArgument<string> UserEmail { get; set; } 

    protected override void Execute(CodeActivityContext context) 
    { 
     IDatabaseFactory databaseFactory = new DatabaseFactory(); 
     IUnitOfWork unitOfWork = new UnitOfWork(databaseFactory); 
     IUserRepository userRepository = new UserRepository(databaseFactory); 

     string userEmail = UserEmail.Get(context); 

     User user = userRepository.Get(u => u.Email == userEmail); 

     if (user != null) 
     { 
      user.Activated = true; 
      userRepository.Update(user); 
      unitOfWork.Commit(); 
     } 
    } 
} 

.

내 질문에 내 워크 플로우에서이 권리를 처리하는 것이 맞습니까? 또는 작업 흐름에서 Dependency Injection을 사용하여 유효성 검사 및 제출 처리기와 함께 새로 작성해야하는 거의 동일한 2 개의 명령 모델을 처리하는 CommandBus를 얻는 것이 더 좋은 방법일까요? 이것이 내 MVC AccountController에서 수행되는 방법입니다.

public class DeleteUserCommand : ICommand 
    { 
     public int UserId { get; set; } 
    } 
    public class ApproveUserCommand : ICommand 
    { 
     public int UserId { get; set; } 
    } 

    public sealed class RemoveMembership : CodeActivity 
    { 
     public InArgument<string> UserEmail { get; set; } 

     private readonly ICommandBus commandBus; 
     private readonly IUserRepository userRepository; 

     public RemoveMembership(ICommandBus commandBus, IUserRepository userRepository) 
     { 
      this.commandBus = commandBus; 
      this.userRepository = userRepository; 
     } 

     protected override void Execute(CodeActivityContext context) 
     { 
      string userEmail = UserEmail.Get(context); 
      User user = userRepository.Get(u => u.Email == userEmail); 

      if (user != null) 
      { 
       var command = new DeleteUserCommand 
       { 
        UserId = user.UserId 
       }; 

       IEnumerable<ValidationResult> errors = commandBus.Validate(command); 
       if (!errors.Any()) 
       { 
        commandBus.Submit(command); 
       } 
      } 
     } 
    } 

확실히 더 많은 코드가 있지만 좋은 디자인입니까?

나는이 글을 쓰면서 나 자신의 질문에 답하는 것처럼 느껴지고 대답은 '예'라고 생각하고있다. 그러나 여전히 전문적인 의견을 듣고 싶습니다.

답변

2

내 질문은 내 워크 플로우에서이 바로 처리하는 것이 맞습니까?

난 당신이 응용 프로그램 서비스에 CodeActivity 내부에 가지고 응용 프로그램 서비스가 워크 플로 참조가 코드를 캡슐화하는 것 :

class UserApplicationService 
{ 
    public void ApproveMembership(string userEmail) 
    { 
     var user = userRepository.Get(u => u.Email == userEmail); 
     if (user != null) 
     { 
      user.Activated = true; 
      userRepository.Update(user); 
     } 
    } 
} 


public sealed class ApproveMembership : CodeActivity 
{ 
    [RequiredArgument] 
    public InArgument<string> UserEmail { get; set; } 

    protected override void Execute(CodeActivityContext context) 
    { 
     var userEmail = UserEmail.Get(context); 
     this.userService.ApproveMembership(userEmail); 
    } 
} 

이에 대한 동기는 WWF가의 인프라 구성 요소라는 것이다 당신의 아키텍처이며 도메인 논리에서 인프라를 분리하는 데 적합합니다. WWF는 동일한 응용 프로그램 서비스를 참조하는 NServiceBus와 같은 것으로 대체 될 수 있습니다. 어떤 사람들은 이것이 YAGNI의 사례라고하지만, 나는 도메인 코드를위한 인프라를 분리하는 것이 코드 품질과 도메인에 대한 추론 능력면에서 매우 유리하다고 생각합니다.

응용 프로그램 서비스가 Commit을 명시 적으로 호출 할 필요가 없도록 작업 단위 코드를 인프라에 최대한 밀어 넣는 것이 좋습니다.

또는 대한 검증 및 제출 핸들러와 함께, 내가 만들어야 할 것이다 2 개의 새로운, 거의 동일한 명령 모델을 가공 처리하는 CommandBus을 얻을 수있는 워크 플로우 에 의존성 삽입 (Dependency Injection)를 사용하는 더 나은 방법입니다 그들?

이것은 내 제안에 더 가깝지만 코드 예제를 바탕으로 한 단계 더 나아가 CodeActivity 내부의 로직을 응용 프로그램 서비스로 추출하거나 응용 프로그램을 구조화하는 것이 좋습니다. 저장소에 대한 액세스가 필요없이 명령을 전달할 수 있습니다.

+0

훌륭한 답변 주셔서 감사합니다.서비스 종속성에 관해서는 ServiceLocator 패턴이 WWF에서 DI와 동일한 것으로 나타 났으며이 패턴을 사용하여 사용자가 말한 것을 성취 할 것입니다. 다시 한번 감사드립니다. http://stackoverflow.com/a/3828323/1267778 – parliament