使用ABP框架踩过的坑系列2

ABP中有很多惯例,如果使用得当,可以事半功倍,如果使用不当,也会有很大的麻烦,是否适当其实还是要看Need需求

ASP.NET Boilerplate (ABP) is an open source and well documented application framework started idea of "developing a common framework for all companies and all developers!" It's not just a framework but also provides a strong architectural model based on Domain Driven Design and best practices in mind. 开源和文档友好,适合所有公司所有开发者的公共框架,基于DDD提供强壮架构,并且是最佳实践,这是作者的预期目标。
    看一下,代码例子,也许是程序员更喜欢的方式:
public class TaskAppService : ApplicationService, ITaskAppService
{
    private readonly IRepository<Task> _taskRepository;

    public TaskAppService(IRepository<Task> taskRepository)
    {
        _taskRepository = taskRepository;
    }

    [AbpAuthorize(MyPermissions.UpdatingTasks)]
    public async Task UpdateTask(UpdateTaskInput input)
    {
        Logger.Info("Updating a task for input: " + input);

        var task = await _taskRepository.FirstOrDefaultAsync(input.TaskId);
        if (task == null)
        {
            throw new UserFriendlyException(L("CouldNotFoundTheTaskMessage"));
        }

        input.MapTo(task);
    }
}
 
Here, we see a sample Application Service method. An application service, in DDD, is directly used by presentation layer to perform use cases of the application. We can think that UpdateTask method is called by javascript via AJAX. Let's see ABP's some benefits here:
Application Service 的方法,在DDD中对应的是UseCase用例,用例是什么?是用户需求,不清楚的同学请参考《有效需求分析》一书。从B/S角度看,该方法是由页面中js的AJAX调用的(其实也可能是被手机端APP调用的)。这个方式带来以下好处(注意要使用得当才有的,否则适得其反)
    • Dependency Injection : ABP uses and provides a strong and conventional DI infrastructure. Since this class is an application service, it's conventionally registered to DI container as transient (created per request). It can simply inject all dependencies (as IRepository<Task> in this sample).
      依赖注入,的确是个最佳实践,如果不用依赖注入,你的代码中可能由50%以上要考虑:如何实例化依赖(被调用方),但带来方便的同时,可能增加了阅读代码的难度,因为你看到的都是接口,实现都隐藏起来,找起来比较费劲。比如这里ApplicationService依赖的IRepository<Task>, 想真正了解它的代码,是间比较困难的。ABP中大量使用的依赖方式是,
           
       public override void Initialize()
              {
                  IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
              }
      也就是惯例依赖,这个对刚开始接触ABP的开发者来讲,是需要好好理解,才能好好利用
       
       public class BasicConventionalRegistrar : IConventionalDependencyRegistrar
          {
              public void RegisterAssembly(IConventionalRegistrationContext context)
              {
                  //Transient
                  context.IocManager.IocContainer.Register(
                      Classes.FromAssembly(context.Assembly)
                          .IncludeNonPublicTypes()
                          .BasedOn<ITransientDependency>()
                          .WithService.Self()
                          .WithService.DefaultInterfaces()
                          .LifestyleTransient()
                      );
      
                  //Singleton
                  context.IocManager.IocContainer.Register(
                      Classes.FromAssembly(context.Assembly)
                          .IncludeNonPublicTypes()
                          .BasedOn<ISingletonDependency>()
                          .WithService.Self()
                          .WithService.DefaultInterfaces()
                          .LifestyleSingleton()
                      );
      
                  //Windsor Interceptors
                  context.IocManager.IocContainer.Register(
                      Classes.FromAssembly(context.Assembly)
                          .IncludeNonPublicTypes()
                          .BasedOn<IInterceptor>()
                          .WithService.Self()
                          .LifestyleTransient()
                      );
              }
      以上说明,实现ITransientDependency、 ISingletonDependency 、IInterceptor 这三个接口的类会被自动Register,当然也就可以Resolve注入; 其实IOC就是和一个全局的容器,可以把它看作一个巨大的一个全局变量,就时Register和Resolve 两个步骤,你存了银行,自然也能取钱了,就这么简单。
    • Repository : ABP can create a default repository for each entity (as IRepository<Task> in this example). Default repository has many useful methods as FirstOrDefault used in this example. We can easily extend default repository upon our needs. Repositories abstracts DBMS and ORMs and simplifies data access logic.
      Repository 实际上是ABP架构代码量比较大的一部分,它抽象了DBMS和ORMS, 其实和UnitOfWork也有关联,在实际项目的CRUD方面提供了几乎所有的几十个方法,遗憾的是没有提供数据库的批量插入、批量更新, 我自己做了个扩充,到时做成nuget库分享给大家
    • Authorization : ABP can check permissions. It prevents access to UpdateTask method if current user has no "updating task" permission or not logged in. It simplifies authorization using declarative attributes but also has additional ways of authorization.
      用户和角色管理,项目中的基本模块,原来Microsoft有个MemberShip, 现在用Identity,ABP这块集成的比较好,可以真正实现声明式编程
    • Validation : ABP automatically checks if input is null. It also validates all properties of an input based on standard data annotation attributes and custom validation rules. If request is not valid, it throws a proper validation exception.
      声明式验证,加上少量代码,基本上可以满足Need, 关键是直接用于DTO,而且有UI的配套,这块效率可以大大提高
posted @ 2018-06-11 11:27 szdlsoft 阅读(...) 评论(...) 编辑 收藏