I. Explain the application service layer
Application services are used to expose domain (business) logic to the presentation layer. The presentation layer invokes the application service by passing in the DTO (data transfer object) parameter, and the application service executes the appropriate business logic through the domain object and returns the DTO to the presentation layer. Therefore, the presentation layer and the domain layer will be completely separated.
Here are some things to keep in mind when creating an app service:
In an ABP, an application service needs to implement the Iapplicationservice interface, and the best practice is to create an interface that inherits from Iapplicationservice for each app service. (by inheriting the interface, the ABP will automatically help with dependency injection)
The ABP provides the default implementation applicationservice for Iapplicationservice, which provides convenient logging and localization capabilities. When implementing the application service, inherit from Applicationservice and implement the defined interface.
In ABP, an application service method defaults to a unit of work. The ABP automates database connection and transaction management for UOW mode, and data modifications are automatically saved.
Second, define the Itaskappservice interface
1, let's take a look at the defined interface
Public interface Itaskappservice:iapplicationservice { gettasksoutput gettasks (gettasksinput input); void Updatetask (Updatetaskinput input); int createtask (createtaskinput input); task<taskdto> gettaskbyidasync (int taskId); Taskdto Gettaskbyid (int taskId); void Deletetask (int taskId); Ilist<taskdto> getalltasks (); }
Observe the parameters and return values of the method, and you may find that the task entity object is not used directly. What is this for? Because the presentation layer and the Application service layer are data transfer via the data Transfer Object (DTO).
2, why do I need to transfer data through a DTO?
In summary, the use of DTOs for data transfer has the following benefits.
Data hiding
Serialization and lazy loading issues
ABP provides a contract class for DTOs to support validation
Change of parameter or return value, easy extension via DTO
For more information, please refer to:
ABP Framework-Data Transfer Object
3,DTO specification (Flexible application)
ABP recommends naming input/output parameters: Methodnameinput and Methodnameoutput
and define separate input and output dtos for each application service method (if you define a DTO for each method's input and output, there will be a large dto class that needs to define maintenance.) Common by defining a common dto)
Even if your method only accepts/returns a parameter, it is best to create a DTO class
A new DTOs folder is typically created under the App Service folder for the corresponding entity to manage the DTO class.
Third, define the DTO that the application service interface needs to use
1, first look at the definition of taskdto
namespace learningmpaabp.tasks.dtos{//<summary>//A DTO class that can is used in various application Ser Vice methods when needed to send/receive Task objects. </summary> public class Taskdto:entitydto {public long? Assignedpersonid {get; set;} public string Assignedpersonname {get; set;} public string Title {get; set;} public string Description {get; set;} Public DateTime CreationTime {get; set;} Public Taskstate State {get; set;} This method was just used by the Console application to list tasks public override string ToString () { return string. Format ("[Task id={0}, Description={1}, creationtime={2}, Assignedpersonname={3}, state={4}]", Id, Description, CreationTime, Assignedpersonid, (taskstate ) state); } }}
The taskdto directly inherits from the simple class that entitydto,entitydto is a generic entity that defines only the id attribute. The purpose of defining a taskdto directly is to be used in multiple application service methods.
2, let's look at the definition of gettasksoutput.
is to share the taskdto directly.
public class Gettasksoutput {public list<taskdto> Tasks {get; set;} }
3, then look at Createtaskinput, Updatetaskinput
public class Createtaskinput {public int? Assignedpersonid {get; set;} [Required] public string Description {get; set;} [Required] public string Title {get; set;} Public Taskstate State {get; set;} public override string ToString () { return string. Format ("[createtaskinput > Assignedpersonid = {0}, Description = {1}]", Assignedpersonid, Description); } }
<summary>//This DTO class was used to send needed data to <see cref= "Itaskappservice.updatetask"/> ; Method. Implements <see cref= "Icustomvalidate"/> For additional custom validation. </summary> public class Updatetaskinput:icustomvalidate {[Range (1, Int32.MaxValue)]//data Annot ation attributes work as expected. public int Id {get; set;} public int? Assignedpersonid {get; set;} Public taskstate? State {get; set;} [Required] public string Title {get; set;} [Required] public string Description {get; set;} Custom validation method. It ' s called by ABP after data annotation validations. public void Addvalidationerrors (Customvalidationcontext context) {if (Assignedpersonid = = nul L && state = = NULL) {context. Results.add (New Validationresult ("Both of AssignedpersoNId and state can is null in order to update a task! ", new[] {" Assignedpersonid "," State "}); }} public override string ToString () {return string. Format ("[updatetaskinput > TaskId = {0}, Assignedpersonid = {1}, state = {2}]", Id, Assignedpersonid, state); } }
Updatetaskinput implements the Icustomvalidate interface for custom validation. Understanding DTO Validation Refer to ABP framework-validating data transfer objects
# #4, take a look at the definition of Gettasksinput
These include two properties for filtering.
public class Gettasksinput {public taskstate? State {get; set;} public int? Assignedpersonid {get; set;} }
Define the DTO, is not the head of a question, I am using DTOs in the presentation layer and application service layer for data transmission, but eventually these dtos need to be converted to entities to work directly with the database AH. If every dto has to be converted to a corresponding entity by itself, the workload is not to be underestimated.
As smart as you are, you will certainly want to know how to reduce this workload.
Iv. using AutoMapper to automatically map DTOs and entities
1, Brief introduction AutoMapper
Before you start, if you are not very familiar with AutoMapper, it is recommended to look at this article AutoMapper summary.
AutoMapper the use of the steps, briefly summarize the following:
Create mapping Rules (Mapper.createmap<source, destination> ();)
Type mapping Conversions (mapper.map<source,destination> (Sourcemodel))
There are two ways to create mapping rules in the ABP:
Attribute Data annotation Method:
Automapfrom, Automapto attributes create one-way mappings
Automap Attributes Create bidirectional mappings
Code Creation Mapping Rules:
Mapper.createmap<source, destination> ();
2, define mapping rules for DTOS related to task entities
2.1, define mapping rules for Createtasksinput, Updatetaskinput
The property names in Createtasksinput, Updatetaskinput, and the properties of the task entity are named consistent, and only need to map from the DTO to the entity, no reverse mapping is required. So you can create one-way mappings by Automapto.
[Automapto (typeof Task)]//define one-way mapping public class Createtaskinput { ... } [Automapto (typeof Task)]//define one-way mapping public class Updatetaskinput { ... }
2.2, define mapping rules for taskdto
Taskdto has a property name mismatch with the properties of the task entity. The Assignedpersonname property in Taskdto corresponds to the Assignedperson.fullname attribute in the task entity. For this attribute mapping, AutoMapper is not so smart as to need us to tell it what to do;
var taskdtomapper = Mapperconfig.createmap<task, taskdto> ();
Taskdtomapper.formember (dto = dto). Assignedpersonname, map = map. Mapfrom (M = m.assignedperson.fullname));
After creating a custom mapping rule for taskdto and task, we need to think about where this code should be placed.
Iv. creating a unified portal registration AutoMapper mapping rules
If the mapping rules are created both through attributes and code, it can be confusing and inconvenient to maintain.
To solve this problem, unify the way code is used to create mapping rules. All mapping rule classes are registered through the IOC container, and the registration method is called again.
1, define abstract interface idtomapping
The application service layer root creates the Idtomapping interface, and the definition CreateMapping method is implemented by the mapping rule class.
namespace learningmpaabp{//<summary>///// Implement this interface for mapping rules creation/ //</summary> Internal interface idtomapping { void createmapping (Imapperconfigurationexpression mapperconfig);} }
2, create a mapping class for the task entity-related DTO
namespace learningmpaabp.tasks{public class Taskdtomapping:idtomapping { public void createmapping (Imapperconfigurationexpression mapperconfig) {//define one-way mapping Mapperco Nfig. Createmap<createtaskinput, task> (); Mapperconfig.createmap<updatetaskinput, task> (); Mapperconfig.createmap<taskdto, updatetaskinput> (); Custom mappings var taskdtomapper = Mapperconfig.createmap<task, taskdto> (); Taskdtomapper.formember (dto = dto). Assignedpersonname, map = map. Mapfrom (M = m.assignedperson.fullname)); } }}
3, register idtomapping dependent
The idtomapping is registered in the module of the application service and parsed for mapping rule creation.
namespace learningmpaabp{[DependsOn (typeof (Learningmpaabpcoremodule), typeof (Abpautomappermodule))] public class Le Arningmpaabpapplicationmodule:abpmodule {public override void Preinitialize () {Configurati On. Modules.abpautomapper (). Configurators.add (mapper = {//add your custom AutoMapper mappings here ...}); } public override void Initialize () {iocmanager.registerassemblybyconvention ( embly. GetExecutingAssembly ()); Register idtomapping IocManager.IocContainer.Register (classes.fromassembly (Assembly.getexecutingasse Mbly ()). Includenonpublictypes (). Basedon<idtomapping> (). Withservice.self (). Withservice.defaultinterfaces (). Lifestyletransient ()); Parse dependencies, and make mapping rules to create Configuration.Modules.AbpAutoMapper (). Configurators.add (mapper = {var mappers = iocmanager.ioccontainer.resolveall<idtomapping > (); foreach (Var dtomap in mappers) Dtomap. CreateMapping (mapper); }); } }}
In this way, we only need to implement the idtomappting mapping rule definition. The action of creating a mapping rule is given to the module.
Five, ready to achieve Itaskappservice
Read the above carefully, then to this step, it is very simple, the business is just a simple delete and deletion of the check, the implementation is very simple. You can try your own implementation, and then refer to the code:
namespace learningmpaabp.tasks{//<summary>//Implements <see cref= "Itaskappservice"/> To perform TA SK Related application functionality. Inherits from <see cref= "Applicationservice"/>. <see cref= "Applicationservice"/> contains some basic functionality common for application services (such as Logg ing and localization). </summary> public class Taskappservice:learningmpaabpappservicebase, Itaskappservice {//these me Mbers set in constructor using constructor injection. Private ReadOnly irepository<task> _taskrepository; Private ReadOnly irepository<person> _personrepository; <summary>///in Constructor, we can get needed classes/interfaces. They is sent here by dependency Injection system automatically. </summary> public Taskappservice (irepository<task> taskrepository, irepository<person> person Repository) {_taskrepository = taskrepository; _personrepository = personrepository; Public gettasksoutput gettasks (Gettasksinput input) {var query = _taskrepository.getall (); if (input. Assignedpersonid.hasvalue) {query = query. Where (t = = T.assignedpersonid = = input. Assignedpersonid.value); } if (input. State.hasvalue) {query = query. Where (t = = T.state = = input. State.value); }//used AutoMapper to automatically convert list<task> to List<taskdto>. return new Gettasksoutput {Tasks = mapper.map<list<taskdto>> (query. ToList ())}; } public Async task<taskdto> gettaskbyidasync (int taskId) {//called specific getallwithpeo Ple method of Task repository. var task = await _taskrepository.getasync (taskId); Used AutoMapper to automatically convert list<task> to List<taskdto>. Return task. Mapto<taskdto> (); } public taskdto Gettaskbyid (int taskId) {var task = _taskrepository.get (taskId); Return task. Mapto<taskdto> (); } public void Updatetask (Updatetaskinput input) {//we can use Logger, it's defined in Applicatio Nservice base class. Logger.info ("Updating a task for input:" + input); Retrieving a task entity with given ID using the standard Get method of repositories. var task = _taskrepository.get (input. ID); Updating changed properties of the retrieved task entity. if (input. State.hasvalue) {task. state = input. State.value; } if (input. Assignedpersonid.hasvalue) {task. Assignedperson = _personrepository.load (input. Assignedpersonid.value);}//we even does not call Update method of the repository. Because an application service method was a ' unit of work ' scope as default. ABP automatically saves all changes if a ' unit of work ' scope ends (without any exception). } public int CreateTask (Createtaskinput input) {//we can use Logger, it's defined in application Service class. Logger.info ("Creating a task for input:" + input); Creating a new task entity with given input ' s properties var task = new Task {Desc Ription = input. Description, Title = input. Title, state = input. State, creationtime = Clock.now}; if (input. Assignedpersonid.hasvalue) {task. Assignedperson = _personrepository.load (input. Assignedpersonid.value); }//saving entity with standard Insert method of repositories. return _taskrepository.insertandgetid (Task); } public void Deletetask (int taskId) {var task = _taskrepository.get (taskId); if (task! = null) {_taskrepository.delete (Task); } } }}
This chapter will be adjourned. To deepen your impressions, please answer the following questions yourself:
What is the app service tier?
How do I define an app service interface?
What DTO, how to define a DTO?
How do dtos automatically map with entities?
How is the mapping rule created uniformly?
The above is the ABP Starter series (5)-Create app service content, more about topic.alibabacloud.com (www.php.cn)!