温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
目前在北京搭配家工作,负责家装软件的研发工作
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
舍弃第三方的原因,主要还是因为性能伤不起。于是考虑SOCKET等,但是一则,mono的异步问题我没搞定,二则,我可不想花费大量的时间去进行协议的编解码。而且C#在协议的解析方面简直弱到爆,一个简单的TLV都让人难受,远没有C的那种灵活性。 于是眼光继续投向MS的remoting技术。代理对象真心用着爽。& 测试效果: &&
这篇文章在写得时候参考了/henan_lujun/blog/static/,后来我也将这片博客转到我的空间中了。这篇文章讲解得相对入木三分。你照着文章应该可以写出你自己的。
总而言之,注意点就以下几点: 1、由于消息交互,也就是事件绑定,在事件绑定之前,则远程对象必须是已经存在的。所以,不能使用RemotingConfiguration.RegisterWellKnownServiceType方法,因为这个需要客户端调用才能生成实例。于是我们使用RemotingServices.Marshal方法,保证在客户端调用之前服务器端已经生成实例 2、客户端需要侦听服务端事件,实际上也就是服务器端事件在+=操作时,需要加载他右端delegate的信息,但这个肯定是不现实的,右端的delegate可是客户端的,服务端怎么能加载客户端的代码。于是,我上面转债的那篇文章中提到了弄个包裹类,单独写一个类,客户端注册事件的时候是用这个类去注册,再通过这个类转给本地其他对象。这样服务器事件+=操作的时候就调用这个包裹类的信息,而这个包裹类本来就位于COMMON库中,故而也就解决了这个问题。当然,我是喜欢偷懒的,于是,我就没写这个包裹类,而是直接在客户端再实例化一个远程对象,当然这里应该叫本地对象,然后用这个本地对象去侦听服务端的事件,侦听到之后再转发给本地其他对象。 实现的关键代码:
/// &summary&
/// 进程间远程对象
/// &/summary&
public class IPCRemoteObject : MarshalByRefObject
#region 消息寄存器
private const int LOCK_WAIT_TIME = 500;
private Dictionary&CLIENT_TYPE, MessageHandle& m_messageDescriperMap = new Dictionary&CLIENT_TYPE, MessageHandle&();
private ReaderWriterLock m_messageDescriperMapLock = new ReaderWriterLock();
#region 消息事件
/// &summary&
/// 消息事件
/// &/summary&
public event MessageHandle MessageHandeE
/// &summary&
/// 消息触发器
/// &/summary&
public void MessageHandeEventWrapper(MessageArgs p_args)
if (MessageHandeEvent != null)
Delegate[] broadcaseEvents = MessageHandeEvent.GetInvocationList();
foreach (var item in broadcaseEvents)
((MessageHandle)item)(p_args);
MessageHandeEvent -= ((MessageHandle)item);//客户下线,取消其订阅
#endregion
#region 消息订阅 取消
/// &summary&
/// 订阅指定客户端消息
/// &/summary&
/// ¶m name="p_clientType"&&/param&
/// ¶m name="p_msgHandle"&&/param&
public void SubscribeMessageHandle(CLIENT_TYPE p_clientType, IPCRemoteObject p_loaclObject)
m_messageDescriperMapLock.AcquireWriterLock(LOCK_WAIT_TIME);
if (m_messageDescriperMap.ContainsKey(p_clientType))
LogWrapper.Logger.Warn(string.Format("重复订阅客户端【{0}】消息", p_clientType));
m_messageDescriperMap.Add(p_clientType, p_loaclObject.MessageHandeEventWrapper);
LogWrapper.Logger.Warn(string.Format("订阅客户端【{0}】消息", p_clientType));
m_messageDescriperMapLock.ReleaseWriterLock();
catch (Exception ex)
LogWrapper.Logger.Warn(string.Format("订阅客户端【{0}】失败,未知异常", p_clientType), ex);
/// &summary&
/// 取消指定客户端消息订阅
/// &/summary&
/// ¶m name="p_clientType"&&/param&
/// ¶m name="p_msgHandle"&&/param&
public void DescriberMessageHandle(CLIENT_TYPE p_clientType)
m_messageDescriperMapLock.AcquireWriterLock(LOCK_WAIT_TIME);
m_messageDescriperMap.Remove(p_clientType);
m_messageDescriperMapLock.ReleaseWriterLock();
LogWrapper.Logger.Warn(string.Format("取消订阅客户端【{0}】消息", p_clientType));
catch (Exception ex)
LogWrapper.Logger.Warn(string.Format("订阅客户端【{0}】消息失败,未知异常", p_clientType), ex);
#endregion
#region 消息发布
/// &summary&
/// 发送消息到指定类型客户端
/// &/summary&
/// ¶m name="p_toClient"&目标客户端类型&/param&
/// ¶m name="p_args"&消息&/param&
public void SendMessage(CLIENT_TYPE p_toClient, MessageArgs p_args)
ThreadPool.QueueUserWorkItem(new WaitCallback(o =&
m_messageDescriperMapLock.AcquireReaderLock(LOCK_WAIT_TIME);
if (m_messageDescriperMap.ContainsKey(p_toClient))
Delegate[] broadcaseEvents = m_messageDescriperMap[p_toClient].GetInvocationList();
foreach (var itemDelegate in broadcaseEvents)
((MessageHandle)itemDelegate)(p_args);
catch (Exception ex)
LogWrapper.Logger.Warn(string.Format("客户端【{0}】消息调用异常,未知异常", p_toClient), ex);
m_messageDescriperMapLock.ReleaseReaderLock();
catch (Exception ex)
LogWrapper.Logger.Warn(string.Format("客户端【{0}】消息调用异常,未知异常", p_toClient), ex);
#endregion
#region 重写
/// &summary&
/// 租用期限无限
/// &/summary&
/// &returns&&/returns&
public override object InitializeLifetimeService()
#endregion
} 这里我玩了个小聪明,就是服务器端的不是事件,而是一个数据字典,这样可以有一对客户端的存在,而且任意两个客户端之间通信,只要适当扩展CLIENT_TYPE的枚举值即可。 服务器实例化代码:
/// &summary&
/// 消息代理端口
/// &/summary&
private static int g_messageProxyServerPort = 9900;
/// &summary&
/// 消息代理IP地址
/// &/summary&
private static string m_messageProxyServerIP = @"127.0.0.1";
/// &summary&
/// 消息代理Windows管道名称
/// &/summary&
private const string g_messageProxyServerName = @"ShineView.Proxey.IPC.UWMessageProxy.Server";
/// &summary&
/// 消息代理对象URL
/// &/summary&
private static string g_messageProxyURL = @"tcp://127.0.0.1:9900/ShineView.Proxey.IPC.MessageProxy";
/// &summary&
/// 消息代理名称
/// &/summary&
private const string g_messageProxyURLName = @"ShineView.Proxey.IPC.MessageProxy";
/// &summary&
/// 初始化进程间消息代理
/// &/summary&
public static void InitializeIPCMessageProxy()
g_messageProxyURL = string.Format(@"tcp://{0}:{1}/ShineView.Proxey.IPC.MessageProxy", m_messageProxyServerIP, g_messageProxyServerPort);
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.F
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["name"] = g_messageProxyServerN
props["port"] = g_messageProxyServerP
props["bindTo"] = m_messageProxyServerIP;
TcpChannel channel = new TcpChannel(props, clientProvider, serverProvider);
ChannelServices.RegisterChannel(channel, false);
IPCRemoteObject remoteObject = new IPCRemoteObject();
RemotingServices.Marshal(remoteObject, g_messageProxyURLName);
/// &summary&
/// 释放进程间消息代理
/// &/summary&
public static void DisposeIPCMessageProxy()
IChannel[] regChannels = ChannelServices.RegisteredC
foreach (IChannel item in regChannels)
if (item.ChannelName == g_messageProxyServerName)
TcpChannel channel = item as TcpC
channel.StopListening(null);
ChannelServices.UnregisterChannel(channel);
} 客户端的实例化代码:
/// &summary&
/// 远程物体包裹
/// &/summary&
private static IPCRemoteObject g_remoteObjectWindowsProxyW
/// &summary&
/// 消息代理Windows管道名称
/// &/summary&
private const string g_messageProxyWindowsName = @"ShineView.Proxey.IPCMessage.UWMessageProxy.Windows";
/// &summary&
/// 初始化windows消息代理
/// &/summary&
/// ¶m name="p_windowsMessageProc"&unity消息处理函数&/param&
/// &returns&&/returns&
public static IPCRemoteObject InitializeWindowsMessageProxy(MessageHandle p_windowsMessageProc)
g_messageProxyURL = string.Format(@"tcp://{0}:{1}/ShineView.Proxey.IPC.MessageProxy", m_messageProxyServerIP, g_messageProxyServerPort);
g_remoteObjectWindowsProxyWrapper = new IPCRemoteObject();
g_remoteObjectWindowsProxyWrapper.MessageHandeEvent += p_windowsMessageP
BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.F
IDictionary props = new Hashtable();
props["port"] = 0;
props["name"] = g_messageProxyWindowsN
props["bindTo"] = m_messageProxyServerIP;
TcpChannel channel = new TcpChannel(props, new BinaryClientFormatterSinkProvider(), serverProvider);
ChannelServices.RegisterChannel(channel, false);
IPCRemoteObject remoteObject = Activator.GetObject(typeof(IPCRemoteObject), g_messageProxyURL) as IPCRemoteO
remoteObject.SubscribeMessageHandle(CLIENT_TYPE.WINDOWS, g_remoteObjectWindowsProxyWrapper);
return remoteO
/// &summary&
/// 释放windows消息代理
/// &/summary&
public static void DisposeWindowsMessageProxy()
IChannel[] regChannels = ChannelServices.RegisteredC
foreach (IChannel item in regChannels)
if (item.ChannelName == g_messageProxyWindowsName)
TcpChannel channel = item as TcpC
channel.StopListening(null);
ChannelServices.UnregisterChannel(channel);
到这里一切工作结束
阅读(316)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'unity3d 与C# 通信',
blogAbstract:'\t本文的题目,相信很多人都有过该类需求,最终解决方案也各式各样,从外设数据交互(硬盘、数据库、文件等等)到消息队列SOCKET、PIPE等等各种。\t但外设数据交互,方法好是好,可以说,从健壮性来说,简直强到爆,两边完全解耦(可见有第三方事情就是好办),但从性能来说,弱到爆。最简单的一次数据交互,IO次数就让人感觉不爽,毕竟啥都要从第三方经过,而且,依赖第三方就意味着,程序的稳定性相对受到限制,不过,相对,我们不要整天担心数据库的不稳定,硬盘的损坏等等,因为在这些可能的概率面前,我们程序自己崩溃的概率就是天文数字。除非,我们有能力做出7*24的产品再来纠结第三方带来的稳定性问题。',
blogTag:'unity3d,c#,ipc',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:1,
publishTime:6,
permalink:'blog/static/',
commentCount:2,
mainCommentCount:1,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'目前在北京搭配家工作,负责家装软件的研发工作',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}李林峰的园子
&&&&&&&&&&&
WCF能够建立一个跨平台的安全、可信赖、事务性的解决方案,是一个WebService,.Net Remoting,Enterprise Service,WSE,MSMQ的并集,有一副很经典的对比图如下:
WCF与其他分布式技术对比表
二、WCF中的 "A","B","C" 介绍
我们先看个生活中的例子,某一天,公司的领导让你去送一份合同文件,送文件的过程你可以选择的交通方式为&打车&、&公交&、&地铁&,当然费用是根据***来报销的,到了对方公司后你要找到某经理,并且要一份收到合同文件的回执和相关文件。
要完成这项工作任务我们执行以下几个主要的步骤:
(1)我们首先要知道对方公司的地址,引出WCF中的"A"。
A(Address):英文理解为"地址",在计算机中是通过一个URI唯一地址标识,通过这个地址我们可以找到我们要调用的WCF服务。
A解决了:Where to locate the WCF Service?
(2)我们还要选择我们的交通方式,每种交通方式达到的结果不一样。如:打车费用较贵、但是过程舒服些,时间上视道路情况而定。公交最便宜,并且可选择多条线路。地铁最方便,但是偶尔会很挤,一般都没座等等,引出WCF中的"B"。
B(Binding):英文理解为"捆绑,绑定",&Binding实现在Client和Service通信的所有底层细节。如:我们在客户端与服务端传输的时候采用的是什么样的编码,XML?Text?二进制?...采用哪种传输协议进行传输,TCP?Http?以及采用什么样的机制解决安全问题,SSL?加密?...
B解决了:How to communicate with service?
(3)到了对方公司之后我们能做哪些事?I.送合同,II.拿回执。我们不能要求对方公司给我们其他的东西,引出WCF中的"C"。
C(Contract):英文理解为"合同",合同是什么?告诉我们哪些事能做,如些事不能做。&Contract的主要的作用是暴露某个WCF Service所提供的所有有效的方法。Contract实际上是把每个方法的转化成为相对应的消息。
C解决了:What functionalities do the Service provide?
三、Endpoint(终结点)
WCF实现了网络系统的各个应用程序的通信。各个应用程序的通信是以&终结点(Endpoint)&的来实现的。我们在上面讲的实际例子中的A、B、C即是Endpoint 的组成部分,他是服务器间通信调用的入口。
四、应用程序间通信
我们在第二和第三项中讲了A、B、C与Endpoint,现在正式进入应用程序间的通信。我们还是以刚才送合同的过程为例:
员工A手里有一张便签,标记着:地址、绑定、合同.....而合作方手里也有一张便签,标记着同样的内容,并且一直得在等待员工A的出现。只有当便签上的内容一样时,合作方A才会签署合同回执。
当我们寄宿WCF服务的时候,我们必须定义一个或是多个终结点,然后Serivce端通过***这些终结点来处理Client发来的请求。由于应用程序之间是靠Endpoint来通信,那么我们在Client端也必须定义终结点,只有当Client与Service的终结点完全匹配的时候才能进行通信。
如上图所示:只有EndpointA中的A、B、C与EndPointB中的A、B、C完全匹配时才能通信。EndPointE与EndpointD也是一样的。
在上一节的教程中我们使用了IIS做为宿主,客户端调用WCF服务的是Web应用程序。今天这个小节主要以介绍WCF中传输的配置为主,我们把上一节的内容稍做改动,以体现出"Endpoint"与"A、B、C"。
由于我在教程一里没有手写任何配置的代码,Client与Service端的Web.config都是自动生成的,当我们添加服务引用时,IDE自动将客户端的配置文件中Endpoint与引用的服务的Endpoint匹配了。如下代码所示:
客户端Web.config:
1 &?xml version="1.0" encoding="utf-8"?&
有关如何配置 ASP.NET 应用程序的详细消息,请访问
http:///fwlink/?LinkId=169433
8 &configuration&
&system.web&
&compilation debug="true" targetFramework="4.0" /&
&/system.web&
&system.serviceModel&
&bindings&
&basicHttpBinding&
&binding name="BasicHttpBinding_IUser" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true"&
&readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" /&
&security mode="None"&
&transport clientCredentialType="None" proxyCredentialType="None"
realm="" /&
&message clientCredentialType="UserName" algorithmSuite="Default" /&
&/security&
&/binding&
&/basicHttpBinding&
&/bindings&
&endpoint address="http://localhost/User.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IUser" contract="WCFService.IUser"
name="BasicHttpBinding_IUser" /&
&/system.serviceModel&
38 &/configuration&
&服务端Web.config代码:
1 &?xml version="1.0" encoding="utf-8"?&
2 &configuration&
&system.web&
&compilation debug="true" targetFramework="4.0" /&
&/system.web&
&system.serviceModel&
&behaviors&
&serviceBehaviors&
&behavior&
&!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 --&
&serviceMetadata httpGetEnabled="true"/&
&!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 --&
&serviceDebug includeExceptionDetailInFaults="false"/&
&/behavior&
&/serviceBehaviors&
&/behaviors&
&serviceHostingEnvironment multipleSiteBindingsEnabled="true" /&
&/system.serviceModel&
&system.webServer&
&modules runAllManagedModulesForAllRequests="true"/&
&/system.webServer&
24 &/configuration&
由上面的两个配置文件我们发现,客户端system.serviceMode节点有我们刚才讲的endpoint,而服务端为什么没有?这不是和我们刚才讲的有违背吗?好吧,我们承认IDE生成的Web.config中endpoint很隐晦。那么我们看下面手工修改后[把对看起来很复杂并且对当前的学习无用的配置节删掉]的配置文件的代码(我将服务端和客户端放在一块了):
1 &!--Service Web.config--&
2 &?xml version="1.0" encoding="utf-8"?&
3 &configuration&
&system.web&
&compilation debug="true" targetFramework="4.0" /&
&/system.web&
&system.serviceModel&
&services&
&service name="WCFService"&
&endpoint address="http://localhost/User.svc" binding="basicHttpBinding"
contract="WCFService.IUser" /&
&/service&
&/services&
&/system.serviceModel&
15 &/configuration&
17 &!--Client Web.config--&
18 &?xml version="1.0" encoding="utf-8"?&
19 &configuration&
&system.web&
&compilation debug="true" targetFramework="4.0" /&
&/system.web&
&system.serviceModel&
&endpoint address="http://localhost/User.svc" binding="basicHttpBinding"
contract="WCFService.IUser" /&
&/system.serviceModel&
29 &/configuration&
& 修改配置文件后我们执行下,发现WCF服务依然执行成功!!这次的配置文件够明显了吧,不论是在服务端还是在客户端,endpoint中的A、B、C都是完全一样的。也就是终结点完全匹配!
那么第一次的配置文件为什么能执行呢?***是我们把WCF寄宿在IIS上,而IIS默认***的就是Http协议[B确定了]并且地址也是相对于IIS上的文件地址[A确定了],合同更不用说了,找到User.svc什么都有了[C确定了],所以在服务端就没有必要显示的写出system.serviceModel,不信你试试,把服务端的配置文件中system.serviceModel节删除,程序一样可以运行!服务器端的endpoint确定了,客户端的endpoint自然要和服务端去对应,所以IDE在生成客户端的配置文件里endpoint写的很详细的,而服务端却没有endpoint。
这节教程主要描述了应用程序间的通信过程,Endpoint和ABC非常重要,也比较好理解,所以建议尽量的熟练。
转载请注明出处:
阅读(...) 评论()NetTcpBinding&binding&=&new&NetTcpBinding();binding.Security.Mode&=&SecurityMode.M
&app.config
&bindings&&&&netTcpBinding&&&&&&binding&name&=&"NewBinding0"&&&&&&&&security&mode&=&"Message"&/&&&&&&/binding&&&&/netTcpBinding&&/bindings&
2,选择客户端凭据类型,凭据是WCF用于创建已声明的标识或功能的数据。客户端必须提供该凭据才能与您的服务进行通信。此属性解决的问题是怎样进行安全认证。
传输凭据类型下表列出了在传输安全模式下可以由绑定使用的客户端凭据的可能类型。创建服务时,将 ClientCredentialType 属性设置为这些值之一以指定凭据类型,客户端必须提供该凭据才能与您的服务进行通信。可以在代码或配置文件中设置这些类型。
•None 指定客户端不需要提供任何凭据。这相当于匿名客户端。 •Basic 为客户端指定基本身份验证。 •Digest 为客户端指定摘要式身份验证。 •Ntlm 指定 NT LAN Manager (NTLM) 身份验证。在由于某种原因无法使用 Kerberos 身份验证时使用。还可以通过将 AllowNtlm 属性设置为 false 来禁止将 NTLM 用作回退身份验证,这将使 WCF 在使用 NTLM 时尽可能引发异常。请注意,将此属性设置为 false 可能不阻止通过网络发送 NTLM 凭据。 •Windows 指定 Windows 身份验证。若要在 Windows 域上仅指定 Kerberos 协议,则将 AllowNtlm 属性设置为 false(默认值为 true)。 •Certificate 使用 X.509 ***执行客户端身份验证。 •UserName 用户必须提供用户名和密码。使用 Windows 身份验证或其他自定义解决方案验证用户名/密码对。
消息客户端凭据类型下表列出了在创建使用消息安全的应用程序时可以使用的可能的凭据类型。可以在代码或配置文件中使用这些值。&•None 指定客户端不需要提供凭据。这相当于匿名客户端。 •Windows 允许在使用 Windows 凭据建立的安全上下文中交换 SOAP 消息。 •UserName 允许服务可以要求使用用户名凭据对客户端进行身份验证。请注意,WCF 不允许使用用户名进行任何加密操作,例如生成签名或加密数据。WCF 可确保在使用用户名凭据时传输会受到保护。 •Certificate 允许服务可以要求使用 X.509 ***对客户端进行身份验证。 •IssuedToken 根据安全策略配置的自定义令牌类型。默认令牌类型为安全断言标记语言 (SAML)。令牌由安全令牌服务颁发。有关更多信息,请参见 联合令牌与颁发的令牌.
我们可以通过编码或者配置文件的方式来指定 Binding 的安全方式。
下面配置结果是相同的,在级别使用***的方式认证
NetTcpBinding&binding&=&new&NetTcpBinding();binding.Security.Mode&=&SecurityMode.Mbinding.Security.Message.ClientCredentialType=&MessageCredentialType.Certificate
app.config&
&bindings&&&&netTcpBinding&&&&&&binding&name&=&"NewBinding0"&&&&&&&&security&mode&=&"Message"&&&&&&&&&message&clientCredentialType="Certificate"&/&&&&&&&&/security&&&&&&/binding&&&&/netTcpBinding&&/bindings&
3,设置服务凭据值&& 一旦选择了客户端凭据类型,就必须设置可供服务和客户端使用的实际凭据,用来暗示了服务凭据类型、选择的安全模式和客户端凭据类型 用来向服务器进行安全模式的***明 ,此属性解决的问题是使用那些数据进行认证。&& 如果“选择客户端凭据类型”为“Certificate” 那必须在这里关联一个***,并指定***的验证方式。&& 设置凭据值包含设置服务凭据值和设置客户端凭据值
&behaviors&&&&serviceBehaviors&&&&&&&behavior&name="NewBinding0_Behavior"&&&&&&&&&serviceCredentials&&&&&&&&&&!--指定一个&X.509&***,以供服务用来向使用&Message&安全模式的客户端证明自己的身份--&&&&&&&&&&serviceCertificate&findValue="CN=ejiyuan"&storeLocation="LocalMachine"&storeName="My"/&&&&&&/behavior&&&&/serviceBehaviors&&/behaviors&
综合上述几段代码,在消息级别进行加密,使用X.509 ***进行验证,***信息为findValue="CN=ejiyuan" storeLocation="LocalMachine" storeName="My"
&参考 :常用安全方案&