ASP. net mvc-based ABC framework getting started tutorial, mvcabp
Why do we use the abc@aliyun.com
In recent years, we have developed some Web applications and desktop applications with simple or complex requirements to achieve or elegance or ugliness. A basic fact is that we have accumulated some experience or improved familiarity with NET.
With the increasing experience in software development, we find that a lot of work is repetitive, and with the increasing complexity of software, in the past, it was no longer feasible to simply add, delete, modify, and query operations based on experience. In particular, users have higher and higher requirements and want to add more features. Currently, this development mode has been stretched. It is hard to imagine how to perform continuous integration of multiple systems and add new features in the current mode.
When developing a system, we will inevitably use various frameworks. Data Persistence Layer implementation, logs, ASP. net mvc, IOC, and automatic ing. A high-quality software system often has components such as global fault tolerance and message queue.
When these components are combined, the complexity increases dramatically. Generally, it is difficult for individuals and small teams to design a balanced and coordinated framework. I am also skeptical about the traditional so-called three-tier architecture. (I have read the layer-3 architecture developed by a programmer with a monthly salary of 15 K, which is also a lot of problems. I cannot explain why I should use the layer-3 architecture ).
In fact, we only want to focus most of our attention on business implementation during programming. Do not worry too much about the underlying software structure. There should be a box or a paradigm to provide basic services, such as logs, fault tolerance, AOP, DI, etc.
A slightly more formal company has formed its own internal software framework after years of accumulation. They did not start from a blank space when developing software. Instead, it was built on a very solid basic platform. This greatly improves the development speed, and an architecture often determines the mode of division of labor and collaboration. The root cause of our current lack of division of labor and collaboration is the lack of a mature and stable basic development architecture and workflow.
Currently, there are many open-source frameworks in. NET. For example, Apworks and ABP. Apworks is an open-source framework written by Chinese people. It is a full-featured function that can not only write distributed applications, but also desktop applications. The full name of ABP is Asp.net boilerplate project (asp.net sample project ). Is an active open-source project on github. It does not use any new technology, but the two architects integrate some of the tools commonly used in asp.net development, and partially implement the concept of DDD. Is an out-of-the-box framework that can serve as a good starting point for asp.net distributed applications.
There is a price to use a framework. You must be intruded by a strong framework API or use its dialect. In addition, this framework requires a high learning cost. But the benefits are also obvious. The industry's top architects have built a set of infrastructure for you, responding well to questions about how a software system should be designed and planned, and providing a set of best practices and examples.
Although the learning cost is required, after a long journey, we have never been ignorant of the technical development threshold. Based on this framework, we can well divide tasks and perform unit tests. This greatly reduces the chance of software bugs.
Create an empty web application from the template
ABC Official Website: http://www.aspnetboilerplate.com
Open source projects on Github: https://github.com/aspnetboilerplate
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:
Copy codeThe Code is as follows:
<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.
First, we define the warehousing interface of the Task:
public interface ITaskRepository : IRepository<Task, long>{ List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state);}
It inherits from the pository generic interface in the ABP framework.
In IRepository, you have defined common addition, deletion, modification, and query methods:
Therefore, the above methods are used by default in ITaskRepository. You can add its unique method 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)
Define 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 ).