简易项目搭建(用于一般杂七杂八的小功能点)

在工作过程中,我们总会碰到很多小型的功能点需要完成,以LZ自己的工作情况来举例,其中最频繁的是俩点
1、控制台项目
2、web界面(纯前台)

控制台项目

我们首先来谈控制台项目的工作内容,在没有使用postMan地址详见之前,工作中使用大量的接口调用,在项目准备阶段,首先要对接口的使用进行一个描述,在使用WebService和Wcf为主的服务接口为主的公司,使用Vs直接 <新建控制吧><添加服务引用>一套可视化的操作即可按接口通过代理类的方法进行引用,实在是c#开发的乐趣所在。
废话不多说,现在主要说说工作中常用的功能点
1、测试服务接口
2、编写windows服务

服务接口

控制台项目完成此功能很简单,本文章主要突出的是一些常用的方法。
在编写类项目的过程中,主要会用到三个类库
1.Newtonsoftjson(json序列化)
2.log4net(日志记录)
3.NUint(单元测试)

业务上无非就是调用接口测试,如果成功Pass,如果失败记录日志。
单元测试的目的主要是为了,批量使用接口,测试接口的并发和其他操作所用

Windows服务

windows服务的使用场景在我的工作中主要结合任务调度来来做,同时配合一些其他的技术,像是队列,缓存等
例子:
1、每隔10秒同步一次A数据库数据(SqlServer)至B数据库(Oracle),表名称,字段名称均不一样
2、每天凌晨2点跑一项或多项任务,成功失败均记录日志+推送管理员(手机短信、邮件、内部服务平台)

大体上都是结合任务调度来做的,进行任务调试的库一般选用的是Quartz.Net,console服务转Windows服务用的是topshelf,日志使用Log4net
通过这三个组件就能够满足我的一般需求,其他的功能点按要求要引用不同的类库。

简单项目搭建

项目搭建1.0

新建一个console 项目,运行环境选择.Net Framework 4.5

新建解决方案

建立三个类库
Common 基础层
Models 实体层
ScheduleTasks 任务具体任务

结构图.png

首先引用Nuget包,不同的层引用不同的Nuget,再次简单说明
Common 基础层

log4net、quartz.net

Models 实体层

Sqlsugar

Schedules

待定

进行不同的模块封装

log4net 的引用和封装

log4Net不需要做太多的封装,提供一个初始化,一个日志接口获取方法即可

    public class LogFactory
    {
        static LogFactory()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + @"/log4net.config";
            FileInfo configFile=new FileInfo(path);
            log4net.Config.XmlConfigurator.Configure();
        }

        public static ILog GetLogger(string name)
        {
            return LogManager.GetLogger(name);
        }

        public static ILog GetLogger(Type type)
        {
            return LogManager.GetLogger(type);
        }
    }

最简单的config日志配置

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <log4net>
    <!-- 控制台前台显示日志 -->
    <appender name="Console" type="log4net.Appender.ColoredConsoleAppender">
      <mapping>
        <level value="DEBUG" />
        <foreColor value="White" />
      </mapping>
      <mapping>
        <level value="INFO" />
        <foreColor value="Blue" />
      </mapping>
      <mapping>
        <level value="WARN" />
        <foreColor value="Yellow" />
      </mapping>
      <mapping>
        <level value="ERROR" />
        <foreColor value="Red, HighIntensity" />
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="时间:%date 级别:%-5level 日志记录器:%logger%n内容:%message%n%n" />
      </layout>
      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="Debug" />
        <param name="LevelMax" value="Fatal" />
      </filter>
    </appender>

    <appender name="LogByDate" type="log4net.Appender.RollingFileAppender">
      <!--日志路径-->
      <param name= "File" value= "Log//"/>
      <!--记录日志写入文件时,不锁定文本文件,防止多线程时不能写Log,官方说线程非安全-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!--是否是向文件中追加日志-->
      <param name= "AppendToFile" value= "true"/>
      <!--最多产生的日志文件数,超过则只保留最新的n个。设定值value="-1"为不限文件数-->
      <param name= "MaxSizeRollBackups" value= "-1"/>
      <param name="MaximumFileSize" value="10MB" />
      <!--日志文件名是否是固定不变的-->
      <param name= "StaticLogFileName" value= "false"/>
      <!--固定后缀-->
      <PreserveLogFileNameExtension value="true" />
      <param name="DatePattern" value="yyyyMMdd&quot;.log&quot;" />
      <!--按照何种方式产生多个日志文件(日期[Date],文件大小[Size],混合[Composite])-->
      <param name= "RollingStyle" value= "Composite"/>
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%n时间:%d [%t] %n级别:%-5p %n位置:[%thread] (%file:%line) %n消息描述:%message%n异常:%exception%n%n " />
      </layout>
    </appender>

    <!--root节点的作用是所有其它logger都默认继承它。-->
    <root>
      <!--配置日志的级别,低于此级别的就不写到日志里面去-->
      <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
      <level value="ALL" />
      <!--启用日志输入到控制台-->
      <appender-ref ref="Console"/>
      <appender-ref ref="LogByDate"/>
    </root>
  </log4net>
</configuration>

至此log4net的工作完成

Newtonsoftjson

image.png

版本随便你自己使用

在程序的编码过程中经常会用到json的序列化和么序列化
编写一个简单的help class

    /// <summary>
    /// Json帮助类
    /// </summary>
    public class JsonHelper
    {
        /// <summary>
        /// 将对象序列化为JSON格式
        /// </summary>
        /// <param name="o">对象</param>
        /// <returns>json字符串</returns>
        public static string SerializeObject(object o)
        {
            string json = JsonConvert.SerializeObject(o);
            return json;
        }

        /// <summary>
        /// 解析JSON字符串生成对象实体
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="json">json字符串(eg.{"ID":"112","Name":"石子儿"})</param>
        /// <returns>对象实体</returns>
        public static T DeserializeJsonToObject<T>(string json) where T : class
        {
            JsonSerializer serializer = new JsonSerializer();
            StringReader sr = new StringReader(json);
            object o = serializer.Deserialize(new JsonTextReader(sr), typeof(T));
            T t = o as T;
            return t;
        }

        /// <summary>
        /// 解析JSON数组生成对象实体集合
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="json">json数组字符串(eg.[{"ID":"112","Name":"石子儿"}])</param>
        /// <returns>对象实体集合</returns>
        public static List<T> DeserializeJsonToList<T>(string json) where T : class
        {
            JsonSerializer serializer = new JsonSerializer();
            StringReader sr = new StringReader(json);
            object o = serializer.Deserialize(new JsonTextReader(sr), typeof(List<T>));
            List<T> list = o as List<T>;
            return list;
        }

        /// <summary>
        /// 反序列化JSON到给定的匿名对象.
        /// </summary>
        /// <typeparam name="T">匿名对象类型</typeparam>
        /// <param name="json">json字符串</param>
        /// <param name="anonymousTypeObject">匿名对象</param>
        /// <returns>匿名对象</returns>
        public static T DeserializeAnonymousType<T>(string json, T anonymousTypeObject)
        {
            T t = JsonConvert.DeserializeAnonymousType(json, anonymousTypeObject);
            return t;
        }
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容