Analysis of the Series 2 and the basic tutorial of the series (the modern ASP. NET sample development framework ),
ABP is short for "ASP. NET Boilerplate Project (ASP. NET sample Project.
ASP. NET Boilerplate is a new starting point for developing modern WEB applications with best practices and popular technologies. It aims to become a general WEB application framework and project template.
ABC Official Website: http://www.aspnetboilerplate.com
Open source projects on Github: https://github.com/aspnetboilerplate
The origin of ABP
"DRY -- avoid repeated code" is one of the most important ideas a good developer has when developing software. We have similar requirements when developing enterprise WEB applications, such as logon pages, user/role management, permission verification, Data Validity verification, and multi-language/localization. A high-quality large software will use some best practices, such as layered architecture, domain-driven design, and dependency injection. We may also use ORM, Database migration (Database Migrations), Logging, and other tools.
Creating an enterprise application from scratch is cumbersome because you need to repeat a lot of common basic work. Many companies are developing their own application frameworks to focus on different projects, and then developing some new functions based on the frameworks. But not every company has such strength. If we can share more, we may avoid writing similar code repeatedly for each company or project. The author named the project "ASP. NET Boilerplate" in the hope that it will become a new starting point for developing general enterprise WEB applications and directly use the project as a project template.
What is ABP?
ABP is a starting point for new modern Web applications to use best practices and use the most popular tools. It can be used as a basic framework or project template for general-purpose applications. Its functions include:
Server:
- Based on the latest. NET Technology (currently ASP. net mvc 5, Web API 2, C #5.0, will be upgraded after ASP. NET 5 is officially released)
- Implement domain-driven design (entity, warehousing, domain services, domain events, application services, data transmission objects, work units, etc)
- A Layered Architecture (domain layer, application layer, presentation layer, and infrastructure layer) provides an infrastructure for developing reusable and configurable modules and integrating some of the most popular open-source frameworks/libraries, maybe some of them are in use.
- It provides an infrastructure for us to easily use dependency injection (using Castle Windsor as the container for dependency injection)
- The Repository storage mode is provided to support different ORM (Entity Framework, nhib.pdf, MangoDb, and memory database have been implemented)
- Support and implement modular development of database migration (EF Code first) (each module has an independent EF DbContext and can be specified separately)
- Including a simple and flexible multilingual/localization system
- Include an EventBus to implement unified Exception Handling for global domain events on the server side (the application layer almost does not need to handle self-writing Exception Handling Code)
- Data Validity verification (Asp. net mvc can only verify the parameters of the Action method, while ABP can verify the parameter validity of the Application layer method)
- Automatically create the Web Api layer through Application Services (no need to write the ApiController layer)
- Provides base classes and help classes for us to conveniently implement some common tasks.
- Use "conventions are better than configuration principles"
Client:
- Bootstrap, Less, AngularJs, jQuery, Modernizr, and other JS libraries: jQuery. validate, jQuery. form, jQuery. blockUI, and json2
- A project template is provided for single-page applications (AngularJs, Durandaljs) and Multi-page applications (Bootstrap + Jquery.
- Automatically create a Javascript proxy layer to more easily encapsulate some Javascript Functions using Web APIs, and more conveniently use ajax, message boxes, notification components, and busy state masks.
In addition to the ABP framework project, a module named "Zero" has been developed to implement the following functions:
- Authentication and authorization management (implemented through ASP. NET Identity)
- User and role management system set access management (system level, tenant level, user level, automatic management of function scope)
- Audit Log (automatically record the callers and parameters of each interface)
What is the out-of-the-box IP address?
ABP provides an application development model for best practices. It has basic classes, interfaces, and tools that make it easy for us to build large-scale applications that can be maintained.
However:
It is not one of the RAD tools. The RAD tool aims to create applications without coding. On the contrary, abcprovides an encoding best practice.
It is not a code generation tool. At runtime, although it has some features to build dynamic code, it cannot generate code.
It is not an integrated framework. On the contrary, it uses popular tools/libraries to complete specific tasks (for example, using EF for ORM and Log4Net for logging, so that Castle Windsor can be used as a Lai injection container, angularJs is used for the SPA framework ).
As far as I have been using it for a few months, although it is not RAD, it is definitely much faster to use it to develop projects than the traditional three-tier architecture.
Although it is not a code generation tool, it makes the code of our project more concise and standardized, which facilitates the use of the code generation tool.
I use the code generator developed by Scaffolder + T4 in VS2013. All the front-end code and database can be automatically generated based on the UML class diagram of the domain object. The simple CURD module almost does not need to write code, modules with complex business logic can be used to supplement the domain-layer code. In this way, we can spend more time designing Domain Models to reduce the time required to write code.
The following uses the original "simple task system" example to demonstrate how to use the ABC Development Project
Create an empty web application from the template
A launch template is provided for the newly created Project (although you can manually create the project and obtain the ABP package from nuget, the template method is easier ).
Go to www.aspnetboilerplate.com/templatesto create your application from the template.
You can select SPA (AngularJs or DurandalJs) or MPA (classic multi-page application. You can select Entity Framework or nhib.pdf as the orm Framework.
Here, we select AngularJs and Entity Framework, enter the PROJECT name "SimpleTaskSystem", and click "create my project" to download a zip package. decompress the package and obtain the VS2013 solution. the NET version is 4.5.1.
Each project references the Abp component and other third-party components, which need to be downloaded from Nuget.
The yellow exclamation mark icon indicates that this component does not exist in the local folder and needs to be restored from Nuget. The procedure is as follows:
To run the project, you must create a database. This template assumes that you are using SQL2008 or an updated version. Of course, you can also easily switch to other relational databases.
Open the Web. Config file to view and configure the link string:
<add name="Default" connectionString="Server=localhost; Database=SimpleTaskSystemDb; Trusted_Connection=True;" />
(When EF Code first data migration is used later, a database named SimpleTaskSystemDb is automatically created in the SQL Server database .)
In this way, the project is ready to run! Open VS2013 and press F5:
Next we will gradually implement this simple task system program
Create entity
Write the entity class in the Core project because the entity is part of the domain layer.
A Simple Application Scenario: create some tasks and assign them to people. We need two entities: Task and Person.
The Task object has several attributes: Description, CreationTime, Task status, and optional navigation attributes (AssignedPerson) to reference Person.
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; }}
The Person object is simpler. Only one Name attribute is defined:
public class Person : Entity{ public virtual string Name { get; set; }}
In the ABP framework, there is an Entity base class that has an Id attribute. Because the Task class inherits from Entity <long>, it has a long type Id. The Person class has an int type Id, because the int type is the default type of the Entity base class Id. If the type is not specified, the Object Id is the int type.
Create DbContext
To use EntityFramework, You need to first define the DbContext class. The template of the abchas created the DbContext file. We only need to add the Task and Person classes to the IDbSet. Please refer to the Code:
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) { }}
Create Database tables through Database Migrations
We use the Code First mode of EntityFramework to create a database architecture. By default, the data migration function is enabled for projects generated by the ABP template. modify the Configuration. cs file in the Migrations folder of the SimpleTaskSystem. EntityFramework project:
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"} ); }}
In the "Package Manager Console" window at the bottom of VS2013, select the default project and execute the command "Add-Migration InitialCreate"
A xxxx-InitialCreate.cs file is generated in the Migrations folder with the following content:
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"); }}
Then, execute "Update-Database" on the "Package Manager Console". The corresponding data table is automatically created in the Database:
PM> Update-Database
The database is shown as follows:
(After modifying the object, you can execute Add-Migration and Update-Database again to easily synchronize the Database structure with the object class)
Define warehousing Interface
Through the warehousing mode, you can better separate the Business Code from the database operation code, and have different implementation classes for different databases without modifying the Business Code.
Code defining the warehousing interface is written to the Core project because the warehousing interface is part of the domain layer.
Let's first defineWarehouse interface of Task:
public interface ITaskRepository : IRepository<Task, long>{
It inherits from the pository generic interface in the ABP framework.
In IRepository, you have defined common addition, deletion, modification, and query methods:
SoBy default, the above methods are available for ITaskRepository. The unique method can be added.GetAllWithPeople (...).
You do not need to create a storage class for the Person class because the default method is sufficient. ABP provides a method for injecting General warehousing, which will be seen in the TaskAppService class in the "Create Application Service" section later.
Implement warehousing
We will implement the ITaskRepository warehousing interface defined above in the EntityFramework project.
The project created through the template has defined a repository base class: SimpleTaskSystemRepositoryBase (this is a good practice because you can add a common method to this base class in the future ).
Public class TaskRepository: SimpleTaskSystemRepositoryBase <Task, long>, ITaskRepository {public List <Task> GetAllWithPeople (int? AssignedPersonId, TaskState? State) {// In the warehouse method, you do not need to process database connections, DbContext, and data transactions. The ABP framework will automatically process the data. Var query = GetAll (); // GetAll () returns an IQueryable <T> interface type // Add some Where condition 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 inherits from SimpleTaskSystemRepositoryBase and implements the ITaskRepository interface defined above.
Create Application Services)
InDefine the Application service in the Application project. First, define the application service layer interface of the Task:
public interface ITaskAppService : IApplicationService{ GetTasksOutput GetTasks(GetTasksInput input); void UpdateTask(UpdateTaskInput input); void CreateTask(CreateTaskInput input);}
The ITaskAppService inherits from the IApplicationService, And the ABP automatically provides some functional features for this class (such as dependency injection and parameter validity verification ).
Then, we write the TaskAppService class to implement the ITaskAppService interface:
Public class TaskAppService: ApplicationService, ITaskAppService {private readonly ITaskRepository _ taskRepository; private readonly IRepository <Person> _ personRepository; /// <summary> /// constructor automatically injects the required classes or interfaces /// </summary> public TaskAppService (ITaskRepository taskRepository, IRepository <Person> personRepository) {_ taskRepository = taskRepository; _ personRepository = personRepository;} public G EtTasksOutput GetTasks (GetTasksInput input) {// call the specific method of Task warehousing GetAllWithPeople var tasks = _ taskRepository. getAllWithPeople (input. assignedPersonId, input. state); // use AutoMapper to automatically convert List <Task> to List <TaskDto> return new GetTasksOutput {Tasks = Mapper. map <List <TaskDto> (tasks) };} public void UpdateTask (UpdateTaskInput input) {// you can directly use Logger, which is defined in the ApplicationService base class. info ("Updating a task for I Nput: "+ input); // obtain the Task object var task = _ taskRepository of the specified Id through the common method Get of the warehouse base class. get (input. taskId); // modify the attribute value if (input. state. hasValue) {task. state = input. state. value;} if (input. assignedPersonId. hasValue) {task. assignedPerson = _ personRepository. load (input. assignedPersonId. value);} // we do not need to call the Update method. // because the Work Unit mode (Work) is enabled by default for the method at the application service layer) // when the work unit is completed, the ABP framework automatically saves all changes to the object unless an exception occurs. If an exception occurs, the system automatically rolls back because the database transaction is enabled by default in the unit of work.} Public void CreateTask (CreateTaskInput input) {Logger. info ("Creating a task for input:" + input); // create a new Task object var task = new Task {Description = input through input parameters. description}; if (input. assignedPersonId. hasValue) {task. assignedPersonId = input. assignedPersonId. value;} // call the Insert method of the warehouse base class to save the object to the database _ taskRepository. insert (task );}}
TaskAppService uses the warehouse for database operations, which leads to the reference of the constructor injection warehouse object.
Data Verification
If the parameter object of the Application Service (Application Service) method implements the IInputDto or IValidate interface, the TTL automatically verifies the parameter validity.
The CreateTask method has a CreateTaskInput parameter, which is defined as follows:
public class CreateTaskInput : IInputDto{ public int? AssignedPersonId { get; set; } [Required] public string Description { get; set; }}
The Description attribute is required by specifying the annotation. You can also use other Data Annotation features.
If you want to use custom verification, You can implement the ICustomValidate interface:
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 and State cannot be empty at the same time! ", New [] {" AssignedPersonId "," State "}));}}}
You can write custom verification code in the AddValidationErrors method.
Create a Web Api Service
You can easily publish the public method of Application Service as a Web Api interface, which can be called by the client through ajax.
DynamicApiControllerBuilder .ForAll<IApplicationService>(Assembly.GetAssembly(typeof (SimpleTaskSystemApplicationModule)), "tasksystem") .Build();
All classes in the SimpleTaskSystemApplicationModule program that inherit the IApplicationService interface will automatically create the corresponding ApiController. The public method in this set will be converted to the WebApi method.
You can call the api through a route address such as http: // xxx/api/services/tasksystem/Task/GetTasks.
Based on the above case, the usage of the domain layer, infrastructure layer, and application service layer is roughly introduced.
Now, you can directly call the Application Service method in the Action Method of the Controller of ASP. net mvc.
If you use SPA single-page programming, you can directly call the corresponding Application Service method through ajax on the client (by creating a dynamic Web Api ).
Summary
The above is a small Editor to introduce you to the Abo (modern ASP.. NET sample development framework) Series II, an analysis of the ABC getting started tutorial, hope to help you, if you have any questions, please leave a message, xiaobian will reply to you in a timely manner. Thank you very much for your support for the help House website!