[WCF-Discovery]服务如何能被”发现”

要让作为服务消费者的客户端能够动态地发现可用的服务,首先的要求服务本身具有可被发现的特性。那么到底一个可被发现的服务和一个一般的服务有何不同呢?或者说如何让一个一般的服务在寄宿的时候能够被它潜在的消费者“探测”到呢?

我们知道,WCF本质上就是消息交换的通信框架。不论是针对普通的服务操作的调用,还是定义在WS-Discovery中的服务的探测(Probe/PM)和解析(Resolve/RM),本质上都是一种消息的交换。它们并没有本质的不同,或者说唯一不同的就是消息的内容,前者是基于某个服务操作的请求和回复,而后者这是针对服务相关元信息的请求和回复。

从消息交换的角度讲,服务发现和元数据的获取比较类似,因为它们都交换的消息都关于服务本身的一些信息。在《如何将一个服务发布成WSDL》中,我们介绍了元数据的发布具有两种不同的方式:HTTP-GET和MEX终结点。服务发现机制对服务信息交换的实现与基于MEX终结点进行服务元数据交换的实现比较类似,因为它也需要一个特殊类型的终结点,即DiscoveryEndpoint。

一、DiscoveryEndpoint

在前面介绍“标准终结点”的时候,我们列出的一系列标准终结点列表中就有一个DiscoveryEndpoint。一个服务必须具有一个DiscoveryEndpoint才能成为一个可被发现的服务,而客户端也正是通过DiscoveryEndpoint来发现这相应的服务的。为了能够更加深刻地认识这个标准终结点,我们不妨先来看看它的定义。

   1: public class DiscoveryEndpoint : ServiceEndpoint
   2: {
   3:     //其他成员
   4:     public DiscoveryEndpoint();
   5:     public DiscoveryEndpoint(Binding binding, EndpointAddress endpointAddress);
   6:     public DiscoveryEndpoint(DiscoveryVersion discoveryVersion, ServiceDiscoveryMode discoveryMode);
   7:     public DiscoveryEndpoint(DiscoveryVersion discoveryVersion, ServiceDiscoveryMode discoveryMode, Binding binding, EndpointAddress endpointAddress);
   8:  
   9:     public ServiceDiscoveryMode DiscoveryMode { get; }
  10:     public DiscoveryVersion DiscoveryVersion { get; }
  11:     public TimeSpan MaxResponseDelay { get; set; }
  12: }

对于一个终结点来说,当然也包括标准终结点,其核心永远是地址、绑定和契约三要素。从上面的代码片断中我们不难发现,通过构造函数我们可以为DiscoveryEndpoint指定地址和绑定,却无从指定其契约。无需显式指定终结点契约是我们为何要定义这么一个标准终结点的根本目的,而终结点最终采用的契约取决于两个要素:其一、采用的WS-Discovery的版本;其二、选择的服务发现的模式(Ad-Hoc或者Managed)。

WS-Discovery版本通过类型DiscoveryVersion表示,下面的代码片断给出了DiscoveryVersion的定义。DiscoveryVersion具有三个静态的只读属性分别代表了三个主要的WS-Discovery版本。其中WSDiscoveryApril2005和WSDiscovery11代表两个正式的版本1.0和1.1,而WSDiscoveryCD1则代表在2009年1月份针对WS-Discovery
1.1的第一个委员会草案(CD:Committee Draft)

   1: public sealed class DiscoveryVersion
   2: {   
   3:     //其他成员    
   4:     public string Name { get; }
   5:     public string Namespace {get; }
   6:     public Uri AdhocAddress { get; }
   7:     public MessageVersion MessageVersion { get; }
   8:  
   9:     public static DiscoveryVersion WSDiscovery11 { get; }
  10:     public static DiscoveryVersion WSDiscoveryApril2005 { get; }
  11:     public static DiscoveryVersion WSDiscoveryCD1 { get; }
  12: }

DiscoveryVersion具有四个只读属性,Name表示相应版本的名称。对于表示上述三个版本的DiscoveryVersion对象,该属性的值分别为WSDiscoveryApril2005、WSDiscovery11和WSDiscoveryCD1(与上述的三个静态只读属性的名称一致)。而Namespace和AdhocAddress则表示具体版本的WS-Discovery中采用的命名空间和在Ad-Hoc模式下各种广播消息中使用的目标地址(即基于WS-Addressing的<To>报头携带的地址)。MessageVersion表示选择的消息版本(SOAP版本加上WS-Addressing的版本)。默认情况下,DiscoveryEndpoint的DiscoveryVersion属性为WSDiscovery11。

而我们之前介绍的两种典型的服务发现模式(《[WCF-Discovery] WCF-Discovery的协议基础:WS-Discovery》),即Ad-Hoc和Managed则定义在枚举ServiceDiscoveryMode中,该枚举定义如下。在默认情况下,DiscoveryEndpoint的DiscoveryMode属性值为Managed。

   1: public enum ServiceDiscoveryMode
   2: {
   3:     Adhoc,
   4:     Managed
   5: }

我们说DiscoveryEndpoint采用的契约由WS-Discovery的版本和服务发现模式决定,那么对于这两个要素的不同组合,最终被选用的终结点契约类型是什么呢?为此,我编写了如下一段测试程序:基于不同的DiscoveryVersion和ServiceDiscoveryMode创建DiscoveryEndpoint对象,最终打印出终结点契约类型的名称。

   1: DiscoveryEndpoint endpoint1;
   2: DiscoveryEndpoint endpoint2;
   3: Console.WriteLine("{0,-25}{1,-35}{2, -30}", "", "Ad-Hoc", "Managed");
   4:  
   5: endpoint1 = new DiscoveryEndpoint(DiscoveryVersion.WSDiscoveryApril2005, ServiceDiscoveryMode.Adhoc);
   6: endpoint2 = new DiscoveryEndpoint(DiscoveryVersion.WSDiscoveryApril2005, ServiceDiscoveryMode.Managed);
   7: Console.WriteLine("{0,-25}{1,-35}{2, -30}", "WSDiscoveryApril2005", endpoint1.Contract.ContractType.Name, endpoint2.Contract.ContractType.Name);
   8:  
   9: endpoint1 = new DiscoveryEndpoint(DiscoveryVersion.WSDiscovery11, ServiceDiscoveryMode.Adhoc);
  10: endpoint2 = new DiscoveryEndpoint(DiscoveryVersion.WSDiscovery11, ServiceDiscoveryMode.Managed);
  11: Console.WriteLine("{0,-25}{1,-35}{2, -30}", "WSDiscovery11", endpoint1.Contract.ContractType.Name, endpoint2.Contract.ContractType.Name);
  12:  
  13: endpoint1 = new DiscoveryEndpoint(DiscoveryVersion.WSDiscoveryCD1, ServiceDiscoveryMode.Adhoc);
  14: endpoint2 = new DiscoveryEndpoint(DiscoveryVersion.WSDiscoveryCD1, ServiceDiscoveryMode.Managed);
  15: Console.WriteLine("{0,-25}{1,-35}{2, -30}", "WSDiscoveryCD1", endpoint1.Contract.ContractType.Name, endpoint2.Contract.ContractType.Name);

我们将输出的结果通过如下面的表格来表示。从中我们不难发现,针对不同的WS-Discovery版本和服务发现模式组合,最终选择的服务契约类型都是不同的。服务契约类型的名称的命名规则为IDiscoveryContract{Adhoc/Managed}{Discovery Version}。

  Ad-Hoc Managed
WSDiscoveryApril2005 IDiscoveryContractAdhocApril2005 IDiscoveryContractManagedApril2005
WSDiscovery11 IDiscoveryContractAdhoc11 IDiscoveryContractManaged11
WSDiscoveryCD1 IDiscoveryContractAdhocCD1 IDiscoveryContractManagedCD1

上述的6个契约类型对应着6个接口。不过,这些都是内部接口,并不对外公布,不过我们可以通过Reflector察看它们的定义。现在我们就来简单看看针对WS-Discovery

1.1下分别针对Ad-Hoc和Managed模式的服务契约接口IDiscoveryContractAdhoc11和IDiscoveryContractManaged11的定义。

IDiscoveryContractAdhoc11:

   1: [ServiceContract(Name = "TargetService", Namespace = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01", CallbackContract = typeof(IDiscoveryResponseContract11))]
   2: internal interface IDiscoveryContractAdhoc11
   3: {    
   4:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Probe", IsOneWay = true, AsyncPattern = true)]
   5:     IAsyncResult BeginProbeOperation(ProbeMessage11 request, AsyncCallback callback, object state);
   6:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Resolve", IsOneWay = true, AsyncPattern = true)]
   7:     IAsyncResult BeginResolveOperation(ResolveMessage11 request, AsyncCallback callback, object state);
   8:     void EndProbeOperation(IAsyncResult result);
   9:     void EndResolveOperation(IAsyncResult result);
  10:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Probe", IsOneWay = true)]
  11:     void ProbeOperation(ProbeMessage11 request);
  12:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Resolve", IsOneWay = true)]
  13:     void ResolveOperation(ResolveMessage11 request);
  14: }

IDiscoveryContractManaged11:

   1: [ServiceContract(Name = "DiscoveryProxy", Namespace = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01")]
   2: internal interface IDiscoveryContractManaged11
   3: {
   4:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Probe", ReplyAction = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches", AsyncPattern = true)]
   5:     IAsyncResult BeginProbeOperation(ProbeMessage11 request, AsyncCallback callback, object state);
   6:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Resolve", ReplyAction = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ResolveMatches", AsyncPattern = true)]
   7:     IAsyncResult BeginResolveOperation(ResolveMessage11 request, AsyncCallback callback, object state);
   8:     ProbeMatchesMessage11 EndProbeOperation(IAsyncResult result);
   9:     ResolveMatchesMessage11 EndResolveOperation(IAsyncResult result);
  10:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Probe", ReplyAction = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches")]
  11:     ProbeMatchesMessage11 ProbeOperation(ProbeMessage11 request);
  12:     [OperationContract(Action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/Resolve", ReplyAction = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ResolveMatches")]
  13:     ResolveMatchesMessage11 ResolveOperation(ResolveMessage11 request);
  14: }

我们说服务契约本质上定义了采用的消息交换模式和被交换的消息的格式。对于客户端驱动的恶服务发现来说,采用的服务交换不外乎两种类型:服务探测(Probe/PM)和服务解析(Resolve/RM),这在前面针对WS-Discovery的部分有过详细的介绍。所以,服务契约IDiscoveryContractAdhoc11和IDiscoveryContractManaged11实际定义了两组代表着这两种消息交换类型的操作ProbeOperation和ResolveOperation,一组是同步操作,另一组是异步操作。至于契约的名称、命名空间,以及操作的Action,ReplyAction在通过相应的ServiceContractAttribute和OperationContractAttribute特性进行相应的定义,以确保和WS-Discovery
1.1规范保持一致。

除了DiscoveryMode和DiscoveryVersion这两个只读属性,DiscoveryEndpoint还具有一个可读可写的属性MaxResponseDelay,表示服务相应Probe请求的PM消息延迟发送允许的时间范围。在此MaxResponseDelay属性规定的时间范围内,服务的用于响应单个Probe请求的所有PM都将发送出去。如果同时发送所有的PM,则可能发生网络风暴(Network

Storming)。为了防止发生这种情况,响应服务在每个PM发送之间具有一个随机延迟。随机延迟的范围是从0到MaxResponseDelay。如果MaxResponseDelay设置为

0(默认值),则在不使用任何延迟的紧凑循环中发送PM消息。否则,在发送PM消息时将应用随机延迟,以便发送所有PM消息所用的总时间不会超过MaxResponseDelay。

如果你采用编程的方式使用DiscoveryEndpoint,你可以通过在构造函数中传入相应的参数决定采用的WS-Discovery版本和服务发现模式,并通过属性赋值的方式决定MaxResponseDelay的值。如果采用配置的方式,这个标准终结点对应的配置元素也同样提供相应的配置属性。

   1: <standardEndpoints>
   2:    <udpDiscoveryEndpoint>
   3:       <standardEndpoint name="adhocDiscoveryEndpointConfiguration" discoveryVersion="WSDiscovery11" maxResponseDelay="00:00:00.600" />  
   4:    </udpDiscoveryEndpoint>
   5: </standardEndpoints>

二、UdpDiscoveryEndpoint

由于DiscoveryEndpoint需要显式地指定其地址,所以它只能以单播的方式进行消息交换。由于WS-Discovery中的Ad-Hoc模式采用广播形式的消息交换,为此WCF为我们创建另一个标准的终结点UdpDiscoveryEndpoint。如下面的代码片断所示,UdpDiscoveryEndpoint具有两个基本的属性MulticastAddress和TransportSettings。前者代表采用的广播地址,默认值为“soap.udp://239.255.255.250:3702”,该值也是代表默认IPV4广播地址的静态只读属性DefaultIPv4MulticastAddress的值。而另一个代表IPV6默认广播地址的只读属性DefaultIPv4MulticastAddress的值为“soap.udp://[FF02::C]:3702”。后者代表针对UDP传输层的相关设置。

   1: public class UdpDiscoveryEndpoint : DiscoveryEndpoint
   2: {
   3:     //其他成员
   4:     public static readonly Uri DefaultIPv4MulticastAddress;
   5:     public static readonly Uri DefaultIPv6MulticastAddress;
   6:  
   7:     public Uri MulticastAddress { get; set; }
   8:     public UdpTransportSettings TransportSettings { get; }
   9: }

而针对UDP传输层的设置又具有若干选项,这可以从UdpTransportSettings的属性成员的定义就可以看出来。

   1: public class UdpTransportSettings
   2: {
   3:     public int DuplicateMessageHistoryLength { get; set; }
   4:     public long MaxBufferPoolSize { get; set; }
   5:     public int MaxMulticastRetransmitCount { get; set; }
   6:     public int MaxPendingMessageCount { get; set; }
   7:     public long MaxReceivedMessageSize { get; set; }
   8:     public int MaxUnicastRetransmitCount { get; set; }
   9:     public string MulticastInterfaceId { get; set; }
  10:     public int SocketReceiveBufferSize { get; set; }
  11:     public int TimeToLive { get; set; }
  12: }

下面的列表列出了针对UdpTransportSettings每个属性所代表的含义:

  • DuplicateMessageHistoryLength:传输用于标识重复消息的最大消息哈希数,默认值为 4112;
  • MaxBufferPoolSize:传输使用的任何缓冲池的最大大小,默认值为524288;
  • MaxMulticastRetransmitCount:应重新传输多播消息的最大次数(第一次发送除外),默认值为2;
  • MaxPendingMessageCount:已经接收但尚未从每个通道实例的输入队列中移除的消息的最大数量,默认值为32;
  • MaxReceivedMessageSize:绑定可处理的消息的最大大小,默认值为65507;
  • MaxUnicastRetransmitCount:应重新传输单播消息的最大次数(第一次发送除外),默认值为1;
  • MulticastInterfaceId:该值唯一地标识在发送和接收多播消息时所使用的网络适配器,默认值为null;
  • SocketReceiveBufferSize:基础 WinSock 套接字上的接收缓冲区的大小,默认值为55536;
  • TimeToLive:多播数据包可以遍历的网络段跃点数,默认值为1。

标准终结点UdpDiscoveryEndpoint对应的配置元素同样定义了相应的配置属性是你能过对它采用的广播地址以及UDP传输层进行自由的配置。下面给出了一个配置实例。

   1: <udpDiscoveryEndpoint>
   2:   <standardEndpoint name="adhocDiscoveryEndpointConfiguration" discoveryVersion="WSDiscovery11">
   3:     <transportSettings duplicateMessageHistoryLength="2048"
   4:                        maxPendingMessageCount="5"
   5:                        maxReceivedMessageSize="8192"
   6:                        maxBufferPoolSize="262144"/>
   7:   </standardEndpoint>
   8: </udpDiscoveryEndpoint>

三、ServiceDiscoveryBehavior

我们之前就已经说,客户端用于获取可用服务发起的请求,和基于普通服务调用的消息请求并没有本质的不同。匹配的服务在接收到客户端发送的Probe/Resolve请求后,会将自己的信息包含在PM/RM消息中进行回复。现在我们讨论是一个核心的问题:消息的内容如何产生?

对于普通的服务调用,回复消息的内容最初来源于针对服务实例的操作方法的调用的结果。针对服务发现的Probe/Resolve请求也是一样,服务端依然存在一个用于返回目标服务信息的“发现服务”,并且这个服务的实现了添加到目标服务的DiscoveryEndpoint的契约接口。这个服务的类型就是抽象类DiscoveryService的子类。DiscoveryService的定于如下,可见它实现了DiscoveryEndpoint基于不同WS-Discovery版本在Ad-Hoc和Managed模式下的6个契约接口。

   1: public abstract class DiscoveryService : 
   2:     IDiscoveryContractAdhocApril2005, 
   3:     IDiscoveryContractManagedApril2005, 
   4:     IDiscoveryContractAdhoc11, 
   5:     IDiscoveryContractManaged11, 
   6:     IDiscoveryContractAdhocCD1, 
   7:     IDiscoveryContractManagedCD1, ...
   8: {
   9:     //省略成员
  10: }

知道真正用于实现服务发现的服务,我们需要考虑另一个问题:这个继承自DiscoveryService的发现服务在接收到服务发现请求后被激活的。当用于寄宿服务的ServiceHost对象被开启之后,服务的每个终结点都会转换成一个EndpointDispatcher对象,这当然也包括上述的DiscoveryEndpoint。激活的服务实例被封装在一个InstanceContext对象中,而服务对象和用于封装服务对象的InstanceContext分别通过针对EndpointDispatcher对DispatchRuntime的两个特殊的组件来提供,即InstanceProvider和InstanceContextProvider。如果我们能够自定义用于激活发现服务的InstanceProvider和InstanceContextProvider,并且通过扩展将其应用到针对DiscoveryEndpoint的DispatchRuntime上,就能够彻底解决发现服务的激活问题。右图大体上揭示了整个发现服务的激活机制。

在WCF的具体实现中,这个自定义的InstanceProvider和InstanceContextProvider是一个内部的类型ServiceDiscoveryInstanceContextProvider(它同时实现了IInstanceProvider和IInstanceContextProvider两个接口)。而最终将它应用到DiscoveryEndpoint对应的EndpointDispatcher的则是通过一个服务行为来实现的,这个服务行为的类型是System.ServiceModel.Discovery.ServiceDiscoveryBehavior。所以,一个服务能够成为一个可被发现的服务除了具有一个DiscoveryEndpoint之外,还必须应用这个ServiceDiscoveryBehavior服务行为。

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接

时间: 2024-08-08 00:18:31

[WCF-Discovery]服务如何能被”发现”的相关文章

RIA服务-使用WCF RIA服务的企业模式

PDC09 和 Mix10 上宣布了两条重大消息,分别是推出 Silverlight 4 Beta 和 RC.读到本文时,发布到网上的 Silverlight 4 完全版本已经可供下载.除广泛的打印支持外,它还支持权限升级.网络摄像头.麦克风.toast.剪贴板访问,等等.凭借其全新的功能集,Silverlight 4 作为一种多平台的丰富 UI 框架,可以从容应对与 Adobe AIR 之间的正面交锋. 尽管我对这一切确实感到兴奋,但我的主要角色是一名业务应用程序开发人员,我所关注的一点是如何

wcf-想问一下WCF添加服务的问题

问题描述 想问一下WCF添加服务的问题 找了几篇教程学习WCF, 刚才写了几个例子,有个疑问. 我是这样写的,加一个WCF库,然后用代码的方式发布到服务端,再在客户端进行服务引用. 写了几个例子,在添加服务引用的时候,有的是启动服务端后,在客户端引用服务输入URI,有的直接发现本解决方案的服务,不明白两者之间的区别, 看msdn上面之说两种方法都行... 刚才我想手动添加地址,先启动了WCF库,复制了地址,然后再客户端添加,为什么服务端没有启动也能找到服务呢? >_ < ? 解决方案 wcf需

WCF角色服务简介

WCF角色服务能够从可以发送和使用SOAP消息的任何应用程序访问某个用户的角色.这可以包括不使用.NET Framework的应用程序.因此,这些不同应用程序的用户可以在每个应用程序中具有相同的角色.通常情况下,可以检查用户的角色来确定用户具有执行哪些操作的权限. 角色服务仅提供可通过ASP.NET角色管理获得的功能的一个子集.可以通过角色服务检索用户的角色或检查用户是否属于特定的角色.用户必须经过身份验证才能读取用户的角色.角色服务可使用任何类型的ASP.NET身份验证. System.Web

OData 和 AtomPub: 使用WCF数据服务绑定 AtomPub 服务器

如果您不熟悉开放数据协议 (OData),我要告诉您它很美妙.OData(在 odata.org 上有详细介绍)以下列各种基于 HTTP 的功能优势 为基础:用于发布数据的 Atom:用于创建.更新和删除数据的 AtomPub:以及用于定义数据类型的 Microsoft 实体数据模型 (EDM). 如果您拥有 JavaScript 客户端,则可以采用 JSON 格式(而不是 Atom 格式)直接返回数据:如果您拥有其他客户端(包括 Excel. .Microsoft NET Framework.

Visual Studio-Visual Studio 2010中的实体框架4.0和WCF数据服务4.0

在诸多新改进之中,Visual Studio 2010 引入了用户期待已久的实体框架 4.0 和 WCF 数据服务 4.0(以前称为 ADO.NET 数据服务),这两项功能综合起来,简化了您建立数据模型.使用数据和生成数据的方式. 实体框架 4.0 (EF 4.0) 致力于启用和简化两种主要方案:以域为中心的应用程序开发和传统以数据为中心的"基于数据的窗体设计".它引入了诸如模型优先开发等功能(该功能允许您创建模型并为您生成自定义 T-SQL):对持久化透明的支持:外键:延迟加载以及实

WCF 配置服务 演示

1.搭建IIS(具体步骤略)2.服务契约如下: namespace JianKunKing.NewVersion.Service { // 注意: 使用"重构"菜单上的"重命名"命令,可以同时更改代码.svc 和配置文件中的类名"NewVersionService". //[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.

一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)

JSONP(JSON with Padding)可以看成是JSON的一种"使用模式",用以解决"跨域访问"的问题,这篇简单的文章给出一个简单的例子用于模拟如何通过jQuery以JSONP的访问调用一个WCF REST服务.[源代码从这里下载] 在这个例子中,我们将定义一个用于返回所有员工信息的服务,下面是用于表示员工信息的Employee的类型和契约接口.契约接口IEmployees的GetAll操作用以返回所有员工列表,我们指定了Uri模板并将回复消息格式设置为J

wcf-初次接触WCF 哪位大神帮帮忙,C#的 WCF启动服务报错怎么改

问题描述 初次接触WCF 哪位大神帮帮忙,C#的 WCF启动服务报错怎么改 请尝试将 HTTP 端口更改为 8733 或以管理员身份运行. System.ServiceModel.AddressAccessDeniedException: HTTP 无法注册 URL http://+:8733/WcfServiceLibraryForfamily/Service1/.进程不具有此命名空间的访问权限(有关详细信息,请参见 http://go.microsoft.com/fwlink/?LinkId

求助 需要写一个WCF的服务接口用来访问数据库,报文用XML的结果,哪位能给个例程或者提供个思路呢,不甚感激,我原来的应该程序时用delphi写的。

问题描述 求助需要写一个WCF的服务接口用来访问数据库,报文用XML的结果,哪位能给个例程或者提供个思路呢,不甚感激,我原来的应该程序时用delphi写的,现在需要写一个接口给第三方查询数据库用,请各位大虾帮帮忙 解决方案 解决方案二:在线等待中,谢谢各位解决方案三:请问你做什么系统的?我做税控需要这东东,正想研究wcf呢!