ホームページ  >  記事  >  バックエンド開発  >  ASP.NETテンプレート開発フレームワークABPシリーズのABP入門チュートリアルを詳しく解説

ASP.NETテンプレート開発フレームワークABPシリーズのABP入門チュートリアルを詳しく解説

黄舟
黄舟オリジナル
2017-10-14 10:00:278230ブラウズ

ABP は、ベスト プラクティスと最も人気のあるツールを使用した、新しい最新の Web アプリケーションの出発点です。汎用アプリケーションのベース フレームワークまたはプロジェクト テンプレートとして使用できます。次に、この記事でABPの入門チュートリアルを詳しく紹介しますので、興味のある方はぜひ一緒に見てみてください

ABPとは「ASP.NET Boilerplate Project (ASP.NET Sample Project)」の略称です。 。

ASP.NET ボイラープレートは、ベスト プラクティスと一般的なテクノロジを使用して最新の WEB アプリケーションを開発するための新しい出発点であり、普遍的な WEB アプリケーション フレームワークおよびプロジェクト テンプレートになることを目指しています。

ABP の公式 Web サイト: http://www.aspnetboilerplate.com

Github 上の ABP のオープンソース プロジェクト: https://github.com/aspnetboilerplate

ABP の起源

「DRY —」 「コードの重複を避ける」は、優れた開発者がソフトウェアを開発するときに持つ最も重要なアイデアの 1 つです。エンタープライズ WEB アプリケーションを開発する場合、ログイン ページ、ユーザー/ロール管理、権限検証、データ有効性検証、多言語/ローカリゼーションなど、誰もが同様のニーズを抱えています。高品質の大規模ソフトウェアでは、階層化アーキテクチャ、ドメイン駆動設計、依存関係注入などのいくつかのベスト プラクティスが使用されます。 ORM、データベース移行、ログなどのツールを使用する場合もあります。

エンタープライズ アプリケーションを最初から作成するのは、多くの一般的な基本タスクを繰り返す必要があるため、面倒な作業です。多くの企業は、さまざまなプロジェクトで再利用するために独自のアプリケーション フレームワークを開発し、そのフレームワークに基づいていくつかの新機能を開発しています。しかし、すべての企業がそのような強みを持っているわけではありません。もっと多くの情報を共有できれば、すべての会社またはすべてのプロジェクトで同様のコードを繰り返し記述する必要がなくなるかもしれません。筆者がこのプロジェクトを「ASP.NET Boilerplate」と名付けた理由は、ABPをプロジェクトテンプレートとして直接利用し、一般的なエンタープライズWEBアプリケーション開発の新たな出発点となることを期待しているためだ。

ABPとは何ですか?

ABP は、ベスト プラクティスと最も人気のあるツールを使用した、新しい最新の Web アプリケーションの出発点です。汎用アプリケーションのベース フレームワークまたはプロジェクト テンプレートとして使用できます。その機能は次のとおりです:

サーバー側:

  • 最新の .NET テクノロジーに基づいています (現在は ASP.NET MVC 5、Web API 2、C# 5.0 ですが、ASP.NET 5 が正式にリリースされた後にアップグレードされます)

  • ドメイン駆動設計を実装します (エンティティ、ウェアハウス、ドメイン サービス、ドメイン イベント、アプリケーション サービス、データ転送オブジェクト、ワークユニットなど)

  • 階層型アーキテクチャを実装します (ドメイン層、アプリケーション層、プレゼンテーション層、ファシリティ層) は、最も人気のあるオープン ソース フレームワーク/ライブラリ (おそらく、あなたが使用しているものの一部) と統合された、再利用可能で構成可能なモジュールを開発するためのインフラストラクチャを提供します。

  • 依存関係注入を簡単に使用できるインフラストラクチャを提供します (依存関係注入のコンテナとして Castle Windsor を使用します)

  • さまざまな ORM をサポートするリポジトリ ウェアハウジング モードを提供します (Entity Framework、NHibernate、MangoDb、およびメモリは実装されたデータベース)

  • データベース移行 (EF のコード ファースト) モジュラー開発をサポートおよび実装します (各モジュールには独立した EF DbContext があり、データベースは個別に指定できます)

  • シンプルで柔軟な多言語/ローカルが含まれますシステム

  • には、サーバー側でグローバル ドメイン イベントの統合例外処理を実装するための EventBus が含まれています (アプリケーション層は独自の例外処理コードを記述する必要がほとんどありません)

  • データの有効性検証 (Asp.NET MVC) Action メソッドのパラメータ検証に対して、ABP はアプリケーション層メソッドのパラメータ有効性検証を実装することしかできません)

  • Application Services を通じて Web API 層を自動的に作成します (ApiController 層を記述する必要はありません)

  • 基本クラスとヘルパー クラスを提供します。「構成よりも規約」を使用して、いくつかの一般的なタスクを簡単に実装します

  • クライアント:

Bootstrap、Less、AngularJs、jQuery、Modernizr およびその他の JS ライブラリ: jQuery.validate 、 jQuery.form、 jQuery.blockUI、 json2 など

  • シングルページ アプリケーション (AngularJs、Durandaljs) およびマルチページ アプリケーション (Bootstrap+Jquery) のプロジェクト テンプレートを提供します。

  • Web API を使用して一部の Javascript 関数をカプセル化し、Ajax、メッセージ ボックス、通知コンポーネント、ビジー ステータス マスク レイヤーなどを簡単に使用できるようにするために、JavaScript プロキシ レイヤーを自動的に作成します。

  • ABP フレームワーク プロジェクトを除く さらに、次の機能を実装するために「Zero」という名前のモジュールも開発されました:

認証および承認管理 (ASP.NET Identity を通じて実装)

  • ユーザーおよびロール管理システム設定 アクセス管理 (システムレベル、テナントレベル、ユーザーレベル、スコープの自動管理)

  • 監査ログ (呼び出し元と各インターフェイスのパラメータを自動的に記録)

  • ABP とは何ですか?

ABP は、ベスト プラクティスのためのアプリケーション開発モデルを提供します。これには、保守可能な大規模なアプリケーションを簡単に構築できる基本的なクラス、インターフェイス、ツールが含まれています。

ただし:

これは RAD ツールの 1 つではありません。RAD ツールの目的は、コーディングなしでアプリケーションを作成することです。代わりに、ABP はコーディングのベスト プラクティスを提供します。

コード生成ツールではありません。実行時に動的コードを構築する機能がいくつかありますが、コードを生成することはできません。

これはオールインワンのフレームワークではありません。代わりに、特定のタスクに一般的なツール/ライブラリを使用します (例: ORM の EF、ログ記録の Log4Net、依存関係注入コンテナーとしての Castle Windsor、SPA フレームワークの AngularJs)。

数か月間 ABP を使用した経験に基づくと、ABP は RAD ではありませんが、ABP を使用してプロジェクトを開発するのは、従来の 3 層アーキテクチャよりも明らかに高速です。

ABP はコード生成ツールではありませんが、そのおかげで私たちのプロジェクトのコードはより簡潔で標準化されており、コード生成ツールの使用に役立ちます。

私は VS2013 の Scaffolder+T4 によって開発されたコード ジェネレーターを使用しています。これは、ドメイン オブジェクトの UML クラス図に基づいて、すべてのフロントエンドとバックエンドのコードとデータベースを自動的に生成できます。シンプルな CURD モジュールはコーディングをほとんど必要としません。複雑なビジネス ロジックを使用する場合は、主にドメイン層のコードを追加するだけです。このようにして、ドメイン モデルの設計により多くの時間を費やし、コードの作成時間を短縮できます。

以下では、オリジナル作成者の「シンプル タスク システム」の例を使用して、ABP を使用してプロジェクトを開発する方法を示します

テンプレートから空の Web アプリケーションを作成します

ABP は、新しいプロジェクト用のスタートアップ テンプレートを提供します (ただし、プロジェクトを手動で作成し、nuget から ABP パッケージを取得できます。テンプレートの方法の方が簡単です)。

www.aspnetboilerplate.com/Templates にアクセスして、テンプレートからアプリケーションを作成します。

SPA (AngularJs または DurandalJs) または MPA (クラシック マルチページ アプリケーション) プロジェクトを選択できます。 ORM フレームワークとして Entity Framework または NHibernate を選択できます。

ここでは、AngularJs と Entity Framework を選択し、プロジェクト名「SimpleTaskSystem」を入力し、「CREATE MY PROJECT」ボタンをクリックして zip パッケージをダウンロードし、それを解凍して VS2013 ソリューションを取得します。使用される .NET バージョンは 4.5 です。 1.

Abp コンポーネントとその他のサードパーティ コンポーネントは各プロジェクトで参照されており、Nuget からダウンロードする必要があります。

黄色の感嘆符アイコンは、このコンポーネントがローカル フォルダーに存在しないため、Nuget から復元する必要があることを示します。操作は次のとおりです:

プロジェクトを実行するには、データベースを作成する必要があります。このテンプレートは、SQL2008 以降を使用していることを前提としています。もちろん、他のリレーショナル データベースに簡単に置き換えることもできます。

Web.Config ファイルを開いてリンク文字列を表示および構成します:


<add name="Default" connectionString="Server=localhost; Database=SimpleTaskSystemDb; Trusted_Connection=True;" />

(後で EF のコード最初のデータ移行を使用すると、SimpleTaskSystemDb という名前のデータベースが SQL Server データベースに自動的に作成されます。)

以上で、プロジェクトを実行する準備が整いました。 VS2013 を開いて F5 キーを押します:

以下は、この単純なタスク システム プログラムをステップごとに実装します

エンティティを作成します

エンティティはドメインの一部であるため、Core プロジェクトにエンティティ クラスを書き込みます層。

簡単なアプリケーション シナリオ: いくつかのタスクを作成し、それらを人々に割り当てます。 Task と Person という 2 つのエンティティが必要です。

タスク エンティティには、説明 (Description)、作成時間 (CreationTime)、タスク ステータス (State)、および個人を参照するためのオプションのナビゲーション属性 (Assignedperson) といういくつかの属性があります。


public class Task : Entity<long>
{
 [ForeignKey("AssignedPersonId")]
 public virtual Person AssignedPerson { get; set; }

 public virtual int? AssignedPersonId { get; set; }

 public virtual string Description { get; set; }

 public virtual DateTime CreationTime { get; set; }

 public virtual TaskState State { get; set; }

 public Task()
 {
  CreationTime = DateTime.Now;
  State = TaskState.Active;
 }
}

person エンティティはより単純で、Name 属性のみを定義します。


public class Person : Entity
{
 public virtual string Name { get; set; }
}

ABP フレームワークには、Id 属性を持つ Entity 基本クラスがあります。 Task クラスは Entity4db15037c2d45d75b28ec2b6a696f099 を継承するため、long 型の ID を持ちます。タイプが指定されていない場合、エンティティの ID は int タイプであるため、Person クラスの ID は int タイプになります。

DbContext を作成する

EntityFramework を使用するには、まず DbContext クラスを定義する必要があります。IDbSet に Task クラスと Person クラスを追加するだけです。コード:


public class SimpleTaskSystemDbContext : AbpDbContext
{
 public virtual IDbSet<Task> Tasks { get; set; }

 public virtual IDbSet<Person> People { get; set; }

 public SimpleTaskSystemDbContext()
  : base("Default")
 {

 }

 public SimpleTaskSystemDbContext(string nameOrConnectionString)
  : base(nameOrConnectionString)
 {
   
 }
}

通过Database Migrations创建数据库表

我们使用EntityFramework的Code First模式创建数据库架构。ABP模板生成的项目已经默认开启了数据迁移功能,我们修改SimpleTaskSystem.EntityFramework项目下Migrations文件夹下的Configuration.cs文件:


internal sealed class Configuration : DbMigrationsConfiguration<SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext>
{
 public Configuration()
 {
  AutomaticMigrationsEnabled = false;
 }

 protected override void Seed(SimpleTaskSystem.EntityFramework.SimpleTaskSystemDbContext context)
 {
  context.People.AddOrUpdate(
   p => p.Name,
   new Person {Name = "Isaac Asimov"},
   new Person {Name = "Thomas More"},
   new Person {Name = "George Orwell"},
   new Person {Name = "Douglas Adams"}
   );
 }
}

在VS2013底部的“程序包管理器控制台”窗口中,选择默认项目并执行命令“Add-Migration InitialCreate”

会在Migrations文件夹下生成一个xxxx-InitialCreate.cs文件,内容如下:


public partial class InitialCreate : DbMigration
{
 public override void Up()
 {
  CreateTable(
   "dbo.StsPeople",
   c => new
    {
     Id = c.Int(nullable: false, identity: true),
     Name = c.String(),
    })
   .PrimaryKey(t => t.Id);
   
  CreateTable(
   "dbo.StsTasks",
   c => new
    {
     Id = c.Long(nullable: false, identity: true),
     AssignedPersonId = c.Int(),
     Description = c.String(),
     CreationTime = c.DateTime(nullable: false),
     State = c.Byte(nullable: false),
    })
   .PrimaryKey(t => t.Id)
   .ForeignKey("dbo.StsPeople", t => t.AssignedPersonId)
   .Index(t => t.AssignedPersonId);   
 }
  
 public override void Down()
 {
  DropForeignKey("dbo.StsTasks", "AssignedPersonId", "dbo.StsPeople");
  DropIndex("dbo.StsTasks", new[] { "AssignedPersonId" });
  DropTable("dbo.StsTasks");
  DropTable("dbo.StsPeople");
 }
}

然后继续在“程序包管理器控制台”执行“Update-Database”,会自动在数据库创建相应的数据表:


PM> Update-Database

数据库显示如下:

(以后修改了实体,可以再次执行Add-Migration和Update-Database,就能很轻松的让数据库结构与实体类的同步)

定义仓储接口

通过仓储模式,可以更好把业务代码与数据库操作代码更好的分离,可以针对不同的数据库有不同的实现类,而业务代码不需要修改。

定义仓储接口的代码写到Core项目中,因为仓储接口是领域层的一部分。

我们先定义Task的仓储接口:


public interface ITaskRepository : IRepository<Task, long>
{

它继承自ABP框架中的IRepository泛型接口。

在IRepository中已经定义了常用的增删改查方法:

所以ITaskRepository默认就有了上面那些方法。可以再加上它独有的方法GetAllWithPeople(...)。

不需要为Person类创建一个仓储类,因为默认的方法已经够用了。ABP提供了一种注入通用仓储的方式,将在后面“创建应用服务”一节的TaskAppService类中看到。

实现仓储类

我们将在EntityFramework项目中实现上面定义的ITaskRepository仓储接口。

通过模板建立的项目已经定义了一个仓储基类:SimpleTaskSystemRepositoryBase(这是一种比较好的实践,因为以后可以在这个基类中添加通用的方法)。


public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository
{
  public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state)
  {
    //在仓储方法中,不用处理数据库连接、DbContext和数据事务,ABP框架会自动处理。
      
    var query = GetAll(); //GetAll() 返回一个 IQueryable<T>接口类型
      
    //添加一些Where条件

    if (assignedPersonId.HasValue)
    {
      query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value);
    }

    if (state.HasValue)
    {
      query = query.Where(task => task.State == state);
    }

    return query
      .OrderByDescending(task => task.CreationTime)
      .Include(task => task.AssignedPerson)
      .ToList();
  }
}

TaskRepository继承自SimpleTaskSystemRepositoryBase并且实现了上面定义的ITaskRepository接口。

创建应用服务(Application Services)

Application项目中定义应用服务。首先定义Task的应用服务层的接口:


public interface ITaskAppService : IApplicationService
{
  GetTasksOutput GetTasks(GetTasksInput input);
  void UpdateTask(UpdateTaskInput input);
  void CreateTask(CreateTaskInput input);
}

ITaskAppService继承自IApplicationService,ABP自动为这个类提供一些功能特性(比如依赖注入和参数有效性验证)。

然后,我们写TaskAppService类来实现ITaskAppService接口:


public class TaskAppService : ApplicationService, ITaskAppService
{
  private readonly ITaskRepository _taskRepository;
  private readonly IRepository<Person> _personRepository;
    
  /// <summary>
  /// 构造函数自动注入我们所需要的类或接口
  /// </summary>
  public TaskAppService(ITaskRepository taskRepository, IRepository<Person> personRepository)
  {
    _taskRepository = taskRepository;
    _personRepository = personRepository;
  }
    
  public GetTasksOutput GetTasks(GetTasksInput input)
  {
    //调用Task仓储的特定方法GetAllWithPeople
    var tasks = _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);

    //用AutoMapper自动将List<Task>转换成List<TaskDto>
    return new GetTasksOutput
        {
          Tasks = Mapper.Map<List<TaskDto>>(tasks)
        };
  }
    
  public void UpdateTask(UpdateTaskInput input)
  {
    //可以直接Logger,它在ApplicationService基类中定义的
    Logger.Info("Updating a task for input: " + input);

    //通过仓储基类的通用方法Get,获取指定Id的Task实体对象
    var task = _taskRepository.Get(input.TaskId);

    //修改task实体的属性值
    if (input.State.HasValue)
    {
      task.State = input.State.Value;
    }

    if (input.AssignedPersonId.HasValue)
    {
      task.AssignedPerson = _personRepository.Load(input.AssignedPersonId.Value);
    }

    //我们都不需要调用Update方法
    //因为应用服务层的方法默认开启了工作单元模式(Unit of Work)
    //ABP框架会工作单元完成时自动保存对实体的所有更改,除非有异常抛出。有异常时会自动回滚,因为工作单元默认开启数据库事务。
  }

  public void CreateTask(CreateTaskInput input)
  {
    Logger.Info("Creating a task for input: " + input);

    //通过输入参数,创建一个新的Task实体
    var task = new Task { Description = input.Description };

    if (input.AssignedPersonId.HasValue)
    {
      task.AssignedPersonId = input.AssignedPersonId.Value;
    }

    //调用仓储基类的Insert方法把实体保存到数据库中
    _taskRepository.Insert(task);
  }
}

TaskAppService使用仓储进行数据库操作,它通往构造函数注入仓储对象的引用。

数据验证

如果应用服务(Application Service)方法的参数对象实现了IInputDto或IValidate接口,ABP会自动进行参数有效性验证。

CreateTask方法有一个CreateTaskInput参数,定义如下:


public class CreateTaskInput : IInputDto
{
  public int? AssignedPersonId { get; set; }

  [Required]
  public string Description { get; set; }
}

Description属性通过注解指定它是必填项。也可以使用其他 Data Annotation 特性。

如果你想使用自定义验证,你可以实现ICustomValidate 接口:


public class UpdateTaskInput : IInputDto, ICustomValidate
{
  [Range(1, long.MaxValue)]
  public long TaskId { get; set; }

  public int? AssignedPersonId { get; set; }

  public TaskState? State { get; set; }

  public void AddValidationErrors(List<ValidationResult> results)
  {
    if (AssignedPersonId == null && State == null)
    {
      results.Add(new ValidationResult("AssignedPersonId和State不能同时为空!", new[] { "AssignedPersonId", "State" }));
    }
  }
}

你可以在AddValidationErrors方法中写自定义验证的代码。

创建Web Api服务

ABP可以非常轻松地把Application Service的public方法发布成Web Api接口,可以供客户端通过ajax调用。


DynamicApiControllerBuilder
  .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem")
  .Build();

SimpleTaskSystemApplicationModule这个程序集中所有继承了IApplicationService接口的类,都会自动创建相应的ApiController,其中的公开方法,就会转换成WebApi接口方法。

可以通过http://xxx/api/services/tasksystem/Task/GetTasks这样的路由地址进行调用。

通过上面的案例,大致介绍了领域层、基础设施层、应用服务层的用法。

现在,可以在ASP.NET MVC的Controller的Action方法中直接调用Application Service的方法了。

SPA シングルページ プログラミングを使用する場合は、(動的 Web API を作成することにより) クライアント上の ajax を介して、対応するアプリケーション サービス メソッドを直接呼び出すことができます。

概要

以上がASP.NETテンプレート開発フレームワークABPシリーズのABP入門チュートリアルを詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。