zoukankan      html  css  js  c++  java
  • [开源]MasterChief 快速开发辅助类库

    C# 开发辅助类库,和士官长一样身经百战且越战越勇的战争机器,能力无人能出其右。
    GitHub:MasterChief 欢迎Star,欢迎Issues;
    项目架构思维导图:

    设计

    目录

    1. 数据库访问


    a. 支持Dapper和Entity Framework 两种ORM框架;

    b. 通过IOC可以很少代码在Dapper和Entity Framework切换;

    c. 实现Repository和UnitOfWork;

    d. CURD以及事务实现简单,很大程度关注业务实现即可;

    代码使用说明:

    1. Create 添加
    public bool Create(EFSample samle)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.Create<EFSample>(samle);
        }
    }
    
    1. Delete 删除
    public bool Delete(EFSample sample)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.Delete(sample);
        }
    }
    
    1. Update 修改
    public bool Update(EFSample sample)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.Update(sample);
        }
    }
    
    1. GetByKeyID 根据主键查询
    public EFSample GetByKeyID(Guid id)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.GetByKeyID<EFSample>(id);
        }
    }
    
    1. GetList 条件查询集合
    public List<EFSample> GetList(Expression<Func<EFSample, bool>> predicate = null)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.GetList<EFSample>(predicate);
        }
    }
    
    1. Exist 条件查询是否存在
    public bool Exist(Expression<Func<EFSample, bool>> predicate = null)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.Exist<EFSample>(predicate);
        }
    }
    
    1. SqlQuery 执行Sql脚本
    public List<EFSample> SqlQuery(string sql, DbParameter[] parameter)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.SqlQuery<EFSample>(sql, parameter)?.ToList();
        }
    }
    
    1. CreateWithTransaction 事务处理
    public bool CreateWithTransaction(EFSample sample, EFSample sample2)
    {
        bool result = true;
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            try
            {
                dbcontext.BeginTransaction();//开启事务
                dbcontext.Create(sample);
                dbcontext.Create(sample2);
                dbcontext.Commit();
            }
            catch (Exception)
            {
                dbcontext.Rollback();
                result = false;
            }
        }
     
        return result;
    }
    
    1. GetFirstOrDefault 条件查询第一项或默认数据
    public EFSample GetFirstOrDefault(Expression<Func<EFSample, bool>> predicate = null)
    {
        using (IDbContext dbcontext = _contextFactory.Create())
        {
            return dbcontext.GetFirstOrDefault<EFSample>(predicate);
        }
    }
    
    1. 单元测试以及Sql Server脚本
    using MasterChief.DotNet.Core.DapperTests;
    using MasterChief.DotNet.Core.DapperTests.Model;
    using MasterChief.DotNet.Core.DapperTests.Service;
    using MasterChief.DotNet4.Utilities.Common;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Ninject;
    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Data.SqlClient;
    using System.Threading.Tasks;
     
    namespace MasterChief.DotNet.Core.Dapper.Tests
    {
        [TestClass()]
        public class SampleServiceTests
        {
            private IKernel _kernel = null;
            private ISampleService _sampleService = null;
            private readonly Guid _testID = "2F6D3C43-C2C7-4398-AD2B-ED5E82D78888".ToGuidOrDefault(Guid.Empty);
            private readonly string _testName = "DapperSample";
     
            [TestInitialize]
            public void SetUp()
            {
                _kernel = new StandardKernel(new ServiceModule());
                Assert.IsNotNull(_kernel);
     
                _sampleService = _kernel.Get<ISampleService>();
                if (!_sampleService.Exist(ent => ent.ID == _testID))
                {
                    _sampleService.Create(new EFSample() { UserName = _testName, ID = _testID });
                }
            }
     
            /// <summary>
            /// 创建测试
            /// </summary>
            [TestMethod()]
            public void CreateTest()
            {
                bool actual = _sampleService.Create(new EFSample() { UserName = "Dapper" + DateTime.Now.ToString("MMddHHmmss") });
                Assert.IsTrue(actual);
            }
     
            [TestMethod()]
            public void GetFirstOrDefaultTest()
            {
                EFSample actual = _sampleService.GetFirstOrDefault(ent => ent.ID == _testID);
                Assert.IsNotNull(actual);
            }
     
            [TestMethod()]
            public void GetByKeyIdTest()
            {
                EFSample actual = _sampleService.GetByKeyID(_testID);
                Assert.IsNotNull(actual);
            }
     
            [TestMethod()]
            public void DeleteTest()
            {
                bool actual = _sampleService.Delete(new EFSample() { ID = _testID });
                Assert.IsTrue(actual);
            }
     
            [TestMethod()]
            public void GetListTest()
            {
                List<EFSample> actual = _sampleService.GetList(ent => ent.Available == true);
                Assert.IsNotNull(actual);
                CollectionAssert.AllItemsAreNotNull(actual);
            }
     
            [TestMethod()]
            public void UpdateTest()
            {
                EFSample sample = new EFSample
                {
                    ID = _testID,
                    ModifyTime = DateTime.Now,
                    UserName = "modify"
                };
                bool actual = _sampleService.Update(sample);
                Assert.IsNotNull(actual);
            }
     
            [TestMethod()]
            public void TransactionSuccessTest()
            {
                EFSample sample = new EFSample
                {
                    UserName = "TransactionSuccess1"
                };
     
                EFSample sample2 = new EFSample
                {
                    UserName = "TransactionSuccess2"
                };
                bool actual = _sampleService.CreateWithTransaction(sample, sample2);
                Assert.IsTrue(actual);
            }
     
            [TestMethod()]
            public void TransactionFailTest()
            {
                EFSample sample3 = new EFSample
                {
                    UserName = "TransactionSuccess3"
                };
     
                EFSample sample4 = new EFSample
                {
                    UserName = null
                };
                bool actual = _sampleService.CreateWithTransaction(sample3, sample4);
                Assert.IsFalse(actual);
            }
     
            [TestMethod()]
            public void ExistTest()
            {
                bool actual = _sampleService.Exist(ent => ent.ID == _testID);
                Assert.IsTrue(actual);
     
                actual = _sampleService.Exist(ent => ent.UserName == _testName);
                Assert.IsTrue(actual);
     
                actual = _sampleService.Exist(ent => ent.CreateTime >= DateTime.Now.AddDays(-1));
                Assert.IsTrue(actual);
     
                actual = _sampleService.Exist(ent => ent.CreateTime <= DateTime.Now);
                Assert.IsTrue(actual);
     
                actual = _sampleService.Exist(ent => ent.Available == true);
                Assert.IsTrue(actual);
     
                actual = _sampleService.Exist(ent => ent.Available != true);
                Assert.IsFalse(actual);
            }
     
            [TestMethod()]
            public void SqlQueryTest()
            {
                string sql = @"select * from [dbo].[EFSample]
    where CreateTime>=@CreateTime
    and Available=@Available
    order by CreateTime desc";
                DbParameter[] parameter = {
                        new SqlParameter(){ ParameterName="@CreateTime", Value=DateTime.Now.AddDays(-1) },
                        new SqlParameter(){ ParameterName="@Available", Value=true }
                    };
                List<EFSample> actual = _sampleService.SqlQuery(sql, parameter);
                Assert.IsNotNull(actual);
                CollectionAssert.AllItemsAreNotNull(actual);
            }
     
            /// <summary>
            /// 多线程测试
            /// </summary>
            [TestMethod()]
            public void CreateTestThreadTest()
            {
                Task[] tasks = {
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                    Task.Factory.StartNew(() => CreateTest()),
                                };
                Task.WaitAll(tasks);
            }
        }
    }
    
    USE [Sample]
    GO
     
    /****** Object:  Table [dbo].[EFSample]    Script Date: 2019/3/9 22:04:45 ******/
    SET ANSI_NULLS ON
    GO
     
    SET QUOTED_IDENTIFIER ON
    GO
     
    CREATE TABLE [dbo].[EFSample](
    	[ID] [uniqueidentifier] NOT NULL,
    	[CreateTime] [datetime] NOT NULL,
    	[ModifyTime] [datetime] NOT NULL,
    	[Available] [bit] NOT NULL,
    	[UserName] [nvarchar](20) NOT NULL,
     CONSTRAINT [EFSamle_PK] PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    GO
     
    EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'EFSample', @level2type=N'COLUMN',@level2name=N'UserName'
    GO
    

    2. 日志


    a. 目前实现基于Log4Net的本地文件日志以及Kafka ELK的日志;

    b. 基于接口ILogService可以很容易扩展其他日志显示;

    代码使用说明

    1. 配置依赖注入,日志实现方式,这里采用文件日志形式
    using MasterChief.DotNet.Core.Log;
    using Ninject.Modules;
     
    namespace MasterChief.DotNet.Core.LogTests
    {
        public sealed class LogModule : NinjectModule
        {
            public override void Load()
            {
                Bind<ILogService>().To<FileLogService>().InSingletonScope();
            }
        }
    }
    
    1. 拷贝日志config文件到项目内,并设置属性“始终复制”到输出目录,您可以根据项目需求调整config内容
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" />
      </configSections>
      <log4net>
        <!-- FileLogger -->
        <logger name="FATAL_FileLogger">
          <level value="ALL" />
          <appender-ref ref="FATAL_FileAppender" />
        </logger>
        <logger name="ERROR_FileLogger">
          <level value="ALL" />
          <appender-ref ref="ERROR_FileAppender" />
        </logger>
        <logger name="WARN_FileLogger">
          <level value="ALL" />
          <appender-ref ref="WARN_FileAppender" />
        </logger>
        <logger name="INFO_FileLogger">
          <level value="ALL" />
          <appender-ref ref="INFO_FileAppender" />
        </logger>
        <logger name="DEBUG_FileLogger">
          <level value="ALL" />
          <appender-ref ref="DEBUG_FileAppender" />
        </logger>
        <!-- AdoNetLogger -->
        <!--<logger name="AdoNetLogger">
          <level value="ALL" />
          <appender-ref ref="AdoNetAppender" />
        </logger>-->
        <!-- ConsoleLogger -->
        <logger name="ConsoleLogger">
          <level value="ALL" />
          <appender-ref ref="ColoredConsoleAppender" />
        </logger>
     
        <!--使用Rolling方式记录日志按照日来记录日志-->
        <appender name="FATAL_FileAppender" type="log4net.Appender.RollingFileAppender">
          <!--文件名,可以相对路径,也可以绝对路径,这里只给定了文件夹-->
          <file value=".log\FATAL\" />
          <!--是否增加文件-->
          <appendToFile value="true" />
          <maxSizeRollBackups value="5" />
          <!--日志追加类型,Date为按日期增加文件,Size为按大小-->
          <rollingStyle value="Date" />
          <!--最小锁定模型以允许多个进程可以写入同一个文件,解决文件独占问题-->
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <!--最大文件大小-->
          <maximumFileSize value="10MB" />
          <!--文件命名格式,非日期参数化要进行转义,如自定义文件后缀-->
          <datePattern value="yyyyMM\yyyy-MM-dd&quot;.log&quot;" />
          <!--是否固定文件名-->
          <staticLogFileName value="false" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="---------------------------------------------------%newline发生时间:%date %newline事件级别:%-5level %newline事件来源:%logger%newline日志内容:%message%newline" />
          </layout>
        </appender>
        <appender name="ERROR_FileAppender" type="log4net.Appender.RollingFileAppender">
          <!--文件名,可以相对路径,也可以绝对路径,这里只给定了文件夹-->
          <file value=".log\ERROR\" />
          <!--是否增加文件-->
          <appendToFile value="true" />
          <maxSizeRollBackups value="5" />
          <!--日志追加类型,Date为按日期增加文件,Size为按大小-->
          <rollingStyle value="Date" />
          <!--最小锁定模型以允许多个进程可以写入同一个文件,解决文件独占问题-->
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <!--最大文件大小-->
          <maximumFileSize value="10MB" />
          <!--文件命名格式,非日期参数化要进行转义,如自定义文件后缀-->
          <datePattern value="yyyyMM\yyyy-MM-dd&quot;.log&quot;" />
          <!--是否固定文件名-->
          <staticLogFileName value="false" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="---------------------------------------------------%newline发生时间:%date %newline事件级别:%-5level %newline事件来源:%logger%newline日志内容:%message%newline" />
          </layout>
        </appender>
        <appender name="WARN_FileAppender" type="log4net.Appender.RollingFileAppender">
          <!--文件名,可以相对路径,也可以绝对路径,这里只给定了文件夹-->
          <file value=".log\WARN\" />
          <!--是否增加文件-->
          <appendToFile value="true" />
          <maxSizeRollBackups value="5" />
          <!--日志追加类型,Date为按日期增加文件,Size为按大小-->
          <rollingStyle value="Date" />
          <!--最小锁定模型以允许多个进程可以写入同一个文件,解决文件独占问题-->
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <!--最大文件大小-->
          <maximumFileSize value="10MB" />
          <!--文件命名格式,非日期参数化要进行转义,如自定义文件后缀-->
          <datePattern value="yyyyMM\yyyy-MM-dd&quot;.log&quot;" />
          <!--是否固定文件名-->
          <staticLogFileName value="false" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="---------------------------------------------------%newline发生时间:%date %newline事件级别:%-5level %newline事件来源:%logger%newline日志内容:%message%newline" />
          </layout>
        </appender>
        <appender name="INFO_FileAppender" type="log4net.Appender.RollingFileAppender">
          <!--文件名,可以相对路径,也可以绝对路径,这里只给定了文件夹-->
          <file value=".log\INFO\" />
          <!--是否增加文件-->
          <appendToFile value="true" />
          <maxSizeRollBackups value="5" />
          <!--日志追加类型,Date为按日期增加文件,Size为按大小-->
          <rollingStyle value="Date" />
          <!--最小锁定模型以允许多个进程可以写入同一个文件,解决文件独占问题-->
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <!--最大文件大小-->
          <maximumFileSize value="10MB" />
          <!--文件命名格式,非日期参数化要进行转义,如自定义文件后缀-->
          <datePattern value="yyyyMM\yyyy-MM-dd&quot;.log&quot;" />
          <!--是否固定文件名-->
          <staticLogFileName value="false" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="---------------------------------------------------%newline发生时间:%date %newline事件级别:%-5level %newline事件来源:%logger%newline日志内容:%message%newline" />
          </layout>
        </appender>
        <appender name="DEBUG_FileAppender" type="log4net.Appender.RollingFileAppender">
          <!--文件名,可以相对路径,也可以绝对路径,这里只给定了文件夹-->
          <file value=".log\DEBUG\" />
          <!--是否增加文件-->
          <appendToFile value="true" />
          <maxSizeRollBackups value="5" />
          <!--日志追加类型,Date为按日期增加文件,Size为按大小-->
          <rollingStyle value="Date" />
          <!--最小锁定模型以允许多个进程可以写入同一个文件,解决文件独占问题-->
          <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
          <!--最大文件大小-->
          <maximumFileSize value="10MB" />
          <!--文件命名格式,非日期参数化要进行转义,如自定义文件后缀-->
          <datePattern value="yyyyMM\yyyy-MM-dd&quot;.log&quot;" />
          <!--是否固定文件名-->
          <staticLogFileName value="false" />
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="---------------------------------------------------%newline发生时间:%date %newline事件级别:%-5level %newline事件来源:%logger%newline日志内容:%message%newline" />
          </layout>
        </appender>
        <!--使用AdoNetAppender方式记录日志按照日来记录日志-->
        <!--<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
          <bufferSize value="1" />
          <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          <connectionString value="DATABASE=Sample;SERVER=.SQLEXPRESS;UID=sa;PWD=sasa;Connect Timeout=15;" />
          <commandText value="INSERT INTO [Log4Net] ([Date],[Host],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @host, @thread, @log_level, @logger, @message, @exception)" />
          <parameter>
            <parameterName value="@log_date" />
            <dbType value="DateTime" />
            <layout type="log4net.Layout.RawTimeStampLayout" />
          </parameter>
          <parameter>
            <parameterName value="@thread" />
            <dbType value="String" />
            <size value="255" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%thread" />
            </layout>
          </parameter>
     
          <parameter>
            <parameterName value="@host" />
            <dbType value="String" />
            <size value="50" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%property{log4net:HostName}" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@log_level" />
            <dbType value="String" />
            <size value="50" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%level" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@logger" />
            <dbType value="String" />
            <size value="255" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%logger" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@message" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%message" />
            </layout>
          </parameter>
          <parameter>
            <parameterName value="@exception" />
            <dbType value="String" />
            <size value="4000" />
            <layout type="log4net.Layout.ExceptionLayout" />
          </parameter>
        </appender>-->
        <!--使用ConsoleAppender方式记录日志按照日来记录日志-->
        <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
          <mapping>
            <level value="INFO" />
            <foreColor value="White, HighIntensity" />
            <backColor value="Green" />
          </mapping>
          <mapping>
            <level value="DEBUG" />
            <foreColor value="White, HighIntensity" />
            <backColor value="Blue" />
          </mapping>
          <mapping>
            <level value="WARN" />
            <foreColor value="Yellow, HighIntensity" />
            <backColor value="Purple" />
          </mapping>
          <mapping>
            <level value="ERROR" />
            <foreColor value="Yellow, HighIntensity" />
            <backColor value="Red" />
          </mapping>
          <layout type="log4net.Layout.PatternLayout">
            <conversionPattern value="---------------------------------------------------%newline发生时间:%date %newline事件级别:%-5level%newline事件来源:%logger%newline事件行号:%line%newline日志内容:%message%newline" />
          </layout>
        </appender>
        <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
          <remoteAddress value="127.0.0.1" />
          <remotePort value="7071" />
          <layout type="log4net.Layout.XmlLayoutSchemaLog4j" />
        </appender>
        <root>
          <appender-ref ref="UdpAppender" />
        </root>
      </log4net>
    </configuration>
    
    1. 单元测试
    using MasterChief.DotNet.Core.LogTests;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Ninject;
     
    namespace MasterChief.DotNet.Core.Log.Tests
    {
        [TestClass()]
        public class FileLogServiceTests
        {
            private IKernel _kernel = null;
            private ILogService _logService = null;
     
            [TestInitialize]
            public void SetUp()
            {
                _kernel = new StandardKernel(new LogModule());
                Assert.IsNotNull(_kernel);
     
                _logService = _kernel.Get<ILogService>();
            }
     
            [TestMethod()]
            public void DebugTest()
            {
                _logService.Debug("DebugTest");
            }
     
            [TestMethod()]
            public void ErrorTest()
            {
                _logService.Error("ErrorTest");
            }
     
            [TestMethod()]
            public void FatalTest()
            {
                _logService.Fatal("FatalTest");
            }
     
            [TestMethod()]
            public void InfoTest()
            {
                _logService.Info("InfoTest");
            }
     
            [TestMethod()]
            public void WarnTest()
            {
                _logService.Warn("WarnTest");
            }
        }
    }
    

    3. 缓存


    a. 支持本地内存缓存,HttpRequest请求缓存,Redis缓存;

    b. 基于ICacheProvider接口,可以很容易扩展其他缓存实现;

    代码使用说明:

    1. 配置依赖注入,缓存实现方式,这里采用LocalCacheProvider缓存实现;

      using MasterChief.DotNet.Core.Cache;
      using Ninject.Modules;
       
      namespace MasterChief.DotNet.Core.CacheTests
      {
          public sealed class CacheModule : NinjectModule
          {
              public override void Load()
              {
                  Bind<ICacheProvider>().To<LocalCacheProvider>().InSingletonScope();
              }
          }
      }
      
    2. 单元测试

      using MasterChief.DotNet.Core.CacheTests;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using Ninject;
       
      namespace MasterChief.DotNet.Core.Cache.Tests
      {
          [TestClass()]
          public class LocalCacheProviderTests
          {
              private IKernel _kernel = null;
              private ICacheProvider _cacheProvider = null;
              private readonly string _testCacheKey = "sampleKey";
              private readonly string _testCache = "sample";
              private readonly string _testKeyFormat = "login_{0}";
       
              [TestInitialize]
              public void SetUp()
              {
                  _kernel = new StandardKernel(new CacheModule());
                  Assert.IsNotNull(_kernel);
       
                  _cacheProvider = _kernel.Get<ICacheProvider>();
                  _cacheProvider.Set(_testCacheKey, _testCache, 10);
              }
       
              [TestMethod()]
              public void GetTest()
              {
                  string actual = _cacheProvider.Get<string>(_testCacheKey);
                  Assert.AreEqual(_testCache, actual);
              }
       
              [TestMethod()]
              public void IsSetTest()
              {
                  bool actual = _cacheProvider.IsSet(_testCacheKey);
                  Assert.IsTrue(actual);
              }
       
              [TestMethod()]
              public void RemoveTest()
              {
                  _cacheProvider.Remove(_testCacheKey);
                  bool actual = _cacheProvider.IsSet(_testCacheKey);
                  Assert.IsFalse(actual);
              }
       
              [TestMethod()]
              public void RemoveByPatternTest()
              {
                  string _loginKey = string.Format(_testKeyFormat, "123");
                  _cacheProvider.Set(_loginKey, _testCache, 10);
                  bool actual = _cacheProvider.IsSet(_loginKey);
                  Assert.IsTrue(actual);
                  _cacheProvider.RemoveByPattern(_testKeyFormat);
                  actual = _cacheProvider.IsSet(_loginKey);
                  Assert.IsFalse(actual);
                  actual = _cacheProvider.IsSet(_testCacheKey);
                  Assert.IsTrue(actual);
              }
       
              [TestMethod()]
              public void SetTest()
              {
                  _cacheProvider.Set("sampleSetKey", "sampleSetCache", 10);
                  bool actual = _cacheProvider.IsSet("sampleSetKey");
                  Assert.IsTrue(actual);
              }
          }
      }
      
      

    4. 配置


    a. 目前支持配置文件本地持久化,并且支持配置文件缓存依赖减少读取文件次数;

    b. 基于IConfigProvider接口,可以很容易扩展其他配置实现;

    代码使用说明:

    1. 配置依赖注入,配置实现方式,这里采用FileConfigProvider缓存实现;

      using MasterChief.DotNet.Core.Config;
      using Ninject.Modules;
       
      namespace MasterChief.DotNet.Core.ConfigTests
      {
          public sealed class ConfigModule : NinjectModule
          {
              public override void Load()
              {
                  Bind<IConfigProvider>().To<FileConfigService>().InSingletonScope();
                  // Bind<ConfigContext>().ToSelf().InSingletonScope();
                  Bind<ConfigContext>().To<CacheConfigContext>().InSingletonScope();
              }
          }
      }
      
    2. 扩展配置上下文基于文件依赖

      using MasterChief.DotNet.Core.Config;
      using MasterChief.DotNet4.Utilities.WebForm.Core;
      using System;
      using System.Web.Caching;
       
      namespace MasterChief.DotNet.Core.ConfigTests
      {
          public sealed class CacheConfigContext : ConfigContext
          {
              public override T Get<T>(string index = null)
              {
                  if (!(base.ConfigService is FileConfigService))
                  {
                      throw new NotSupportedException("CacheConfigContext");
                  }
                  string filePath = GetClusteredIndex<T>(index);
                  string key = filePath;
                  object cacheContent = CacheManger.Get(key);
                  if (cacheContent != null)
                  {
                      return (T)cacheContent;
                  }
                  T value = base.Get<T>(index);
                  CacheManger.Set(key, value, new CacheDependency(filePath));
                  return value;
              }
          }
      }
      
    3. 单元测试

      using MasterChief.DotNet.Core.ConfigTests;
      using Microsoft.VisualStudio.TestTools.UnitTesting;
      using Ninject;
      using System.Collections.Generic;
       
      namespace MasterChief.DotNet.Core.Config.Tests
      {
          [TestClass()]
          public class FileConfigServiceTests
          {
              private IKernel _kernel = null;
              private IConfigProvider _configProvider = null;
              public ConfigContext _configContext = null;
       
              [TestInitialize]
              public void SetUp()
              {
                  _kernel = new StandardKernel(new ConfigModule());
                  Assert.IsNotNull(_kernel);
       
                  _configProvider = _kernel.Get<IConfigProvider>();
                  _configContext = _kernel.Get<ConfigContext>();
              }
       
              [TestMethod()]
              public void SaveConfigTest()
              {
                  RedisConfig redisConfig = new RedisConfig
                  {
                      AutoStart = true,
                      LocalCacheTime = 10,
                      MaxReadPoolSize = 1024,
                      MaxWritePoolSize = 1024,
                      ReadServerList = "10",
                      RecordeLog = true,
                      WriteServerList = "10"
                  };
                  redisConfig.RedisItems = new List<RedisItemConfig>
                  {
                      new RedisItemConfig() { Text = "MasterChief" },
                      new RedisItemConfig() { Text = "Config." }
                  };
       
                  _configContext.Save(redisConfig, "prod");
                  _configContext.Save(redisConfig, "alpha");
       
                  RedisConfig prodRedisConfig = _configContext.Get<RedisConfig>("prod");
                  Assert.IsNotNull(prodRedisConfig);
      
                  prodRedisConfig = _configContext.Get<RedisConfig>("prod");//文件缓存测试
                  Assert.IsNotNull(prodRedisConfig);
      
                  RedisConfig alphaRedisConfig = _configContext.Get<RedisConfig>("alpha");
                  Assert.IsNotNull(alphaRedisConfig);
       
                  DaoConfig daoConfig = new DaoConfig
                  {
                      Log = "server=localhost;database=Sample;uid=sa;pwd=sasa"
                  };
                  _configContext.Save(daoConfig, "prod");
                  _configContext.Save(daoConfig, "alpha");
                  DaoConfig prodDaoConfig = _configContext.Get<DaoConfig>("prod");
                  Assert.IsNotNull(prodDaoConfig);
       
                  DaoConfig alphaDaoConfig = _configContext.Get<DaoConfig>("alpha");
                  Assert.IsNotNull(alphaDaoConfig);
              }
          }
      }
      
    4. 本地配置会在程序根目录Config下,如图:

      1552231625890

    5. 配置文件基于XML持久化存储,如图:

      1552231725395

    5. 验证码


    a. 派生实现ValidateCodeType抽象类,来自定义验证码样式;

    b. 派生实现VerifyCodeHandler抽象类,快速切换需要显示验证码;

    代码使用说明:

    1. Mvc 简单使用如下:

      /// <summary>
      ///     处理生成Mvc 程序验证码
      /// </summary>
      public sealed class MvcVerifyCodeHandler : VerifyCodeHandler
      {
          public override void OnValidateCodeCreated(HttpContext context, string validateCode)
          {
              context.Session["validateCode"] = validateCode;
          }
       
          public override byte[] CreateValidateCode(string style)
          {
              ValidateCodeType createCode;
              switch (style)
              {
                  case "type1":
                      createCode = new ValidateCode_Style1();
                      break;
                  default:
                      createCode = new ValidateCode_Style1();
                      break;
              }
       
              var buffer = createCode.CreateImage(out var validateCode);
              OnValidateCodeCreated(HttpContext.Current, validateCode);
              return buffer;
          }
      }
      
    2. WebForm 简单使用如下:

      /// <summary>
      ///     WebFormVerifyCodeHandler 的摘要说明
      /// </summary>
      public class WebFormVerifyCodeHandler : VerifyCodeHandler, IHttpHandler, IRequiresSessionState
      {
          public void ProcessRequest(HttpContext context)
          {
              var validateType = context.Request.Params["style"];
              var buffer = CreateValidateCode(validateType);
              context.Response.ClearContent();
              context.Response.ContentType = MimeTypes.ImageGif;
              context.Response.BinaryWrite(buffer);
          }
       
          public bool IsReusable => false;
       
          public override void OnValidateCodeCreated(HttpContext context, string validateCode)
          {
              context.Session["validateCode"] = validateCode;
          }
       
          public override byte[] CreateValidateCode(string style)
          {
              style = style?.Trim();
              ValidateCodeType createCode;
              switch (style)
              {
                  case "type1":
                      createCode = new ValidateCode_Style1();
                      break;
       
                  default:
                      createCode = new ValidateCode_Style1();
                      break;
              }
       
              var buffer = createCode.CreateImage(out var validateCode);
              OnValidateCodeCreated(HttpContext.Current, validateCode);
              return buffer;
          }
      }
      
      

    6. 序列化与反序列化


    a. 目前支持Json以及Protobuf两种方式的序列化与反序列化

    b. 可以通过实现接口ISerializer扩展实现其他方式;

    代码使用说明:

    private static void Main()
    {
        SampleSerializer(new JsonSerializer());
        Console.WriteLine(Environment.NewLine);
        SampleSerializer(new ProtocolBufferSerializer());
        Console.ReadLine();
    }
     
    private static void SampleSerializer(ISerializer serializer)
    {
        #region 单个对象序列化与反序列化
     
        var person = new Person();
        person.Age = 10;
        person.FirstName = "yan";
        person.LastName = "zhiwei";
        person.Remark = "ISerializer Sample";
        var jsonText = serializer.Serialize(person);
        Console.WriteLine($"{serializer.GetType().Name}-Serialize" + jsonText);
     
     
        var getPerson = serializer.Deserialize<Person>(jsonText);
        Console.WriteLine($"{serializer.GetType().Name}-Deserialize" + getPerson);
     
        #endregion
     
        #region 集合序列化与反序列化
     
        var persons = new List<Person>();
        for (var i = 0; i < 10; i++)
            persons.Add(new Person
            {
                FirstName = "Yan",
                Age = 20 + i,
                LastName = "Zhiwei",
                Remark = DateTime.Now.ToString(CultureInfo.InvariantCulture)
            });
        jsonText = serializer.Serialize(persons);
        Console.WriteLine($"{serializer.GetType().Name}-Serialize" + jsonText);
     
        var getPersons = serializer.Deserialize<List<Person>>(jsonText);
        foreach (var item in getPersons)
            Console.WriteLine($"{serializer.GetType().Name}-Deserialize" + item);
     
        #endregion
    }
    

    7. EXCEL导入导出


    a. 基于Npoi实现,可以基于接口IExcelManger扩展实现诸如MyXls等;

    b. 目前实现了将Excel导出DataTable和DataTable导出到Excel文件;

    c. 后续完善诸如整个Excel文件导入导出等;

    代码使用说明:

    1. 将DataTable导出到Excel文件

      private void BtnToExcel_Click(object sender, EventArgs e)
      {
          var mockTable = BuilderExcelData();
          _mockExcelPath = $"D:\ExcelSample{DateTime.Now.FormatDate(12)}.xls";
          _excelManger.ToExcel(mockTable, "员工信息汇总", "员工列表", _mockExcelPath);
          Process.Start(_mockExcelPath);
      }
       
      private DataTable BuilderExcelData()
      {
          var mockTable = new DataTable();
          mockTable.Columns.Add(new DataColumn {ColumnName = "序号"});
          mockTable.Columns.Add(new DataColumn {ColumnName = "姓名"});
          mockTable.Columns.Add(new DataColumn {ColumnName = "工作单位"});
          mockTable.Columns.Add(new DataColumn {ColumnName = "性别"});
          mockTable.Columns.Add(new DataColumn {ColumnName = "入职时间"});
       
          for (var i = 0; i < 100; i++)
              mockTable.Rows.Add(i.ToString(), $"张{i}", $"李{i}计算机公司", i % 2 == 0 ? "男" : "女",
                  DateTime.Now.AddDays(i));
          return mockTable;
      }
      

    2. 将Excel文件导出DataTable

      private void BtnToDataTable_Click(object sender, EventArgs e)
      {
          if (string.IsNullOrEmpty(_mockExcelPath))
          {
              MessageBox.Show("请生成模拟测试EXCEL文件");
              return;
          }
       
          var excleTable = _excelManger.ToDataTable(_mockExcelPath, 0, 1, 2);
          var jsonText = _jsonSerializer.Serialize(excleTable);
          MessageBox.Show(jsonText);
      }
      

    8. 文件下载


    a.支持下载文件加密;

    b.支持下载自定义限速;

    c.通过DownloadHandler抽象类实现扩展诸如在Asp.Net Mvc实现;

    代码使用说明:

    1. 文件下载配置文件

      <?xml version="1.0" encoding="utf-16"?>
      <DownloadConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                      FileNameEncryptorIv="0102030405060708090a0a0c0d010208"
                      FileNameEncryptorKey="DotnetDownloadConfig"
                      LimitDownloadSpeedKb="1024"
                      DownLoadMainDirectory="D:OneDrive软件工具">
      </DownloadConfig>
      
    2. 在WebForm实现DownloadHandler抽象类,迅速实现文件下载

      public class FileDownloadHandler : DownloadHandler, IHttpHandler
      {
          public void ProcessRequest(HttpContext context)
          {
              var fileName = context.Request["fileName"];
              StartDownloading(context, fileName);
          }
       
          public bool IsReusable => false;
       
          public override void OnDownloadFailed(HttpContext context, string fileName, string filePath, string ex)
          {
              context.Response.Write(ex);
          }
       
          public override void OnDownloadSucceed(HttpContext context, string fileName, string filePath)
          {
              var result = $"文件[{fileName}]下载成功,映射路径:{filePath}";
              context.Response.Write(result);
          }
      }
      
    3. 修改Web.Config 文件

        <system.web>
          <compilation debug="true" targetFramework="4.5"/>
          <httpRuntime targetFramework="4.5"/>
          <httpHandlers>
            <add verb="*" path="FileDownloadHandler.ashx" type="MasterChief.DotNet.Framework.WbSample.BackHandler.FileDownloadHandler" />
          </httpHandlers>
        </system.web>
        <system.webServer>
          <modules runAllManagedModulesForAllRequests="true" />
        </system.webServer>
      
  • 相关阅读:
    window.open的火狐、谷歌兼容写法
    一个分数怎样约分?想知道的速度了。。。
    这是第二道题内容要求写一个银行的ATM系统 这个浪费了好长时间 ,遇到了许多问题,不过都解决了,上程序
    两个有理数相加(要求输入时以分数形式,输出时也以分数形式)
    linux centos 7.5下 源码编译安装 lua环境
    SecureCRT 6.7 vim高亮
    C#第一章笔记
    HTML5考试错题
    第九章博客
    第八章博客
  • 原文地址:https://www.cnblogs.com/MeetYan/p/10765721.html
Copyright © 2011-2022 走看看