WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序

现在我们创建一个Lig工程 - Litelog

2.1 创建Lig服务

_________________________________________________________________________________

不好意思。我尽最大的程度说明清楚问题。
Lig这些内容是写

How to use the WCF rather than to explain what the WCF is.

所以以跳跃性比较大,如果有些WCF基础最好。如果想知道Details,建议看Artech的《WCF全面解析》或search他的cnblog,这是最好的解决问题之道。

不过有一点你会高兴,这儿会提供这些文章与源代码工程.

OpenSource codes provided with you here .Thanks

2.1 .1Lig工程创建 - Litelog

如图 2.1 .1所示
创建一个名为Litelog的空solution,同时添加如下四个新建项目:

1)LigServer:  WCF服务端程序。控制台程序。Console Application
2)ILigAgent:  WCF服务接口(服务契约)。库类代码。ClassLibrary
3)LigAgent:  WCF服务实现,继承ILigAgent,借宿于LigServer进程。库类代码。ClassLibrary
4)LigClient:  WCF客户端测试用例。控制台程序。Console Application

WCF创建遵循SOA标准中要求对契约编程,而不是实现。

WCF通过接口定义服务契约,通过数据契约定义接口出现的参数,通常数据契约(非简单变量)出现的参数会在Server-Client之间共享。

因为WCF是基于特性的编程,如果你了解对象关系模型(ORM) ,就知道.net中所有继承于Attribute类的类是如何影响方法运行的。

图 2.1.1 Lig工程结构

所以,首先,我们看WCF服务接口内部是什么样子的。

2.1.2 创建WCF服务接口 – ILigAgent

在ILigAgent项目中添加两个文件夹:DataMembers与Interfaces,分别用来存放数据契约与服务契约。目前只含LigLevel.cs与ILigAgent.cs两个项目文件。

LigLevel : 枚举变量。Lig日志级别。

    public enum LigLevel
{
Info = 0,
Debug = 1,
Warn = 2,
Error = 3,
Fatal = 4
}

图2.1.2  ILigAgent 服务契约结构

ILigAgent : 服务契约。一共含 8 个操作接口。

注意:

1) LigFatal有一个重载方法,这儿显式应用OperationContract特性中的Name属性加以区分。

否则,WCF服务接口中使用默认OperationContract特性是不允许重载方法出现的。在用SvcUtil.exe生成LigAgent代理类时时你会看到

void LigFatal(string message, Exception ex)

变成

void LigFatalex(string message, Exception ex)

了。讲LigServer生存代理类与客户端配置时后面会提到

2) Initialize用于初始化Lig路径。

SayHelloToServer则用于客户端创建通道(ChannelFactory)成功后测试Server是否在线,在创建LigClient时会解释SayHelloToServer存在的意义。

    [ServiceContract]
public interface ILigAgent
{
[OperationContract]
void LigMessage(string message, LigLevel level);
[OperationContract]
void LigInfo(string message);
[OperationContract]
void LigDebug(string message);
[OperationContract]
void LigWarn(string message);
[OperationContract]
void LigError(string message);
[OperationContract(Name = "LigFatal")]
void LigFatal(string message);
[OperationContract(Name = "LigFatalex")]
void LigFatal(string message, Exception ex);
[OperationContract]
void SayHelloToServer(string message);
[OperationContract]
void Initialize(string ligPath);
}

2.1.3 创建WCF服务

LogAgent

如图2.1.3所示。创建WCF服务实现,实现ILigAgent服务接口。LigAgent将会用于借宿于LigServer进程。

关于服务行为特性说明(ServiceBehavior):

实例模式:PerSession。这儿采用一个代理,一个实例。

并发模式:Multiple。多线程。

这两个参数与WCF并发与实例管理相关。这儿的配置是因Lig的客户可能需要写不同的文件,同时要考虑多个Lig客户端存在会有异步调用的需求,以加快日志书写时间,提高LigServer的性能。从客户端需求与性能上考虑采用一个代理,一个实例,并发模式采用多线程。

图 2.1.3 创建WCF服务实现

2.1.4 LigCore - EmitFileMessage

对于OOP,其中有一条“依赖倒置”原则
其实,对C#本身面言,编程中,我们抽象出的更多的是interface而不是abstract类。

我们个人喜欢用interface而不是单单的abstract类去实践“依赖倒置”原则。但有时还是有例外的,比如累量级的ORM PetaPoco对不同的数据库对象Privider,interface在.net中已经存在,所以我们会写abstract类为所有不同Privider的基类。说多了。

1)为了减小LigAgent的本身代码负担,我们创建另外一个类,LigCore,专门负责文件书写工作,并用Mutex保证线程操作安全,所有日志操作由EmitFileMessage完成。

2)同时提供一个EmitFileMessage的非静态重载版本。

(此处文件操作用简单的StreamWriter实现。Log4net采用FileStream + TextWriter实现,同时采用Mutex保证文件操作线程安全)

图2.1.4 LigCore文件操作

public void LigMessage(string message, LigLevel level)
{
string formatMsg = LigCore.LiggedTime + level.ToString() + " " + message;
new LigCore().EmitFileMessage(formatMsg, this.LigPath, true);
}

EmitFileMessage的非静态重载版本

        public void EmitFileMessage(string message, string fullpath, bool isAppending)
{
StreamWriter writer = null;
try
{
writer = new StreamWriter(fullpath, isAppending);
writer.Write(message);
writer.Flush();
}
catch (Exception ex)
{
// ignore
}
finally
{
if (writer != null)
{
writer.Close();
}
writer = null;
}
}

2.2 创建LigServer

_________________________________________________________________________________

2.2.1 关于Lambda表达式

先暂时不用去理解这儿出现的Lambda表达式:

(sender,e)=>{}

不过有必要说下,Lambda表达式,linq与扩展方法在.net3.0引入的新特性会大在简化你的编程时间。

如果应用Sql,Linq是最佳的方式。

你懂得Lambda表达式在创建临时方法的好处,linq查询对泛型委托的极致应用带来的对for/foreach/while的简化操作,扩展方法对现有类功能扩展的方便之处。如果你构建超时方法,事件处理等通用类,对Lambda表达式,linq查询与扩展方法会变成最常用的操作。

2.2.2 SvcUtil工具生成客户端代理类与客户端配置

1)启动LigServer,打开控制台,进入SvcUtil.exe所在的目录,输入:

SvcUtil.exe http://127.0.0.1:7023/Lig.vivitue.LigMetadata

2)

回车。如果你对SvcUtil的使用没有问题,你会看到生成的LigAgent.cs文件与output.config配置。把output.config改成App.config后就可以加入到客户端LigClient中使用了。

3) 
同时在浏览器中输入http://127.0.0.1:7023/Lig.vivitue.LigMetadata你就能看到LigServer发布的元数据了。

4)打开Output.config与LigAgent代理类。

不清楚svcutil的,baidu或google下。太多文章讲svcutil如何使用

用过svcutil的人都看过这种东西,看着LigAgent与output.config是不是有些乱?很多人看过这种文件。

我要说的是,对IIS借宿的基于Web访问的WCF服务,这是一种很好的方式,但对window form程序,这并不好,不利于代码后期维护。下面这两个文件在我们的客户端中都不会出现。

我们将采用一种新的方式来编写我们客户端的配置与用接口取代代理类。

图 2.2.1 LigServer

图 2.2.2 SvcUtil工具生成客户端代理类与配置

图 2.2.3 生成的 Output.config与LigAgent代理类

2.2.3 服务端配置文件- App.config

服务端用的配置


创建的WCF项目默认采用App.config或Web.config(IIS服务用)作为服务端与客户端的配置文件。该文件编译后会与*.exe文件放在一起。变成*.exe.config,在WCF配置启动时ServiceHost内部会自动加载。如果想改变配置文件路径与名称,则你得重写ServiceHost类与ChannelFactory<T>类了,后面讲《自定义配置》会解释。

关于WCF配置中WCF服务的行为 behavior

WCF中,定义behavior用于设置服务运行时的特性,此处,我们通过指定ServiceMetadataBehavior使WCF服务对外公布Metadata,这样我们可以通过http形式访问。
同时用SvcUtil.exe工具生存代理类与代理类的配置文件output.config (客户端使用的)。

1)在WCF中,behavior被定义为Attribute
2)ServiceBehavior与OperationBehavior是最常用的behavior (在前面的接口中你看到的WCF服务接口的特性性应用)

3)一个WCF服务可以有多种行为

4)但在配置中,一个WCF服务地址默认情况下只能指定一个行为(behaviorConfiguration),如果想一个WCF服务地址指定多种行为,此时你得扩展ServiceHost类了。
通过ServiceHost中的Description.Behaviors属笥添加多种行为。后面扩展ServiceHost类时会提到ServiceHost中的Description属性。

图 2.2.3 客户端配置

2.3 创建LigClient的代码
_________________________________________________________________________________

2.3.1 在客户端应用ILigAgent – 接口编程

WCF依赖统一的服务接口在客户端与服务端进行通信,我们完全可以用ILigAgent来取代用SvcUtil工具自动生成的代理类LigAgent。

了解这点后,我们可以在LigClient添加ILigAgent接口,而不是应用自动生成了LigAgent代理类,那样代码太乱了,同时不太符合OOP中“依赖倒置”原则采用基于抽象编程的概念。这儿LigClient用接口,而不是实现类LigAgent。

2.3.2 创建 LigManager

我们创建两个方法。ConnectServer与DisconnectServer用来连接LigServer服务与断开LigServer服务。

采用ChannelFactory<T>来创建客户端通道同时获取客户端代理实例。看到红色的代码:

this.iLig.SayHelloToServer("LigManager Connecting : ClientHash : " + this.GetHashCode().ToString());

如果LigServer没有启动,ConnectServer会阻塞到这行代码,直到时间达到配置中的超时,会引发一个超时异常。

在WCF中。ChannelFactory<T>创建通道与服务端存在与否无关,也就是说,如果LigServer没有启动,ChannelFactory<T>创建通道也会成功,所以我们不能用创建通道成功与否来表明WCF连接是否已经成功建立,我们必须通过Client调用Server的服务来确保WCF已经连接。

WCF服务只有在客户端第一次调用服务的时候才会创建实例为客户端服务。我们为了确保LigServer已经启动,所以加入了SayHelloToServer代码去调用服务,如果调用成功,LigClient与LigServer才算正式建立成功。

然后加入配置,编写如下客户端代码就可以工作了

图 2.3.1 LigManager

2.3.3 创建Client

1) 我们采用LigManager中的静态资源来获取ILigAgent实例写日志。这样Client代码就变得很简单了。

2) 你可能注意到了,在这里我们并没有用ILigAgent的Initialize接口初始化Lig文件路径,而是用了系统默认路径。因为我要让不同的客户端去写同一个文件,而不是不同文件。
3) 以后的章节中我们会对ILigAgent进行改进,ILigAgent接口暴露的东西还是太多了,把WCF特性暴露了。

4) 同时使用ILigAgent也太过于复杂,因为使用LigClient我们自己还得创建一个LigManager,简简单单的写个日志,这样做使LigServer客户端的使用有些麻烦。别担心,在后面的章节中,你会看到,我们会解决这儿的所有问题,我们会让LigManager不复存在。

5) 写日志我们只需要这样 

ILigger lig= new Ligger(“ligfile”);
lig.Info(“YourInfo here”);


图 2.3.2 LigClient

图 2.3.3 LigClient 客户端配置

2.4 Lig系统测试

_________________________________________________________________________________

启动LigServer,同时启动4个LigClient,4个Client同时向默认文件Lig.lg中写入日志。。。

图 2.4.1 Lig系统测试

Lig系统已经工作

好了。到现在为止,这个经量级的Log已经完成。并且能够很好的稳定工作。

但到现在为止,它还不够优秀,表现在:

1) 我们还没有考虑,这个LigServer到底可以同时连接多少个LigClient。

2) 同样还有没考虑,如果LigClient如果出现异常怎么办。

3)  也没有解释LigServer控制台中出现的HashCode是什么东东

4)  LigServer与LigClient双向通信会是什么样子?服务端监控是什么样子?

在第三节中我们会解答这些所有的问题。。。

本节的源代码下载:

_________________________________________________________________________________

Litelog - WCF 项目应用连载[2] - 创建Lig日志系统 C# 源代码.rar

_________________________________________________________________________________

WCF 项目应用连载[3] - 双向通信 并发、实例管理与服务端监控

MB CSDN审核资源真TM慢。

参考引文:
[1] Artech.WCF全面解析[M].2012
[2] O'Reilly.WCF编程[M].2009
[3] Adnrew Trolesen.C#与.net3.5/4高级程序设计[M].2009/2013

WCF 项目应用连载[2] - 创建Lig日志系统的更多相关文章

  1. WCF 项目应用连载[3] - 双向通信 实例管理与服务端监控

    WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序 第二节我们已经创建了Lig项目,并且能稳定工作了.现在我们来改进ILigAgent接口,实现WCF的双向通 ...

  2. WCF 项目应用连载[8] - 绑定、服务、行为 大数据传输与限流 - 下 (ServiceThrottlingAttribute)

    因为ORM的原因,对Attribute编程有一种情节..所以这节的出现,完全是因为在WCF对自定义Attribute的一种应用. WCF 项目应用连载[7] - 绑定.服务.行为 大数据传输与限流 - ...

  3. cocos creator主程入门教程(五)—— 日志系统

    五邑隐侠,本名关健昌,10年游戏生涯,现隐居五邑.本系列文章以TypeScript为介绍语言. 这一篇介绍日志系统的设计.一般我们开发一个demo,只会简单的用cocos提供的cc.log打印下日志, ...

  4. asp.net Web项目中使用Log4Net进行错误日志记录

      使用log4net可以很方便地为应用添加日志功能.应用Log4net,开发者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能.同时,通过外部配置文件,用户可以不用重新编译程序就能 ...

  5. Springboot项目使用aop切面保存详细日志到ELK日志平台

    上一篇讲过了将Springboot项目中logback日志插入到ELK日志平台,它只是个示例.这一篇来看一下实际使用中,我们应该怎样通过aop切面,拦截所有请求日志插入到ELK日志系统.同时,由于往往 ...

  6. 项目01-flume、kafka与hdfs日志流转

    项目01-flume.kafka与hdfs日志流转 1.启动kafka集群 $>xkafka.sh start 3.创建kafka主题 kafka-topics.sh --zookeeper s ...

  7. 基于sentry的前端错误监控日志系统(部署sentry服务器/前端项目部署)-让前端最快的定位到生产问题

    背景 在这越来越发达的网络时代,web应用也是越来越复杂,尤其是前端的开发,也是越来越受重视. 所以在我们前端开发完成后,会有一些列的web应用的上线验证,如自测.QA测试.code review 等 ...

  8. 03篇ELK日志系统——升级版集群之ELK日志系统整合springboot项目

    [ 前言:整个ELK日志系统已经搭建好了,接下来的流程就是: springboot项目中的logback日志配置通过tcp传输,把springboot项目中所有日志数据传到————>logsta ...

  9. Go项目实战:打造高并发日志采集系统(一)

    项目结构 本系列文章意在记录如何搭建一个高可用的日志采集系统,实际项目中会有多个日志文件分布在服务器各个文件夹,这些日志记录了不同的功能.随着业务的增多,日志文件也再增多,企业中常常需要实现一个独立的 ...

随机推荐

  1. gettid()和pthread_self()的区别

    Linux中,每个线程有一个tid,类型long,由sys_gettid()取得. Linux内核中并没有实现线程,而是由glibc线程库实现的POSIX线程.每个线程也有一个id,类型 pthrea ...

  2. jquery学习之旅

    在jQuery中,css()方法的功能是设置或获取元素的某项样式属性. $<"div">.css("font-weight","bold& ...

  3. transcode_step()在转码过程中对pts、dts、duration的处理

    对pts.dts.duration的处理主要集中在两大函数里面 1.process_input()读入数据并处理,放到滤镜里面 2.reap_filters()从滤镜读出数据,处理后写入文件 proc ...

  4. compser 执行命令提示do not run composer as root/super !

    这个是因为composer为了防止非法脚本在root下执行,解决办法随便切换到非root用户即可

  5. PYTHON开发--面向对象基础入门

    面向对象 一:面向对象初级 1.思考:首先在python中,以前我们以前用到的几乎都是函数式编程,但是有时候函数式编程其中代码重复利用率太高,我们往往会把这些重复代码写进一个函数日后去调用,所以呢,今 ...

  6. MongoDB 模糊查询,及性能测试

    var mongodb = new MongoClient("mongodb://127.0.0.1:27017");//MongoServer.Create();//创建链接 v ...

  7. 【技术贴】解决xp下Microsoft.SqlServer.Management.PSProvider.dll

    解决 安装SQLserver2008时有出错信息,提示:Configuration error description: 无法获得 C:\Program Files\Microsoft SQL Ser ...

  8. 如何通过js使搜索关键词高亮

    给你推荐通过jquery来实现高亮关键词.jquery.textSearch-1.0.js代码: (function($){ $.fn.textSearch =function(str,options ...

  9. LeetCode 面试:Add Binary

    1 题目 Given two binary strings, return their sum (also a binary string). For example,a = "11&quo ...

  10. innodb_buffer_pool_instances and innodb_buffer_pool_size的关系

    把buffer pool 分成一个用户指定的单独的区域, 每个有它自己的LRU list和相关的数据结构, 降低竞争在并发内存读取和写操作. 这个选项只有当innodb_buffer_pool_siz ...