使用ABP框架中踩過的坑系列2

szdlsoft發表於2018-06-08

      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中大量使用的依賴方式是,
         
    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的配套,這塊效率可以大大提高

相關文章