ABP is a web development framework based on ASP.NET. Its log and framework settings are also relatively complete. Here, the editor of the new technology channel will introduce in detail the basic configuration of log management and setting management in the ABP framework. Friends in need can refer to it carefully!
Log Management
Server side (server side)
ASP.NET Boilerplate uses Castle Windsor's logging facility logging tool, and can use different log class libraries, such as: Log4Net, NLog, Serilog... and so on. For all log class libraries, Castle provides a general interface to implement it. We can easily handle various special log libraries, and it is easy to replace the log components when business needs it.
Translator's Note: What is Castle: Castle is an open source project for the .NET platform, from data access framework ORM to IOC containers, to the MVC framework and AOP at the WEB layer, it basically includes everything in the entire development process. The Ioc container of ASP.NET Boilerplate is implemented through Castle.
Log4Net is the most popular log library component under asp.net. The ASP.NET Boilerplate template also uses the Log4Net log library component. However, we implement Log4Net dependency injection through just one line of key code (specifically explained in the configuration file below). Therefore, it is also easy to replace it with your own log component.
Get logger
Regardless of which log library component you choose, it is the same for logging through code. (Complaint here, Castle's universal ILogger interface is really awesome).
Let’s get to the topic: (Translator’s note: The following code is the Castle.Core source code analysis and implementation of the abp framework)
1. First of all, we need to deal with the logger object logger first. The ASP.NET Boilerplate framework uses dependency injection dependency injection technology, and we can easily use dependency injection to generate the logger object logger.
Next, let’s take a look at how ASP.NET Boilerplate implements logging function:
using Castle.Core.Logging; //1: The namespace for importing the log, Castle.Core.Loggingpublic class TaskAppService: ITaskAppService{ //2: Get the logger object through dependency injection. Here we first define a public property Logger of ILogger type, which is the object we use to record logs. After creating the TaskAppService object (the task defined in our application), it is implemented through attribute injection. public ILogger Logger { get; set; } public TaskAppService() { //3: If there is no logger, return the logger to an empty instance and do not write the log. This is the best way to implement dependency injection, // If you do not define this empty logger, an exception will be generated when we get the object reference and instantiate it. // Doing so ensures that the object is not empty. So, in other words, without setting up a logger, the log will not be recorded, and a null object will be returned. // The NullLogger object is actually nothing, empty. Only by doing this can we ensure that the classes we define work normally when instantiated. Logger = NullLogger.Instance; } public void CreateTask(CreateTaskInput input) { //4: Write to log Logger.Info("Creating a new task with description: " + input.Description); //TODO: save task to database... } } The code copy is as follows:INFO 2014-07-13 13:40:23,360 [8 ] SimpleTaskSystem.Tasks.TaskAppService - Creating a new task with description:Remember to drink milk before sleeping!
After writing to the log, we can view the log file, just like the following format:
Using Logger via base classThe ASP.NET Boilerplate framework provides the base classes of MVC Controllers, Web API Controllers and Application service classes (the controllers and application services you define must inherit the base classes of ASP.NET Boilerplate. In other words, when your customized Web API controllers, mvc controllers, and Application service classes all inherit the base classes corresponding to the ASP.NET Boilerplate framework, you can directly use the logger).
public class HomeController : SimpleTaskSystemControllerBase { public ActionResult Index() { Logger.Debug("A sample log message..."); return View(); } }Description: SimpleTaskSystemControllerBase This base class controller is the base class controller we define ourselves, and it must inherit from AbpController.
This way, the logger can work normally. Of course, you can also implement your own base class, so you can no longer use dependency injection.
Configuration
If you generate your project through ASP.NET Boilerplate templates on the official website, all configurations of Log4Net are automatically generated.
The default configuration format is as follows:
•Log level: Log recording level, 5 DEBUG, INFO, WARN, ERROR or FATAL.
•Date and time: Logging time.
•Thread number: The thread number when each line of log is written.
•Logger name: The name of the logger, usually the class name.
•Log text: The log content you wrote.
Configuration file: log4net.config is usually located in the project's web directory.
<?xml version="1.0" encoding="utf-8" ?><log4net> <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" > <file value="Logs/Logs.txt" /> <appendToFile value="true" /> <rollingStyle value="Size" /> <maxSizeRollBackups value="10" /> <maximumFileSize value="10000KB" /> <staticLogFileName value="true" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%-5level %date [%-5.5thread] %-40.40logger - %message%newline" /> </layout> </appender> <root> <appender-ref ref="RollingFileAppender" /> <level value="DEBUG" /> </root> <logger name="NHibernate"> <level value="WARN" /> </logger></log4net>
Log4Net is a very powerful and easy-to-use log library component. You can write various logs, such as writing to txt files, writing to databases, etc. You can set the minimum log level, just like the above configuration for NHibernate. Different loggers write different logs, etc.
For specific usage, please refer to: http://logging.apache.org/log4net/release/config-examples.html
Finally, in the Global.asax file of the project, define the Log4Net configuration file:
public class MvcApplication: AbpWebApplication{ protected override void Application_Start(object sender, EventArgs e) { IocManager.Instance.IocContainer.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithConfig("log4net.config")); base.Application_Start(sender, e); }}A few lines of code call Log4Net, the logging component. The Log4Net library in the project is in the nuget package. You can also change it to other log component libraries, but the code does not need to be changed. Because, our framework implements the logger through dependency injection!
Client side (client)
Finally, what's even more amazing is that you can also call the logger on the client side. On the client side, the ASP.NET Boilerplate framework has a corresponding javascript log API, which means that you can record the browser's logs, and the implementation code is as follows:
abp.log.warn('a sample log message...');Attached: Client JavaScript API. What you need to explain here is that you can use console.log to output logs on the client, but this API does not necessarily support all browsers, and may cause exceptions to your script. You can use our API, ours is safe, and you can even overload or extend these APIs.
abp.log.debug('...');abp.log.info('...');abp.log.warn('...');abp.log.error('...');abp.log.fatal('...');abp.log.fatal('...');Settings Management
introduce
Each application needs to store some settings and use them somewhere in the application. The ABP framework provides a powerful infrastructure that we can set on the server or client to store/get application, tenant and user-level configurations.
Settings are usually stored in a database (or another source), represented by the structure corresponding to the name-value string. We can convert non-string values into string values for storage.
Note: About the ISettingStore interface
In order to use Settings Management, the ISettingStore interface must be implemented. You can implement it in your own way, and there are complete implementations in the module-zero project to refer to.
Define settings
You must define the settings before using them. The ABP framework is a modular design, so different modules can have different settings. To define the module's own settings, each module should create a derived class inherited from SettingProvider. The setup provider example is as follows:
public class MySettingProvider : SettingProvider{ public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context) { return new[] { new SettingDefinition( "SmtpServerAddress", "127.0.0.1" ), new SettingDefinition( "PassiveUsersCanNotLogin", "true", scopes: SettingScopes.Application | SettingScopes.Tenant ), new SettingDefinition( "SiteColorPreference", "red", scopes: SettingScopes.User, isVisibleToClients: true ) }; }}The GetSettingDefinitions method returns the SettingDefinition object. The constructor of the SettingDefinition class has the following parameters:
•Name (required): Must have a unique name on the entire system. A better way is to define string constants to set Name.
•Default value: Sets a default value. This value can be null or an empty string.
•Scopes: Defines the scope of the setting (see below).
•Display name: A localizable string for later displaying the set name in the UI.
•Description: A localizable string for later displaying the description of settings in the UI.
•Group: Can be used to set up groups. This is only for UI use and is not for setting management.
•IsVisibleToClients: Setting to true will make the settings available on the client.
After creating the SettingProvider, we should register our module in the PreIntialize method:
Configuration.Settings.Providers.Add<MySettingProvider>(); The setting provider automatically registers dependency injection. Therefore, the setup provider can inject any dependencies (such as a repository) to generate some other source of the setup definition.
Set the range
There are three settings (or levels) defined in the SettingScopes enum:
•Application: Application-wide settings are used for user/tenant independent settings. For example, we can define a setting called "SmtpServerAddress" that gets the server's IP address when sending an email. If this setting has a single value (not changed based on user), then we can define it as application scope.
•Tenant: If the application is multi-tenant, we can define tenant-specific settings.
•User: We can use user-wide settings to store/get set values for each user.
The SettingScopes enum has a Flags property, so we can define a setting with multiple scopes.
The settings range is hierarchical. For example, if we define the setting range to "Application | Tenant | User" and try to get the value of the currently set;
•We get the value of a specific user if it defines (rewrites) the User.
•If not, we get the specific tenant value if it defines (rewrites) Tenant.
•If not, we get the value of the application if it defines the Application.
•If not, we get the default value.
The default value can be null or an empty string. If possible, it is recommended to provide a default value for the settings.
Get the set value
After defining the settings, we can get its current value on the server and client.
(1) Server side
ISettingManager is used to perform settings. We can inject and use it anywhere in the application. ISettingManager defines many methods to get set values.
The most commonly used method is GetSettingValue (or GetSettingValueAsync is an asynchronous call). It returns the currently set value based on the default, application, tenant, and user settings range (as described in the paragraph before setting range). example:
//Getting a boolean value (async call)var value1 = await SettingManager.GetSettingValueAsync<bool>("PassiveUsersCanNotLogin");//Getting a string value (sync call)var value2 = SettingManager.GetSettingValue("SmtpServerAddress");GetSettingValue has generic and asynchronous versions, as shown above. There are also ways to get a list of settings for a specific tenant or user or all settings for it.
Because ISettingManager is widely used, some specific base classes (such as ApplicationService, DomainService, and AbpController) have a property called SettingManager. If we inherit from these classes, there is no need to explicitly inject it.
(2) Client
If IsVisibleToClients is set to true when defining the settings, you can get its current value using javascript on the client. abp.setting The namespace defines the required functions and objects. Example:
var currentColor = abp.setting.get("SiteColorPreference"); there are also methods such as getInt and getBoolean. You can use the abp.setting.values object to get all values. Note that if you change settings on the server side, the client won't know about this change unless the page is refreshed or reloaded in some way or updated manually via code.
Change settings
ISettingManager defines ChangeSettingForApplicationAsync, ChangeSettingForTenantAsync and ChangeSettingForUserAsync methods (and the synchronous version) to change the settings of the application, tenant, and user separately.
About Cache
The cache is in server-side settings management, so we should not directly use the repository or database update statement to change the set value.
The above is a detailed introduction to the basic configuration of log management and setting management in the ABP framework compiled by the editor of Fooxin Technology Channel. I hope it will be helpful for everyone to learn this knowledge. For more content, please continue to pay attention to Fooxin Technology Channel!