最近忙于学车,抽时间将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[] { "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[] { "aaaa", "bbb" });
}
  
  至此,开发框架中添加了常用的缓存、网站设置、系统日志、用户操作日志功能。

基于NopCommerce的开发框架——缓存、网站设置、系统日志、用户操作日志的更多相关文章

  1. 基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

    在我们对数据进行重要修改调整的时候,往往需要跟踪记录好用户操作日志.一般来说,如对重要表记录的插入.修改.删除都需要记录下来,由于用户操作日志会带来一定的额外消耗,因此我们通过配置的方式来决定记录那些 ...

  2. SqlServer设置特定用户操作特定表(插入、删除、更新、查询 的权限设置)

    目录 一.需求场景: 二.操作步骤: 表上右键选择[属性],选择[权限]选项卡: 点击[搜索],在弹出的框中点击[浏览],选择需要设置的用户: 在上面点击[确定]后,就可以在[权限]选项卡中看到权限列 ...

  3. .Net捕获网站异常信息记录操作日志

    第一步:在Global.asax文件下的Application_Error()中写入操作日志 /// <summary> /// 整个网站出现异常信息,都会执行此方法 /// </s ...

  4. 基于nopCommerce的开发框架(附源码)

    .NET的开发人员应该都知道这个大名鼎鼎的高质量b2c开源项目-nopCommerce,基于EntityFramework和MVC开发,拥有透明且结构良好的解决方案,同时结合了开源和商业软件的最佳特性 ...

  5. 053医疗项目-模块五:权限设置-将用户操作权限写入Session

    权限管理指的是用户授权,与拦截器没有关系.拦截器只是一个技术,也可以用别的技术来实现的.别人问你权限管理,可不要和人家说什么拦截器.要说用户授权 前一篇文章是把实现了不同的用户呈现不用的菜单.这一篇文 ...

  6. 基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理

    在一个应用系统的开发框架中,往往很多地方需要用到缓存的处理,有些地方是为了便于记录用户的数据,有些地方是为了提高系统的响应速度,如有时候我们在发送一个短信验证码的时候,可以在缓存中设置几分钟的过期时间 ...

  7. 基于SqlSugar的开发框架循序渐进介绍(20)-- 在基于UniApp+Vue的移动端实现多条件查询的处理

    在做一些常规应用的时候,我们往往需要确定条件的内容,以便在后台进行区分的进行精确查询,在移动端,由于受限于屏幕界面的情况,一般会对多个指定的条件进行模糊的搜索,而这个搜索的处理,也是和前者强类型的条件 ...

  8. 基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理

    在早期的随笔就介绍过,把常规页面的内容拆分为几个不同的组件,如普通的页面,包括列表查询.详细资料查看.新增资料.编辑资料.导入资料等页面场景,这些内容相对比较独立,而有一定的代码量,本篇随笔介绍基于V ...

  9. 基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用

    在我们实际项目开发过程中,往往需要根据实际情况,对组件进行封装,以更简便的在界面代码中使用,在实际的前端应用中,适当的组件封装,可以减少很多重复的界面代码,并且能够非常简便的使用,本篇随笔介绍基于El ...

随机推荐

  1. NuGet(Nuget Packages)

    Nuget是一个.NET平台下的开源的项目,它是Visual Studio的扩展.在使用Visual Studio开发基于.NET Framework的应用时,Nuget能把在项目中添加.移除和更新引 ...

  2. C++学习笔记1(标准的输入输出)

    前言: 个人一直以来比较懒,最近才准备记录一下自己学习C++的学习过程,希望自己能在写博客的时候能够坚持下去,欢迎大家在博客中支出存在的问题,好了不多说了,自己能坚持下去.我准备在我的博客中通过与C语 ...

  3. vue 调用高德地图

    一. vue-amap,一个基于 Vue 2.x 和高德地图的地图组件 https://elemefe.github.io/vue-amap/#/ 这个就不细说了,按照其文档,就能够安装下来. 二. ...

  4. 如何使用HTML5自定义数据属性

    在本文中,我将向你介绍如何使用HTML5自定义数据属性.我还将向你介绍一些开发人员在工作中经常使用的优秀实例. 为什么需要自定义数据属性? 很多时候我们需要存储一些与不同DOM元素相关联的信息.这些信 ...

  5. JS模式--装饰者模式

    在Javascript中动态的给对象添加职责的方式称作装饰者模式. 下面我们通常遇到的例子: var a = function () { alert(1); };//改成: var a = funct ...

  6. [ext4]磁盘布局 - group分析

    ext4文件系统的磁盘布局是先把磁盘分成一个个相同大小的block块(每个block块的大小默认是4K),然后把这些block块合成一个个group. group大小最大为256M(默认为256M), ...

  7. [移动端] IOS下border-image不起作用的解决办法

    上周五突然接到现场的一个需求,做一个移动端的劳模展示页面.现场美工把原型图发了过来.这个样子的: 说实在的很想吐槽一下我们美工的审美哈,不过这不是重点. 因为边框是需要特殊花纹的所以打算用border ...

  8. webpack学习(三)之web-dev-server不能自动刷新问题

    使用webpack-dev-server中遇到不能浏览器无法自动刷新的问题:寻找多方答案后明白了一些: 下面有一些需要注意的点: 1.webpack-dev-server并不能读取你的webpack. ...

  9. Linux centos7下安装配置redis及Redis desktop Manager工具连接注意事项

    基本工具:VMware12.CentOS-7-x86_64-Everything-1611.iso.redis-desktop-manager-0.8.0.3841 废话不多说,首先,关于什么是Red ...

  10. Transform java future into completable future 【将 future 转成 completable future】

    Future is introduced in JDK 1.5 by Doug Lea to represent "the result of an asynchronous computa ...