Configure ABP
the configuration is implemented by the Preinitialize method of your own module
The code example is as follows:
public class Simpletasksystemmodule:abpmodule
{public
override void Preinitialize ()
{
// Add a language pack to your application, which is Turkish for English and the author.
Configuration.Localization.Languages.Add (New Languageinfo ("en", "中文版", "Famfamfam-flag-england", true));
CONFIGURATION.LOCALIZATION.LANGUAGES.ADD (New Languageinfo ("tr", "Türkçe", "famfamfam-flag-tr"));
CONFIGURATION.LOCALIZATION.SOURCES.ADD (
new Xmllocalizationsource (
"Simpletasksystem"),
HttpContext.Current.Server.MapPath ("~/localization/simpletasksystem")
)
;
Configure navigation and menu
configuration.navigation.providers.add<simpletasksystemnavigationprovider> ();
}
public override void Initialize ()
{
iocmanager.registerassemblybyconvention ( Assembly.getexecutingassembly ());
}
Like Orchard, the ABP framework was designed to be modular at the outset, and different modules could be configured through the ABP framework. For example, different modules can add navigation, through the navigation to add menu items to their own definition of the main menu, specific details you can refer to:
Localization: http://www.aspnetboilerplate.com/Pages/Documents/Localization
Navigation: http://www.aspnetboilerplate.com/Pages/Documents/Navigation
Configuration module
compared to the. NET Framework native startup configuration, what's different about ABP? ABP Framework modules can be personalized through the Iabpmoduleconfigurations interface, so that the module configuration is more simple and convenient.
The sample code is as follows:
...
Using Abp.Web.Configuration;
...
public override void Preinitialize ()
{
Configuration.Modules.AbpWeb (). Sendallexceptionstoclients = true;
}
...
In the example above, we send an exception to the client by configuring the Abpweb module. Of course, not every module needs this kind of configuration, usually we need it, when a module needs to be reused in many different applications, we do this configuration.
To create a configuration for a module
The following code, if we have a module named MyModule, and the modules have their own configuration. So we're going to start by creating classes that are defined as attributes: The property has an automatic get and set accessor. ) and represents a different configuration.
public class Mymoduleconfig
{public
bool SampleConfig1 {get; set;}
public string SampleConfig2 {get; set;}
}
Next, we register this class by relying on injection.
Iocmanager.register<mymoduleconfig> (); Translator Note: A class is registered in the Iocmanager, in other words, we can get an instance of this class mymoduleconfig through Iocmanager. As for the principle of the IOC here is not in detail, in short, it is possible to get a class instance.
Finally, we get the configuration reference by creating an extended method Imoduleconfigurations. The following code:
Translator Note: The module configuration is a static class because we need to reuse it. The static method MyModule returns a configuration interface, and the parameter is a imoduleconfigurations interface.
Now, we can also configure our custom MyModule module in other modules.
Configuration.Modules.MyModule (). SAMPLECONFIG1 = false;
Configuration.Modules.MyModule (). SAMPLECONFIG2 = "Test";
In a sense, mymodule needs these configurations, you can inject mymoduleconfig and you can use these values.
public class Myservice:itransientdependency
{
private readonly mymoduleconfig _configuration;
Public MyService (Mymoduleconfig configuration)
{
_configuration = configuration;
}
public void DoIt ()
{
if (_configuration). SampleConfig2 = = "Test")
{
//...
}
}
}
This means that in the ABP framework system, all modules can be centrally configured.
ABP Dependency Injection
What is Dependency injection
If you already know the concept of dependency injection, constructors and attribute injection patterns, you can skip this section.
"Dependency injection is one or more dependency injection (or service) of a software design pattern, or passed by reference, as part of the dependent object (or client) and client state," Wikipedia said. Patterns establish a customer dependency behavior, which allows programming to be loosely coupled, dependent on inverted and single duty principles. It directly contrasts the service locator model, which allows customers to understand the systems they use to find dependencies. ”。
Dependency management, modular development, and application modularity are difficult to use without dependency injection technology.
Problems in the traditional way
In an application, classes are dependent on each other. Suppose we have an application service that inserts an entity into the database using the warehousing (repository) class. In this case, the application service class relies on the warehousing (repository) class. Look at the example:
public class Personappservice
{
private ipersonrepository _personrepository;
Public Personappservice ()
{
_personrepository = new Personrepository ();
}
public void Createperson (string name, int age)
{
var person = new Person {name = name, age = age};
_personrepository.insert (person);
}
Personappservice inserts a person into the database using Personrepository. The problem with this code:
The
Personappservice invokes the Createperson method by IPersonRepository, so this method relies on ipersonrepository instead of the personrepository concrete class. However, the Personappservice (constructor) still relies on personrepository. Components should be dependent on interfaces rather than implementations. This is called the dependency inversion principle.
If Personappservice creates the personrepository itself, it becomes a concrete implementation that relies on the IPersonRepository interface and cannot use another implementation. Therefore, this way of separating the interface from the implementation becomes meaningless. Hard Dependencies (hard-dependency) make code tightly coupled and less reusable.
We may need to change the way we create personrepository in the future. That is, we might want it to be created as a singleton (a single shared instance instead of creating an object for each use). Or we might want to create multiple classes that implement IPersonRepository and create objects based on criteria. In this case, we need to modify all the classes that depend on IPersonRepository.
With such dependencies, it is difficult (or impossible) to unit test the Personappservice.
to overcome these problems, you can use the factory pattern. Therefore, the warehouse class created is abstract. Look at the following code:
public class Personappservice
{
private ipersonrepository _personrepository;
Public Personappservice ()
{
_personrepository = Personrepositoryfactory.create ();
}
public void Createperson (string name, int age)
{
var person = new Person {name = name, age = age};
_personrepository.insert (person);
}
Personrepositoryfactory is a static class that creates and returns a ipersonrepository. This is called the service locator pattern. The above dependency problem is resolved because Personappservice does not need to create a IPersonRepository implementation object that depends on the personrepositoryfactory create method. However, there are still some problems:
At this point, Personappservice depends on personrepositoryfactory. It is much easier to accept, but there is still a hard dependency (hard-dependency).
Write a factory class/method that is tedious for each library or for each dependency.
Testability is still bad, because it's hard to make personappservice use mocks to implement IPersonRepository.
Solution:
There are some best practices (patterns) for class dependencies.
Constructor injection
Rewrite The example above, as follows:
public class Personappservice
{
private ipersonrepository _personrepository;
Public Personappservice (ipersonrepository personrepository)
{
_personrepository = personrepository;
}
public void Createperson (string name, int age)
{
var person = new Person {name = name, age = age};
_personrepository.insert (person);
}
This is called constructor injection. Now, Personappservice doesn't know which classes implement ipersonrepository and how to create it. Who needs to use Personappservice, first create a ipersonrepository personappservice and pass it to the constructor, as follows:
var repository = new Personrepository ();
var personservice = new Personappservice (repository);
Personservice.createperson ("Yunus Emre", 19);
Constructor injection is a perfect way to make a class create dependent objects independently. However, the above code has some problems:
Creating a personappservice becomes difficult. Imagine that if it had 4 dependencies, we would have to create these four dependent objects and pass them to the constructor Personappservice.
Dependent classes may have other dependencies (here, personrepository may have dependencies). So, we have to create all the dependencies of Personappservice, dependencies on all dependencies, and so on. So, dependencies make it too complicated for us to create an object.
Fortunately, dependency injection frameworks automate the management of dependencies.
Property Injection
The constructor injection pattern is a perfect way to provide the dependencies of a class. In this way, you cannot create an instance of a class without providing a dependency. It is also a powerful way to explicitly declare what kind of requirements work correctly.
However, in some cases, the class relies on another class, but it can be without it. This is usually appropriate for crosscutting concerns, such as logging. A class can have no work log, but it can write logs if you provide a log object. In this case, you can define dependencies as public properties rather than having them put in constructors. Think about it if we want to write a log in Personappservice. We can rewrite the class as follows:
public class Personappservice
{public
ilogger Logger {get; set;}
Private IPersonRepository _personrepository;
Public Personappservice (ipersonrepository personrepository)
{
_personrepository = personrepository;
Logger = nulllogger.instance;
}
public void Createperson (string name, int age)
{
logger.debug ("Inserting a new person to database with name =" + name);
var person = new Person {name = name, age = age};
_personrepository.insert (person);
Logger.debug ("Successfully inserted!");
}
Nulllogger.instance is a single instance object that implements the ILogger interface, but actually does nothing (log not). It implements the ILogger instance and the method body is empty. Now, Personappservice can write a log, if you set the logger for the Personappservice instance, as follows:
var personservice = new Personappservice (new Personrepository ());
Personservice.logger = new Log4netlogger ();
Personservice.createperson ("Yunus Emre", 19);
Suppose Log4netlogger implements the ILogger instance, allowing us to write logs using the Log4net library. Therefore, Personappservice can write logs. If we don't set the Logger,personappservice, we don't write the log. Therefore, we can say that Personappservice ILogger instance is an optional dependency.
Almost all dependency injection frameworks support attribute injection patterns
Dependency Injection Framework
There are many dependency injection frameworks that can automatically resolve dependencies. They can create all dependencies (recursive dependencies and dependencies). So you just need to write class and class constructors & attributes according to the injection pattern, and others to the DI framework! In good applications, classes are even independent of the DI framework. The entire application will have only a few lines of code or classes that are displayed to interact with the DI framework.
ABP Dependency Injection is based on the Castle Windsor framework. Castle Windsor is one of the most mature di frames. There are many such frameworks, such as UNITY,NINJECT,STRUCTUREMAP,AUTOFAC and so on.
When using a dependency injection framework, first register your interface/class into the dependency injection framework, and then you can resolve an object. In Castle Windsor, it is like this:
var container = new WindsorContainer ();
Container. Register (
component.for<ipersonrepository> (). Implementedby<personrepository> (). Lifestyletransient (),
component.for<ipersonappservice> (). Implementedby<personappservice> (). Lifestyletransient ()
);
var personservice = container. Resolve<ipersonappservice> ();
Personservice.createperson ("Yunus Emre", 19);
We first created the WindsorContainer. Then register the Personrepository and Personappservice and their interfaces. Then we ask the container to create a Ipersonappservice instance. It creates the Personappservice object and its dependencies and returns. In this simple example, the use of the DI framework may not be that neat, but imagine that you have many classes and dependencies in a real enterprise application. Of course, registered dependencies are created only once in a place where the program starts.
Notice that we're just talking about objects declared as temporary objects (transient). This means that whenever we create an object of these types, a new instance is created. There are many different life cycles (such as singletion).
ABP Dependency Injection Infrastructure
following best practices and conventions when writing applications, ABP almost makes it invisible to use the dependency injection framework.
Registered:
In ABP, there are many different ways to register your class to the dependency injection system. Most of the time, the usual method is enough.
General registration:
By convention, ABP automatically registers all repositories, Domain Services, application services, MVC controllers, and Web API controllers. For example, you might have a Ipersonappservice interface and implementation class Personappservice:
Public interface Ipersonappservice:iapplicationservice
{
//...
}
public class Personappservice:ipersonappservice
{
//...
}
ABP automatically registers it because it implements the Iapplicationservice interface (it is just an empty interface). It will be registered as transient (an instance is created for each use). When you inject (using constructor injection) The Ipersonappservice interface into a class, the Personappservice object is automatically created and passed to the constructor.
Naming conventions are very important here. For example, you can change the name Personappservice to Mypersonappservice or another name that contains the suffix "personappservice" because Ipersonappservice contains this suffix. But you can not follow the Peopleservice name of your service class. If you do this, it will not be automatically registered for Ipersonappservice (it needs to be registered (self-registration) to the DI framework, not the interface), so if you want you should register it manually.
ABP Registers an assembly by convention. So you should tell ABP to register your assembly according to the Convention. This is easy:
Iocmanager.registerassemblybyconvention (assembly.getexecutingassembly ());
Assembly.getexecutingassembly () Gets a reference to the assembly that contains this code. You can register other assemblies through the Registerassemblybyconvention method. This is done with the initialization of your module (Abpmodule.initialize ()). Check the ABP module system for more information.
You can do this by implementing the Iconventionalregisterer interface and calling Iocmanager. Addconventionalregisterer method to write your own contract registration class. You should add it to the Pre-initialize method of the module.
Help interface
You can register a specific class and do not follow the traditional rules of engagement system. ABP provides a quick way to itransientdependency and Isingletondependency interfaces. For example:
Public interface Ipersonmanager
{
//...
}
public class Mypersonmanager:ipersonmanager, isingletondependency
{
//...
}
In this way, you can easily register Mypersonmanager as transient. When a ipersonmanager is needed, Mypersonmanager is used. Note that dependencies are declared as a single case. Therefore, the Mypersonmanager that is created is passed to all required classes. is only created on first use, then the application's entire lifecycle uses the same instance.
Custom/Direct Registration
If the method described earlier is still not enough to handle your situation, you can use Castle Windsor to register classes and dependencies. Therefore, you will have all the capabilities of Castle Windsor registration.
You can implement the Iwindsorinstaller interface for registration. You can create a class in your application that implements the Iwindsorinstaller interface:
public class Myinstaller:iwindsorinstaller
{public
void Install (IWindsorContainer container, Iconfigurationstore store)
{
container. Register (classes.fromthisassembly (). Basedon<imyspecialinterface> (). Lifestyleperthread (). Withserviceself ());
}
ABP automatically discovers and executes this class. Finally, you can get windsorcontainer by using the Iiocmanager.ioccontainer property. For more information, read the Windsor documentation.
Parsing (resolving)
Register to notify the IOC (Control reversal) container about your classes, their dependencies, and the lifecycle. When your application needs to create objects using the IOC container, ASP. NET provides a number of ways to resolve dependencies.
Constructors & Property Injection
As a best practice, you can use constructors and attribute injection to get the dependencies of your class. Wherever possible, you should do so. Example:
public class Personappservice
{public
ilogger Logger {get; set;}
Private IPersonRepository _personrepository;
Public Personappservice (ipersonrepository personrepository)
{
_personrepository = personrepository;
Logger = nulllogger.instance;
}
public void Createperson (string name, int age)
{
logger.debug ("Inserting a new person to database with name =" + name);
var person = new Person {name = name, age = age};
_personrepository.insert (person);
Logger.debug ("Successfully inserted!");
}
IPersonRepository from the constructor injection, the ILogger instance is injected from the public property. In this way, your code does not reflect the dependency injection system. This is the most appropriate way to use the DI system.
Iiocresolver and Iiocmanager
Sometimes you may need to create your dependencies directly instead of constructors and attribute injection. This should be avoided as much as possible, but it may not be avoided. ABP provides a number of services that make such injections easy to implement. Example:
public class Mysampleclass:itransientdependency {private ReadOnly Iiocresolv
ER _iocresolver;
Public Mysampleclass (Iiocresolver iocresolver) {_iocresolver = Iocresolver; public void DoIt () {//resolving, using and releasing manually var PersonService1 = _iocresolver.
Resolve<personappservice> ();
Personservice1.createperson (new Createpersoninput {Name = "Yunus", Surname = "Emre"});
_iocresolver.release (PersonService1); Resolving and using in a safe way using (var PersonService2 = _iocresolver.resolveasdisposable<personappservice
> ()) {PersonService2.Object.CreatePerson (new Createpersoninput {Name = "Yunus", Surname = "Emre"}); }
}
}
Mysampleclass is an example class for an application. Iicresolver is injected through a constructor and then used to create and release objects. There are several workaround overloads that can be used as needed. The release method is used to free the component (object). If you are creating an object manually, it is important to invoke the release method to dispose of the object. Otherwise, your application will have a memory leak problem. To ensure that the object is freed, use resolveasdisposable as much as possible (as shown in the previous example). It automatically invokes the release method at the end of the using code block.
If you want to use the IOC container directly (Castle Windsor) to handle dependency items, you can inject iiocmanager through a constructor and use it Iiocmanager.ioccontainer properties. If you are in a static context or cannot inject iiocmanager, there is one last way you can use a single Instance object iocmanager.instance, which you can get anywhere, it is everywhere. However, in this case your code will become less susceptible to testing.
Additional
Ishouldinitialize Interface:
Some classes need to be initialized before they are used for the first time. Ishouldinitialize has a initialize () method. If you implement it, then your initialize () method will automatically be invoked after the object is created (before use). Of course, in order to use this feature, you should inject/create this object.
asp.net MVC & asp.net Web API integration:
Of course, we have to call the dependency injection system to process the root object of the dependency graph. In a asp.net MVC application, it is usually a controller class. We can inject the controller using the constructor injection pattern. When a request arrives in our application, the controller and all dependencies are created recursively by the IOC container. So, who did all this? This is done automatically by the ASP.net MVC default controller factory, which is extended by ABP. The ASP.net Web API is similar. You don't have to worry about creating and releasing objects.