Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CommandHandler装饰程序依赖项_C#_.net_Dependency Injection_Decorator_Cqrs - Fatal编程技术网

C# CommandHandler装饰程序依赖项

C# CommandHandler装饰程序依赖项,c#,.net,dependency-injection,decorator,cqrs,C#,.net,Dependency Injection,Decorator,Cqrs,我有一个问题,我希望我的处理程序使用从处理程序生成的数据: UpdateUserProfileImageCommandHandlerAuthorizeDecorator UpdateUserProfileImageCommandHandlerUploadDecorator UpdateUserProfileImageCommandHandler 我的问题是架构和性能 UpdateUserCommandHandlerAuthorizeDecorator调用存储库(entityframework)以

我有一个问题,我希望我的处理程序使用从处理程序生成的数据:

  • UpdateUserProfileImageCommandHandlerAuthorizeDecorator
  • UpdateUserProfileImageCommandHandlerUploadDecorator
  • UpdateUserProfileImageCommandHandler
  • 我的问题是架构和性能

    UpdateUserCommandHandlerAuthorizeDecorator
    调用存储库(entityframework)以授权用户。我还有其他类似的装饰程序,它们应该使用和修改实体,并将其发送到链的上游

    UpdateUserCommandHandler
    只需将用户保存到数据库。我目前必须进行另一个存储库调用并更新实体,而我本可以从以前的decorator处理该实体

    我的问题是,该命令只接受用户Id和一些要更新的属性。在我从Authorize decorator获取用户实体的情况下,我如何仍然处理链上的该实体?将
    User
    属性添加到命令并处理该属性可以吗

    代码:

    public类UpdateUserProfileImageCommand:Command
    {
    public UpdateUserProfileImageCommand(Guid id,流图像)
    {
    这个.Id=Id;
    这个。图像=图像;
    }
    公共流映像{get;set;}
    公共Uri ImageUri{get;set;}
    }
    公共类UpdateUserProfileImageCommandHandlerAuthorizeDecorator:ICommandHandler
    {
    公共无效句柄(UpdateUserProfileImageCommand命令)
    {
    //我想在`UpdateUserProfileImageCommandHandlerUploadDecorator'中使用此实体`
    var user=userRespository.Find(u=>u.UserId==command.Id);
    if(userCanModify(user,currentPrincipal))
    {
    decoratedHandler(命令);
    }
    }
    }
    公共类UpdateUserProfileImageCommandHandlerUploadDecorator:ICommandHandler
    {
    公共无效句柄(UpdateUserProfileImageCommand命令)
    {
    //我不想再次从存储库中请求这个,而是希望重用来自上一个decorator的实体
    var user=userRespository.Find(u=>u.UserId==command.Id);
    fileService.DeleteFile(user.ProfileImageUri);
    var command.ImageUri=fileService.Upload(generatedUri,command.Image);
    decoratedHandler(命令);
    }
    }
    公共类UpdateUserProfileImageCommandHandler:ICommandHandler
    {
    公共无效句柄(UpdateUserProfileImageCommand命令)
    {
    //我再次询问用户。。。
    var user=userRespository.Find(u=>u.UserId==command.Id);
    user.ProfileImageUri=command.ImageUri;
    //事实上,我在一家邮政装潢店有这个。
    unitOfWork.Save();
    }
    }
    
    为什么首先要通过装饰器实现这一点

    验证 通常的方法是让客户机在提交命令之前进行所有必要的验证。创建/发布/执行的任何命令在提交之前都应执行所有(合理的)验证。我之所以选择“合理”,是因为有些东西,比如独特性,是无法事先100%验证的。当然,执行命令的授权可以在提交命令之前完成

    拆分命令处理程序 拥有一个只处理命令处理逻辑的一部分,然后丰富命令对象的装饰器对我来说似乎过于工程化了。首先,应该使用decorator来扩展给定的操作,并提供额外的功能,例如日志记录、事务或身份验证(尽管如我所说,我认为这不适用于修饰命令处理程序)

    似乎上传图像,然后在数据库中分配新的图像URL是一个命令处理程序的责任。如果您希望抽象这两个不同操作的细节,那么就向处理程序中注入这样做的类,比如
    IUserimageUploader

    通常地
    通常,命令被认为是不可变的,并且在创建后不应更改。这有助于强制要求命令应预先包含完成操作所需的所有信息。

    您不应仅为了性能而传递任何额外数据。此外,usng装饰师,你不能更改合同。相反,您应该允许缓存该用户实体,这通常应由存储库实现负责。对于实体框架,这实际上相当简单。您可以调用
    DbSet.Find(id)
    ,EF将首先在缓存中查找实体。这可以防止不必要的数据库往返。我总是这样做

    因此,您只需将
    Find(key)
    GetById
    方法添加到您的存储库中,该方法映射到EF的
    Find(key)
    方法,就完成了

    此外,我同意皮特的观点。装饰器应该主要用于交叉关注点。在decorators中添加其他东西有时可以,但是您似乎在处理程序及其decorator上拆分了核心业务逻辑。将文件写入磁盘需要很长的时间才能到达核心逻辑。你可能会考虑坚持单一责任,但在我看来,你将单一责任分解为多个类。这并不意味着您的命令处理程序应该很大。正如Pete所说,您可能希望将其提取到一个服务中,并将该服务注入到处理程序中

    验证授权是一个贯穿各领域的问题,因此在decorator中使用它似乎是可以的,但是您当前的实现存在一些问题。首先,这样做会导致有许多非通用的装饰器,这会导致大量的维护。此外,如果用户未经授权(通常不是您想要的),您会自动跳过执行

    <>不要静静地跳过,考虑抛出一个异常并防止
    public class UpdateUserProfileImageCommand : Command
    {
        public UpdateUserProfileImageCommand(Guid id, Stream image)
        {
            this.Id = id;
            this.Image = image;
        }
    
        public Stream Image { get; set; }
    
        public Uri ImageUri { get; set; }
    }
    
    public class UpdateUserProfileImageCommandHandlerAuthorizeDecorator : ICommandHandler<UpdateUserProfileImageCommand>
    {
        public void Handle(UpdateUserProfileImageCommand command)
        {
             // I would like to use this entity in `UpdateUserProfileImageCommandHandlerUploadDecorator`
             var user = userRespository.Find(u => u.UserId == command.Id);
    
             if(userCanModify(user, currentPrincipal))
             {
                 decoratedHandler(command);
             }
    
        }
    }
    
    public class UpdateUserProfileImageCommandHandlerUploadDecorator : ICommandHandler<UpdateUserProfileImageCommand>
    {
        public void Handle(UpdateUserProfileImageCommand command)
        {
             // Instead of asking for this from the repository again, I'd like to reuse the entity from the previous decorator
             var user = userRespository.Find(u => u.UserId == command.Id);
    
             fileService.DeleteFile(user.ProfileImageUri);
    
             var command.ImageUri = fileService.Upload(generatedUri, command.Image);
    
             decoratedHandler(command);       
    
        }
    }
    
    public class UpdateUserProfileImageCommandHandler : ICommandHandler<UpdateUserProfileImageCommand>
    {
        public void Handle(UpdateUserProfileImageCommand command)
        {
             // Again I'm asking for the user...
             var user = userRespository.Find(u => u.UserId == command.Id);
    
             user.ProfileImageUri = command.ImageUri;     
    
             // I actually have this in a PostCommit Decorator.
             unitOfWork.Save();
        }
    }
    
    [PermittedRole(Role.LabManagement)]
    
    public class UpdateUserProfileImageCommandHandler 
        : ICommandHandler<UpdateUserProfileImageCommand>
    {
        private readonly IFileService fileService;
    
        public UpdateUserProfileImageCommandHandler(IFileService fileService)
        {
            this.fileService = fileService;
        }
    
        public void Handle(UpdateUserProfileImageCommand command)
        {
             var user = userRespository.GetById(command.Id);
    
             this.fileService.DeleteFile(user.ProfileImageUri);
    
             command.ImageUri = this.fileService.Upload(generatedUri, command.Image);
    
             user.ProfileImageUri = command.ImageUri;     
        }
    }