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

目录

  • 1. 数据库访问
  • 2. 日志
  • 3. 缓存
  • 4. 配置
  • 5. 验证码
  • 6. 序列化与反序列化
  • 7. excel导入导出
  • 8. 文件下载

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下,如图:

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

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>