ABP框架中的⽇志管理和设置管理
Server side(端)
ASP.NET Boilerplate使⽤Castle Windsor's logging facility⽇志记录⼯具,并且可以使⽤不同的⽇志类库,⽐如:
Log4Net, NLog, 等等。对于所有的⽇志类库,Castle提供了⼀个通⽤的接⼝来实现,我们可以很⽅便的处理各种特殊的⽇志库,⽽且当业务需要的时候,很容易替换⽇志组件。
译者注释:Castle是什么:Castle是针对.NET平台的⼀个开源项⽬,从数据访问框架ORM到IOC容器,再到WEB层的MVC框架、AOP,基本包括了整个开发过程中的所有东西。ASP.NET Boilerplate的ioc容器就是通过Castle实现的。
Log4Net 是asp下⾯最流⾏的⼀个⽇志库组件, ASP.NET Boilerplate 模板也使⽤了Log4Net⽇志库组件,但是呢,我们这⾥仅仅通过⼀⾏关键代码就实现Log4Net 的依赖注⼊(具体说明在下⾯的配置⽂件),所以,如果你想替换成⾃⼰的⽇志组件,也很容易。
获取⽇志记录器logger
不管你选择哪⼀个⽇志库组件,通过代码来进⾏⽇志记录都是⼀样的。(这⾥吐槽, Castle's 通⽤ ILogger 接⼝实在太⽜逼了)。
下⾯进⼊正题:(译者注:下⾯的代码是abp框架的Castle.Core源码分析以及实现)
1、⾸先呢,我们要先处理⽇志记录器对象logger, ASP.NET Boilerplate框架使⽤了dependency injection依赖注⼊技术,我们可以很⽅便的使⽤依赖注⼊⽣成⽇志记录器对象logger。
接下来我们看⼀下 ASP.NET Boilerplate是怎么实现⽇志记录功能的吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18using Castle.Core.Logging; //1: 导⼊⽇志的命名空间,Castle.Core.Logging
public class TaskAppService : ITaskAppService
{
//2:通过依赖注⼊获取⽇志记录器对象。
这⾥先定义了⼀个ILogger类型的public属性Logger,这个对象就是我们⽤来记录⽇志的对象。在创建了TaskAppService对象(就是我们应⽤中定义的任务)以后,通过属性注⼊的⽅式来实现。
public ILogger Logger { get; set; }
public TaskAppService()
{
//3: 如果没有⽇志记录器,将⽇志记录器返回⼀个空的实例,不写⽇志。这是依赖注⼊的最佳实现⽅式, // 如果你不定义这个空的⽇志记录器,当我们获取对象引⽤并且实例化的时候,就会产⽣异常。 // 这么做,保证了对象不为空。所以,换句话说,不设置⽇志记录器,就不记录⽇志,返回⼀个null的对象。 // NullLogger对象实际上什么都⽊有,空的。这么做,才能保证我们定义的类在实例化时正常运作。
Logger = NullLogger.Instance;
}
public void CreateTask(CreateTaskInput input)
{
//4: 写⼊⽇志
Logger.Info("Creating a new task with description: "+ input.Description);
//TODO: save task }
}
代码如下:
INFO 2014-07-13 13:40:23,360 [8 ] SimpleTaskSystem.Tasks.TaskAppService - Creating a new task with description:Remember to drink milk before sleeping!
写⼊⽇志以后,我们可以查看⽇志⽂件,就像下⾯的格式:
通过基类使⽤Logger
ASP.NET Boilerplate框架提供了MVC Controllers、Web API Controllers和Application service classes的基类(⾃⼰定义的控制器和应⽤服务,都必须要继承ASP.NET Boilerplate的基类,换句话说,当你⾃定义的Web API controllers、mvc controllers,Application service classes都继承了ASP.NET Boilerplate框架对应的基类,你就可以直接使⽤⽇志记录器)。
1 2 3 4 5 6 7 8public class HomeController : SimpleTaskSystemControllerBase {
public ActionResult Index()
{
Logger.Debug("A sample ");
return View();
}
}
说明:SimpleTaskSystemControllerBase这个基类控制器是我们⾃⼰定义的基类控制器,他必须继承⾃AbpController。
这样实现,⽇志记录器才能正常⼯作。当然了,你也可以实现⾃⼰的基类,这样的话你也可以不使⽤依赖注⼊了。
配置
如果你在官⽹上通过ASP.NET Boilerplate templates 来⽣成了你的⼯程,Log4Net的所有配置都⾃动
⽣成了。
默认的配置格式如下:
·Log level: ⽇志记录等级,有DEBUG, INFO, WARN, ERROR or FATAL5个。
·Date and time: ⽇志记录时间。
·Thread number: 每⾏⽇志写时候的线程号。
·Logger name: ⽇志记录器的名字,通常情况就是类名称。
·Log text: 你写⼊的⽇志内容。
配置⽂件:fig ⼀般都在项⽬的web⽬录下⾯。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21<?xml version="1.0"encoding="utf-8"?>
<log4net>
<appender name="RollingFileAppender"type="log4net.Appender.RollingFileAppender">
<file value=""/>
<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是⼀个⾮常强⼤和易⽤的⽇志库组件,你可以写各种⽇志,⽐如写到txt⽂件,写⼊到数据库等等。你能设置最⼩的⽇志等级,就像上⾯这个针对NHibernate的配置。不同的记录器写不同的⽇志,等等。
最后,在⼯程的Global.asax ⽂件中,来定义Log4Net的配置⽂件:
1 2 3 4 5 6 7 8public class MvcApplication : AbpWebApplication
{
protected override void Application_Start(object sender, EventArgs e)
{
IocManager.Instance.IocContainer.AddFacility<LoggingFacility>(f => f.UseLog4Net().WithConfig("fig")); base.Application_Start(sender, e);
}
}
⼏⾏代码就调⽤了Log4Net这个⽇志记录组件,⼯程中的Log4Net库是在 nuget package包中的,你也可以换成其他⽇志组件库,但是代码不⽤做任何改变。因为,我们的框架是通过依赖注⼊实现⽇志记录器的!
Client side(客户端)
最后,更厉害的是,你还可以在客户端调⽤⽇志记录器。在客户端,ASP.NET Boilerplate框架有对应的 javascript ⽇志API,这意味着你可以记录下来浏览器的⽇志,实现代码如下:
1abp.log.warn('a sample ');
附上:客户端javascript的api,这⾥要说明的是,你可以使⽤console.log在客户端输出⽇志,但是这个API 不⼀定⽀持所有的浏览器,还有可能导致你的脚本出现异常,你可以使⽤我们的api,我们的是安全的,你甚⾄可以重载或者扩展这些api。
1 2 3 4 5abp.log.debug('...'); abp.log.info('...'); abp.log.warn('...'); ('...'); abp.log.fatal('...');
设置管理
介绍
每个应⽤程序需要存储⼀些设置并在应⽤程序的某个地⽅使⽤这些设置。ABP框架提供强⼤的基础架构,我们可以在服务端或者客户端设置,来存储/获取应⽤程序、 租户和⽤户级别的配置。
设置通常是存储在数据库(或另⼀个来源)中,⽤名称-值(name-value)字符串对应的结构来表⽰。我们可以把⾮字符串值转换成字符串值来存储。
注意:关于ISettingStore接⼝
为了使⽤设置管理必须实现 ISettingStore 接⼝。你可以⽤⾃⼰的⽅式实现它,在module-zero项⽬中有完整的实现可以参考。
定义设置
使⽤设置之前必须要先定义。ABP框架是模块化设计,所以不同的模块可以有不同的设置。为了定义模块⾃⼰的设置,每个模块都应该创建继承⾃SettingProvider 的派⽣类。设置提供程序⽰例如下所⽰:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25public 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
)
};
}
}
26
GetSettingDefinitions ⽅法返回 SettingDefinition 对象。SettingDefinition 类的构造函数中有如下参数:
·Name (必填):必须具有全系统唯⼀的名称。⽐较好的办法是定义字符串常量来设置Name。
·Default value: 设置⼀个默认值。此值可以是null 或空字符串。
·Scopes: 定义设置的范围 (见下⽂)。
·Display name: ⼀个可本地化的字符串,⽤于以后在UI中显⽰设置的名称。
·Description: ⼀个可本地化的字符串,⽤于以后在UI中显⽰设置的描述。
·Group: 可⽤于设置组。这仅仅是UI使⽤,不⽤于设置管理。
·IsVisibleToClients: 设置为 true 将使设置在客户端可⽤。
在创建设置提供程序(SettingProvider)之后,我们应该在预初始化(PreIntialize)⽅法中注册我们的模块:
Configuration.Settings.Providers.Add<MySettingProvider>();设置提供程序会⾃动注册依赖注⼊。所以,设置提供程序可以注⼊任何依赖项 (如存储库) 来⽣成设置定义的⼀些其它来源。
设置范围
有三个设置范围 (或级别) 在 SettingScopes 枚举中定义:
·Application:应⽤程序范围设置⽤于⽤户/租户独⽴的设置。例如,我们可以定义⼀个名为"SmtpServerAddress"的设置,当发送电⼦邮件时,获取服务器的 IP 地址。如果此设置有⼀个单⼀的值 (不基于⽤户改变),那么我们可以定义它为应⽤程序范围。
·Tenant:如果应⽤程序是多租户的,我们可以定义特定于租户的设置。
·
User:我们可以使⽤的⽤户范围的设置来为每个⽤户存储/获取设置的值。
SettingScopes 枚举具有Flags属性,所以我们可以定义⼀个具有多个作⽤域的设置。
设置范围是分层的。例如,如果我们定义设置范围为"Application | Tenant | User"并尝试获取当前设置的值;
·我们获取特定⽤户的值,如果它定义 (重写) User。
·如果没有,我们获取特定的租户值,如果它定义 (重写) Tenant。
·如果没有,我们获取应⽤的值,如果它定义Application。
·如果没有,我们得到的默认值。
默认值可以是 null 或空字符串。如果可以,建议为设置提供⼀个默认值。
获取设置值
定义设置后,我们可以在服务器和客户端获取到它的当前值。
(1)服务器端(Server side)
ISettingManager ⽤于执⾏设置操作。我们可以在应⽤程序中任何地⽅注⼊和使⽤它。ISettingManager 定义了很多获取设置值⽅法。
最常⽤的⽅法是 GetSettingValue (或GetSettingValueAsync 为异步调⽤)。它将返回当前设置的基于默认值、 应⽤程序、 租户和⽤户设置范围的值(如设置范围之前的⼀段中所述)。例⼦:asp查看源码配置ui
1 2 3 4//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 有泛型和异步版本,如上所⽰。也有⽅法来获取特定的租户或⽤户的设置值或所有设置值的列表。
由于ISettingManager使⽤⼴泛,⼀些特定的基类 (如 ApplicationService、 DomainService 和 AbpController) 有⼀个名为 SettingManager的属性。如果我们从这些类继承,就⽆需显式地注⼊它。
(2)客户端
如果定义设置时将 IsVisibleToClients 设置为 true,就可以在客户端使⽤ javascript得到它的当前值。abp.setting 命名空间定义所需的函数和对象。⽰例:
var currentColor = ("SiteColorPreference");也有 getInt 和 getBoolean 这样的⽅法。你可以使⽤abp.setting.values 对象获取所有值。请注意,如果你在服务器端更改设置,客户端不会知道这种变化,除⾮刷新页⾯或者以某种⽅式重新加载页⾯或者通过代码⼿动更新。
更改设置
ISettingManager 定义了 ChangeSettingForApplicationAsync,ChangeSettingForTenantAsync 和ChangeSettingForUserAsync ⽅法(以及同步版本)来更改应⽤程序,租户和⽤户分别的设置。
关于缓存
缓存在服务器端设置管理,所以,我们不应直接使⽤存储库或数据库更新语句改变设置的值。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论