WCF 项目应用连载[2] - 创建Lig日志系统
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日志系统的更多相关文章
- WCF 项目应用连载[3] - 双向通信 实例管理与服务端监控
WCF 项目应用连载[1] - 索引 - 轻量级的Log系统 - Lig Sample -序 第二节我们已经创建了Lig项目,并且能稳定工作了.现在我们来改进ILigAgent接口,实现WCF的双向通 ...
- WCF 项目应用连载[8] - 绑定、服务、行为 大数据传输与限流 - 下 (ServiceThrottlingAttribute)
因为ORM的原因,对Attribute编程有一种情节..所以这节的出现,完全是因为在WCF对自定义Attribute的一种应用. WCF 项目应用连载[7] - 绑定.服务.行为 大数据传输与限流 - ...
- cocos creator主程入门教程(五)—— 日志系统
五邑隐侠,本名关健昌,10年游戏生涯,现隐居五邑.本系列文章以TypeScript为介绍语言. 这一篇介绍日志系统的设计.一般我们开发一个demo,只会简单的用cocos提供的cc.log打印下日志, ...
- asp.net Web项目中使用Log4Net进行错误日志记录
使用log4net可以很方便地为应用添加日志功能.应用Log4net,开发者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能.同时,通过外部配置文件,用户可以不用重新编译程序就能 ...
- Springboot项目使用aop切面保存详细日志到ELK日志平台
上一篇讲过了将Springboot项目中logback日志插入到ELK日志平台,它只是个示例.这一篇来看一下实际使用中,我们应该怎样通过aop切面,拦截所有请求日志插入到ELK日志系统.同时,由于往往 ...
- 项目01-flume、kafka与hdfs日志流转
项目01-flume.kafka与hdfs日志流转 1.启动kafka集群 $>xkafka.sh start 3.创建kafka主题 kafka-topics.sh --zookeeper s ...
- 基于sentry的前端错误监控日志系统(部署sentry服务器/前端项目部署)-让前端最快的定位到生产问题
背景 在这越来越发达的网络时代,web应用也是越来越复杂,尤其是前端的开发,也是越来越受重视. 所以在我们前端开发完成后,会有一些列的web应用的上线验证,如自测.QA测试.code review 等 ...
- 03篇ELK日志系统——升级版集群之ELK日志系统整合springboot项目
[ 前言:整个ELK日志系统已经搭建好了,接下来的流程就是: springboot项目中的logback日志配置通过tcp传输,把springboot项目中所有日志数据传到————>logsta ...
- Go项目实战:打造高并发日志采集系统(一)
项目结构 本系列文章意在记录如何搭建一个高可用的日志采集系统,实际项目中会有多个日志文件分布在服务器各个文件夹,这些日志记录了不同的功能.随着业务的增多,日志文件也再增多,企业中常常需要实现一个独立的 ...
随机推荐
- 让QMainWindow也表现出QDialog的exec函数的特征
前几天在做毕业设计项目的时候,使用的PyQt4,想实现这么样一个功能: 场景描述:主窗口a(QMainWindow类型)和主窗口b(QMainWindow),b是通过a窗口中某一个按钮弹出来的. 功能 ...
- js上传图片并预览
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- 制作font-icon有感
连日来有些空闲,趁着这闲余时间,我尝试亲自制作一些Font-Icon,让以后可以运用到工作中.但是基于本人水平有限,PS操作只能以非常基础来形容,而AI呢,根本就只会放大操作.在这过程真的非常感谢设计 ...
- JNI-Test
//testdll.h/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header fo ...
- LeetCode(2) || Add Two Numbers && Longest Substring Without Repeating Characters
LeetCode(2) || Add Two Numbers && Longest Substring Without Repeating Characters 题记 刷LeetCod ...
- C#隐私信息(银行账户,身份证号码,名字)中间部分特殊字符替换(*)
最近做到一个关于银行的一个功能模块,需要将隐私信息银行账号中间部分用*代替,于是写下了,如下代码: /// <summary> /// 将传入的字符串中间部分字符替换成特殊字符 /// & ...
- 浅谈C# .Net技术面试 , 正在找工作的人一定要看看
1.引子 最近一直在负责.net(B/S方向)技术面试相关的工作,前前后后面试了不少人,但是通过率较低,大概只有20%左右:有颇多感慨. 最近也一直比较困惑,原因究竟是什么? 是我们要求太高,应聘者本 ...
- 【HTTP】Speed and Mobility: An Approach for HTTP 2.0 to Make Mobile Apps and the Web Faster
This week begins face to face meetings at the IETF on how to approach HTTP 2.0 and improve the Inter ...
- validationEngine[转]
随笔- 31 文章- 0 评论- 40 validationEngine中文版 — jquery强大的表单验证插件 中文汉化版,官方只有英文的.同时根据中国国情修改了部分验证规则. 这个插件 ...
- Energy Minimization
zoj2539:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2539 题意:公式第一项只要当xi=0时才会有作用,第二项只 ...