zoukankan      html  css  js  c++  java
  • 基于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" }); 
            }
      
      至此,开发框架中添加了常用的缓存、网站设置、系统日志、用户操作日志功能。
  • 相关阅读:
    【题解】 [yLOI2019] 梅深不见冬
    【题解】[CSP-S2019] Emiya 家今天的饭
    【题解】Acwing400. 太鼓达人
    【题解】[ZJOI2007]最大半连通子图
    【题解】Acwing395. 冗余路径
    【题解】CF487E Tourists
    “𣎴” 这个字存Mysql Incorrect string value: 'xF0xA3x8ExB4' for column 'msg' at row 1
    logminer分析异机db的归档日志(外部文件)
    logminer存储在外部文件(external file)
    logminer分析在线redo log
  • 原文地址:https://www.cnblogs.com/Alex80/p/12375212.html
Copyright © 2011-2022 走看看