基于NopCommerce的开发框架——缓存、网站设置、系统日志、用户操作日志
最近忙于学车,抽时间将Nop的一些公用模块添加进来,反应的一些小问题也做了修复。前篇——基于nopCommerce的开发框架(附源码):http://www.cnblogs.com/dreling/p/6906688.html。
最新的代码已经同布到GitHub:https://github.com/dreling8/Nop.Framework,有兴趣的可以关注该项目,后续其它的一些通用模块也会添加进去,如用户、权限、本地化、任务、插件功能等。欢迎star给星星,你的支持是我的动力!
一、缓存模块
nopCommerce项目缓存类层级图
ICacheManager接口,该接口定义了数据缓存常用的方法。
CacheExtensions扩展方法对ICacheManager进行扩展。
MemoryCacheCache类,使用.net 缓存框架实现数据缓存。
PerRequestCacheManager类,实现页面请求级的数据缓存。
RedisCacheManager类,实现Redis数据缓存类。
NopNullCache类,空的数据缓存类实现。
IRedisConnectionWrapper接口,redis连接封装接口。
RedisConnectionWrapper类,redis连接实现。
缓存的使用
在依赖注入中(DependencyRegistrar),将缓存注入到IOC容器中,系统默认使用MemoryCacheCache,如果想使用redis缓存可在配置模块启用并设置相关参数。
//cache managers
if (config != null && config.RedisCachingEnabled)
{
builder.RegisterType<RedisConnectionWrapper>().As<IRedisConnectionWrapper>().SingleInstance();
builder.RegisterType<RedisCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").InstancePerLifetimeScope();
}
else
{
builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
}
builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerLifetimeScope();
在用户操作服务UserActivityService中可以了解到,数据缓存是如何处理的,在数据检索时,直接从缓存取数据,其他方法均根据相关正则表达式移除ActivityLogType的所有缓存,以避免读取到脏数据。
protected virtual IList<ActivityLogTypeForCaching> GetAllActivityTypesCached()
{
//cache
string key = string.Format(ACTIVITYTYPE_ALL_KEY);
return _cacheManager.Get(key, () =>
{
var result = new List<ActivityLogTypeForCaching>();
var activityLogTypes = GetAllActivityTypes();
foreach (var alt in activityLogTypes)
{
var altForCaching = new ActivityLogTypeForCaching
{
Id = alt.Id,
SystemKeyword = alt.SystemKeyword,
Name = alt.Name,
Enabled = alt.Enabled
};
result.Add(altForCaching);
}
return result;
});
}
二、设置模块
Nop的设置功能实现比较有意思,先看类层级图。
ILocalizedEntity接口,暂时忽略该接口。
ISettings接口,设置接口。
Setting类,设置实体类。
CommonSettings类,一个实现ISettings接口的通用设置类。
通过Autofac的IRegistrationSource接口,将所有的设置类注入。
public class SettingsSource : IRegistrationSource
{
static readonly MethodInfo BuildMethod = typeof(SettingsSource).GetMethod(
"BuildRegistration",
BindingFlags.Static | BindingFlags.NonPublic);
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service,
Func<Service, IEnumerable<IComponentRegistration>> registrations)
{
var ts = service as TypedService;
if (ts != null && typeof(ISettings).IsAssignableFrom(ts.ServiceType))
{
var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType);
yield return (IComponentRegistration)buildMethod.Invoke(null, null);
}
}
static IComponentRegistration BuildRegistration<TSettings>() where TSettings : ISettings, new()
{
return RegistrationBuilder
.ForDelegate((c, p) =>
{
////var currentStoreId = c.Resolve<IStoreContext>().CurrentStore.Id;
//uncomment the code below if you want load settings per store only when you have two stores installed.
//var currentStoreId = c.Resolve<IStoreService>().GetAllStores().Count > 1
// c.Resolve<IStoreContext>().CurrentStore.Id : 0;
//although it's better to connect to your database and execute the following SQL:
//DELETE FROM [Setting] WHERE [StoreId] > 0
return c.Resolve<ISettingService>().LoadSetting<TSettings>();
})
.InstancePerLifetimeScope()
.CreateRegistration();
}
public bool IsAdapterForIndividualComponents { get { return false; } }
}
如何添加相关的设置
像commonsetting一样,只需要定义一个实现空接口ISettings的类,然后的数据表中添加相关的配置,数据库中Name值对应:类名 + . + 属性名,和接口注入方式一样,不过这里使用类注入。另外需要注意的是在Nop.Core项目ComponentModel目录下的GenericDictionaryTypeConverter和GenericListTypeConverter类中重写了泛型List和泛型Dictionary的CanConvertFrom和ConvertFrom方法,使得数据库中存储字符串能转换成对应的List和Dictionary,如List存储时我们只需要将多个数据使用英文符号(,)分隔符即可。
public class CommonSettings : ISettings
{
public CommonSettings()
{
IgnoreLogWordlist = new List<string>();
}
/// <summary>
/// Gets or sets a value indicating whether stored procedures are enabled (should be used if possible)
/// </summary>
public bool UseStoredProceduresIfSupported { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to use stored procedure (if supported) for loading categories (it's much faster in admin area with a large number of categories than the LINQ implementation)
/// </summary>
public bool UseStoredProcedureForLoadingCategories { get; set; }
/// <summary>
/// Gets or sets a value indicating whether 404 errors (page or file not found) should be logged
/// </summary>
public bool Log404Errors { get; set; }
/// <summary>
/// Gets or sets ignore words (phrases) to be ignored when logging errors/messages
/// </summary>
public List<string> IgnoreLogWordlist { get; set; }
}
public class HomeController : Controller
{
public ILogger _logger;
public IUserActivityService _userActivityService;
public CommonSettings _commonSettings;
public HomeController(
ILogger logger,
IUserActivityService userActivityService,
CommonSettings commonSetting)
{
_logger = logger;
_userActivityService = userActivityService;
_commonSettings = commonSettings;
}
public ActionResult Index()
{
TestSettings();
TestLogger();
return View();
}
private void TestSettings()
{
var s = _commonSettings.IgnoreLogWordlist;
}
private void TestLogger()
{
_logger.InsertLog(LogLevel.Information, "index visit");
_userActivityService.InsertActivity(ActivityLogTypeEnum.AddUser, "添加用户{0},{1}", new string[2] { "aaaa", "bbb" });
}
}
数据库配置(IDataProvider)
之前使用web.config配置的connectionStrings,现在改为IDataProvider的实现来统一配置相关的参数,特别提示数据库配置文件在App_Data目录下的Settings.txt,如果没有新建一个,系统运行后会根据EntityFramework的数据映射自动创建相关表。
DataProvider: sqlserver
DataConnectionString: Data Source=.;Initial Catalog=nopFramework;Integrated Security=False;Persist Security Info=False;User ID=sa;Password=sa1234
三、日志模块
ILogger接口,日志接口。
NullLogger类,Logger接口空实现。
DefaultLogger类,Nop默认的日志接口实现。
LoggingExtensions类,日志扩展,使用日志的扩展方法来存储不同级别的日志记录。
IUserActivityService接口,用户操作服务接口。
UserActivityService类,用户操作服务实现。
Nop没有使用类似于Log4net的开源日志记录组件,当然如果你想使用可以通过实现接口来引入。IUserActivityService用于记录用户操作的记录,需要在ActivityLogType表配置好用户操作的类型,这里优化了一下,将类型通过枚举列出来,这样在记录用户操作的时候不至于输错参数。在首页的控制器中加入测试代码,日志和操作记录都添加到了数据库中。
private void TestLogger()
{
_logger.InsertLog(LogLevel.Information, "index visit");
_userActivityService.InsertActivity(ActivityLogTypeEnum.AddUser, "添加用户{0},{1}", new string[2] { "aaaa", "bbb" });
}
至此,开发框架中添加了常用的缓存、网站设置、系统日志、用户操作日志功能。
作者:徐领
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如果本文对您有用,请不吝点上一个赞,谢谢。