`

WS-Discovery for WCF

阅读更多

Introduction

Windows Communication Foundation represents the state of the art communication library in the .NET environment. The flexibility of this device is amazing, and it allows to easily remotize functions on specific services, automatically serializing all the parameters in the signature through the simple decoration of properties and objects.

WCF allows to interconnect with services through web services standard communications or custom communications by simply modifying the configuration file, supporting a huge number of transfer protocols (HTTP, net TCP, MSMQ, ...) and communication protocols (security, reliable message...).

Another major quality of the library is its extensibility: it is possible to create new protocols, behaviors that can be defined at a service level or at an endpoint level.

The implementation of a service or of a service consumer through WCF is based on three concepts that are resumed by ABC: the Address where the service answers, the Binding which is how the service answers, and the Contract which are the methods exposed by the service. This article aims to describe a component which extends WCF in terms of configuration to make a service to be discovered at runtime by a service consumer through the WS-Discovery specification.

Background

WS-Discovery is a specification in the stack of WS-* protocols within the metadata.

StackProtocolli.gif

The WS-Discovery specification foresees that a service is characterized not by its ABC parameters, but only by the Contract and the 'scopes' that are useful information to distinguish two services having the same interface. Each service implements a scheme of scopes called ScopeMatchBy, and eventually, the scopes in URI format (Uniform Resource Identifier). A service can change its metadata, or the scopes themselves, during its life, but it has to keep track of the version through an information called MetadataVersion.

At the opening, the service introduces itself to the network through a multicast Hello message containing the above information. Similarly, at closure, it sends a multicast Bye message to the network. If the metadata or the scopes change, the service must send just a Hello message with the new MetadataVersion number.

The client looks for a service through the type (that is the contract), eventually attaching the information about scope and ScopeMatchBy. The search can be carried out in two ways: without discovery proxy, and with discovery proxy.

Without discovery proxy, the client sends a multicast message called Probe containing the search parameters (contract type, ScopeMatchBy, and scopes).

Probe-ProbeMatch.Png

The figure above shows the multicast communication in red and the unicast communication in blue.

Every service thinking of satisfying the request answers through a unicast ProbeMatch message. If ProbeMatch information is sufficient, the client can connect to the service, asking the service metadata to collect information about the binding first. Otherwise, the client must send a new multicast message called 'Resolve', and the service must answer with a unicast ResolveMatch message, giving necessarily the missing information.

If the discovery proxy is present in the network, the communication takes place with the same messages (Probe, ProbeMatch...), but modes change from multicast to unicast towards the discovery proxy.

To remind myself how communications take place, I introduce an analogy belonging to an environment other than the IT one. I think about several students in their classroom, every time a new student arrives, he enters the room greeting aloud and saying his name (Hello multicast). Suddenly, a student needs Robert, but he doesn’t’ know him. So, he calls Robert aloud in the silent room (Probe multicast). As a consequence, all the people called Robert stand up and go towards the person who called them (ProbeMatch unicast). Well, the discovery proxy represents the teacher in the room: when someone calls Robert aloud, besides all the people called Robert, the teacher stands up, too. He goes to the student and he introduces himself, 'I’m the teacher, and the next time you need someone, come and ask me for (Hello unicast). After that, the student stands up and asks the teacher when he needs someone (Probe unicast).

In this implementation, I won’t consider the version with the discovery proxy, but as soon as I have time, I will extend my code to include the discovery proxy as well, maybe integrating the IStorageAdapter of Roman Kiss’ WS-Transfer.

Using the code

The WS-Discovery implementation for WCF can be divided into two parts (into three parts if the discovery proxy implementation is included): a part concerning the service and the other concerning the client.

The integration of the discovery approach from the client side point of view extending the WCF configuration is problematic because WCF standard proxy works by specifying the Address Binding and Contract, while the discovery proxy needs only the Contract; other information are just discovered at runtime.

Moreover, I didn’t consider the client-side configuration aspect so important. The scopes are optional: if they aren’t specified, all services implementing the contract will satisfy the scopes request, unless particular service configurations are present.

The implementation of a discovery proxy doesn’t need to inherit from a class as per a WCF proxy, but it is enough to declare a DiscoveryClient< TChannel> class. In fact, the Channel property allows to interact with the methods of the remote service.

Collapse
DiscoveryClient<IServiceSample> proxy = new
 DiscoveryClient<IServiceSample>();

The constructor foresees to be able to eventually receive the scopes required for the service, and so it begins the search for the required service by sending a Probe message to the network. It is important to have an instance of the proxy as soon as possible so that at the first call of a proxy method, the service to be connected to has already been found avoiding useless waits.

ProbeDiscoveryClient.GIF

When the ProbeMatch message arrives, the client can release the WaitHandle , invoke the remote call, and return the result. If the client receives more than one ProbeMatch, the first one unlocks the semaphore, and at the moment of the call invocation, the best service is found through the virtual method GetBestMemento() . It is probable that at the first call, the first service who sent the ProbeMatch is used, unless a sufficient time went by between instantiation and method invocation to receive all ProbeMatch before the method invocation. Once the client uses a channel, it continues to use it all its life long. By re-creating the client, all the early stored ClientMemento remain, and so GetBestMemento will be able to find the best candidate in a more careful way.

As already said, GetBestMemento is a virtual function, that means that it is possible to inherit the DiscoveryClient< IServiceSample> class and to execute the overridden method to run the custom selection logic.

ClientMemento is the class that represents the basic information to interconnect to the service. Through the data received by the probe, it is possible to instantiate the memento that takes care of getting other possible information, as for instance the binding, through the metadata exposed by the service. If the client and the server use this discovery implementation, a shortcut is present to avoid the metadata roundtrip. The ProbeMatch message foresees the sending of the service address endpoint through the EndpointReference XML structure (see WS-Addressing), which includes not only an address field, but also an extensibility paradigm within the ReferenceParameters field. Within this field, the service enters all information concerning the communication binding. If there is this information, ClientM emento doesn’t need the metadata roundtrip, and it is ready for communication.

A major quality of the client implementation is the AutomaticChangeChannelWhenFaulted property, which allows the fault tolerance property on the services. In fact, when there are several candidate services, GetBestMemento returns a channel towards the chosen service. If the proxy operation fails, the client automatically repeats the same operation towards another candidate at disposal, and it throws the exception only when there is no other candidate on which the operation can be executed. This client functionality is disabled by setting the property to false; as a consequence, the exception would be thrown when other candidates are present as well.

One of the main worries dealing with the client concerned with the management of personalized headers in a message sent using WS-Discovery . WCF allows the addition of personalized headers by the use of the OperationContextScope class, which unfortunately was declared sealed and is therefore inextensible to discovery functionalities.

Collapse
IMyContract proxy = cf.CreateChannel();
using (new OperationContextScope((IClientChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.Add(
MessageHeader.CreateHeader(" otherHeaderName" ,
" http://otherHeaderNs" , " otherValue" ));
Console.WriteLine(proxy.echo(" Hello World" ));
}

The problem is due to the fact that the DiscoveryClient channel doesn’t implement the IClientChannel interface, at least until when the real channel is created at the end of the discovery process. That is why I had to create a less elegant solution that let nevertheless bypass the problem. I’m talking about the DiscoveryOperationContextScope< TChannel> class that allows, in a similar way, to execute the required operation.

Collapse
DiscoveryClient<IMyContract> proxy = new
 DiscoveryClient<IMyContract>();
using (DiscoveryOperationContextScope<IMyContract> os
= new DiscoveryOperationContextScope<IMyContract>(proxy))
{
os.OutgoingHeaders.Add(MessageHeader.CreateHeader(" MyHeaderName" ,
" " ," MyheaderValue" ));
Console.WriteLine(" Output string: " + proxy.Channel.GetString(" qqq" ));
}

The implementation of the service part seems easier, the behavior adds to the static ServiceContext class the information concerning the service. ServiceContext hooks the Opened and Closing events of ServiceHost to send Hello and Bye messages and it continues to listen to at the multicast port to receive the Probe/Resolve messages.

A function linked to the extensibility concerns the dynamic scopes. While implementing the service, I wanted to make the scopes to be dynamically manageable to let them be changed during the service life, reminding always to myself that every metadata change has be notified to the client through a new Hello message.

Configuration of the discoverable service

The part concerning the service foresees that WS-Discovery can be set during the configuration phase through a specific Behavior and an associated extension:

Collapse
<
extensions
>

< behaviorExtensions >
< add name =" serviceDiscoverableBehavior"
type =" Masieri.ServiceModel.WSDiscovery.Behaviors.DiscoveryBehaviorSection,
Masieri.ServiceModel.WSDiscovery, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=18ad931e67d285bd"

/ >
< / behaviorExtensions >
< / extensions >
< services >
< service behaviorConfiguration =" serviceDiscoverable"
name =" ServiceTest.IServiceSample" >
...

< / service >
< / services >

The discovery functionality setting can therefore be introduced without recompiling the code again but by simply introducing the settings in the configuration file. The associated behavior has to be configured with specific sections:

Collapse
<
behavior
 name
="
serviceDiscoverable"
>

< serviceMetadata
httpGetEnabled =" true"
httpGetUrl =" http://localhost:8080/Mex" / >
< serviceDiscoverableBehavior
scopesMatchBy =" http://schemas.xmlsoap.org/ws/2005/04/discovery/rfc2396" >
< scopes >
< add url =" http://myscope.tempuri.org/" / >
< / scopes >
< / serviceDiscoverableBehavior >
< / behavior >
< / serviceBehaviors >

The ServiceMetadata behavior has to be specified in the ServiceBehavior setting to allow to recover the binding settings through WSDL. Actually, this setting would be unnecessary, if this discovery library were used both for the client and for the server, as a mechanism was developed to avoid the metadata roundtrip and to allow a faster communication. The automatic metadata creation by WCF is very comfortable, but not so fast: it is true that it is created the first time and then kept in memory for the following requests; that is normal in 90% of the cases, but in some architectural cases, I found the services were often instantiated and destroyed with a lot of trouble for me as a consequence. If the WSDL creator had problems, for instance, due to unknown custom protocols (I noticed it in the implementation of the SDK soap.udp ), the creation could be slowed down for some seconds.

The service setting through the configuration is done, but it is possible to configure the service in a programmatic way.

Log

The log management was realized in a particularly attentive way to allow a complete integration with the WCF logs to have an exhaustive vision of the communication scenario. By the use of the configuration file, it is possible to add the System.ServiceModel.WSDiscovery source to the System.ServiceModel one and to make the log messages to flow together to a specific listener. The WS-Discovery messages are instead added to the System.ServiceModel.MessageLogging source as all the WCF messages.

Collapse
<
system.diagnostics
>

< sources >
< source name =" System.ServiceModel.WSDiscovery"
switchValue =" Warning, Error" >
< listeners >
< add initializeData =" InfoServiceDebug.e2e"
type =" System.Diagnostics.XmlWriterTraceListener,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"

name =" ServiceModel Listener"
traceOutputOptions =" LogicalOperationStack, DateTime,
Timestamp, ProcessId, ThreadId, Callstack"
/ >
< / listeners >
< / source >
< source name =" System.ServiceModel.MessageLogging"
switchValue =" Warning, Error" >
< listeners >
< clear / >
< add type =" System.Diagnostics.DefaultTraceListener" name =" Default"
traceOutputOptions =" None" / >
< add initializeData =" MessageLog.e2e"
type =" System.Diagnostics.XmlWriterTraceListener,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"

name =" MessageLogging Listener"
traceOutputOptions =" LogicalOperationStack, DateTime, Timestamp,
ProcessId, ThreadId, Callstack"
/ >
< / listeners >
< / source >
< / sources >
< sharedListeners >
< add type =" System.Diagnostics.DefaultTraceListener"
name =" Default" / >
< / sharedListeners >
< / system.diagnostics >

Log.Png

Points of interest

In this paragraph, I would like to share my architectural experiences regarding the use of WS-Discovery .

Service redundancy

The key-aspect of an architecture based on WS-Discovery is the realisation of service redundancy when possible. Some time ago, I worked on the system of the Italian railway network (RFI). Talking about used solutions, it is as various and heterogeneous as every other system of such a great dimension, but the whole system is controlled through web services. The geographical aspect of the systems, which are located in stations, compartments, and in the RFI CED (data centre) was a peculiarity to be taken in an adequate consideration, because it was unconceivable that a web service could face all the calls coming from the whole country (actually, it is possible, but really expensive!).

In such a scenario, I developed the first version of WS-Discovery to try to completely change the existing model (of course, the sources were completely rewritten and improved in a lot of aspects). Working in a team of people who work well together, we developed a solution that made several clients from the whole territory, not to interface directly with the central web service, but to find run time local providers that gave them the same information. These local providers were actually cache managers pretending to be the required service. If the client needs information coming directly from the source, it can always get it by the use of the correct scope.

Scalar.Png

Fault tolerance

Fault tolerance represents another magic aspect of WS-Discovery . When a client cannot make a call to a service, it can try with another service satisfying the same scopes criteria. This behaviour is obviously settable through the client AutomaticChangeChannelWhenFaulted property.

Collapse
do

{
try
{
OnInvoking();
object ret = method.Invoke(_lastUsedChannel, parameters);
OnInvoked();
DiscoveryLogger.Info(" Method invoked successfully" );
return ret;
}
catch (Exception ex)
{
DiscoveryLogger.Error(" Errore nell'invocazione del servizio" , ex);
lock (_lock)
{
// endpoint error
ClientContext.Current.RemoveDiscoveredEndpoint(
Helpers.ContractDescriptionsHelper.GetContractFullName<TChannel>(), mem);
// Look for another one
mem = GetBestMemento();
if (mem == null )
{
// Start a new probe process for the future
StartProbeProcess();
DiscoveryLogger.Warn(
@" The DiscoveryClient can't scale on another service" );

// Now I can throw the exception
if (originalException == null )
throw ex;
else
throw originalException;
}
// I try again but I store the original exception before
if (originalException == null )
originalException = ex;
}
}
} while (AutomaticChangeChannelWhenFaulted);

Scopes with quality of service and dynamic change of the system

In another project developed together with the railway society, we studied a solution with dynamic scopes which represented the service QOS (Quality of service) to allow the client to hook the service whose QOS is compatible with its needs, without being too demanding, to avoid blocking all the services with better QOS. By executing the GetBestMemento overload, the client can select the service with the most suitable QOS, while the services update the QOS according to the number of simultaneous users through the MetadataVersion mechanism.

Extension of Roman Kiss’ ESB

WS-Discovery is completely compatible with the implementation of WS-Eventing and WS-Transfer dealt with in Roman Kiss’ article: server-side, by including the discovery Behavior into the service; client-side, by banally using the DiscoveryClient< RKiss.WSEventing.IWSEventing> class, for instance.

Dynamic load balancing

In a recent architecture for video surveillance and scene analyses systems, I implemented a service that can dynamically load some components of scene analyses which allowed, through a SubscriptionManager, to subscribe to the analyzed events. The computational work carried out by these components was high. I thought of integrating them in a server that was sufficiently scalable in several PCs, giving the identifier of the analyzed scene in the scopes. In such a way, the system can optimize the load on several machines without clustering configuration. It can dynamically distribute the load without taking care of the interconnected clients. In the case of dynamic reallocation of a component from a machine to another one, server 1 starts the host preparation process on a new machine (server 2), which sends a hello with the list of scopes of the served component when it is ready. The client, which receives the hello message, files the Memento among those at disposal. Server 1 sends a Hello with a new MetadataVersion version, where the scope of the removed component is no more present, and sends an EndSubscription message to the connected clients automatically, therefore causing the transfer to the new Memento and the new Subscribe on server 2.

EventListener.Png

分享到:
评论

相关推荐

    wcf ws-Discovery 全套源代码

    在这个**"wcf ws-Discovery 全套源代码"**中,包含了服务端和服务客户端的实现,这为学习和理解WCF与WS-Discovery的结合使用提供了实践基础。以下是一些关键知识点: 1. **服务契约(Service Contract)**:定义...

    WCF 我的WCF之旅示例代码

    - **WS-* 规范支持**:WCF全面支持Web服务标准,如WS-Security、WS-ReliableMessaging等。 通过这些示例代码,你可以逐步掌握如何创建服务、配置终结点、实现合同、管理会话以及处理安全性问题。同时,学习过程中...

    Web服务和WCF服务

    - **WCF优势**:WCF提供更灵活的绑定和传输选项,支持多种安全性模型,并且符合WS-I基本规范,增强了跨平台的互操作性。 4. **调用Web服务和WCF服务**: - **调用Web服务**:可以通过HTTP请求直接调用ASP.NET Web...

    WCF高级编程实例(用VS2010编译过)

    7. **服务发现** - 通过UDDI(统一描述、发现和集成)或WS-Discovery,服务可以自动发布自己的存在,让客户端找到并连接。 8. **状态管理和持久化** - WCF支持状态管理,如会话状态、实例化模式(单例、多例、Per...

    WCF服务编程

    9. **服务发现**:通过UDDI(统一描述、发现和集成)或WS-Discovery,WCF服务可以被自动发现和注册,方便客户端找到并使用服务。 10. **服务互操作性**:WCF设计时考虑到了与其他服务导向架构的互操作性,如SOAP、...

    代码配置WCF服务端和客户端

    - 服务发现:若需要动态发现服务,可以使用WS-Discovery协议。 - 负载均衡和可扩展性:对于高并发场景,可以考虑使用负载均衡和多实例部署。 本示例仅展示了WCF服务端和客户端的基础代码配置。在实际项目中,可能...

    最新整理的WCF资料.rar

    9. **服务质量(QoS)**:WCF支持服务质量特性,如消息队列(允许异步操作和解耦)、路由服务(转发消息到多个目的地)和WS-Discovery(服务发现)。 10. **调试和诊断**:WCF提供了丰富的诊断工具,包括事件日志、...

    WCF例子,WCF例子,WCF例子,WCF例子

    9. **服务发现**:通过UDDI(Universal Description, Discovery, and Integration)或WS-Discovery,服务可以被自动发现,使得客户端能够更容易地找到并连接到它们。 10. **服务质量**:WCF支持事务、消息队列和...

    WCF在各领域的应用

    - **服务发现**:通过使用WS-Discovery等标准协议,WCF支持动态服务发现,便于服务的自动注册和查找。 - **服务组合**:WCF允许开发者轻松地将不同的服务组合起来形成更复杂的业务流程。 ##### 2. 互操作性和集成 ...

    wcf 例子打包下载(c#高级编程第五版)

    7. **服务的发布与发现**:了解如何通过服务目录(UDDI)或WS-Discovery让服务能够被自动发现。 8. **延迟加载和服务缓存**:讲解如何优化服务性能,包括延迟加载数据和利用缓存技术。 9. **多层架构中的WCF应用**...

    wcf,net remoting,web service 概念及区别

    - **安全性与可靠性**:WCF支持WS-Security、WS-ReliableMessaging等一系列高级特性,提供了比.NET Remoting和Web Service更为强大和全面的安全保障和消息可靠性支持。 - **性能与状态管理**:.NET Remoting在某些...

    webservice6 共免费18讲

    探讨如何使用Java的JAX-WS或.NET的WCF框架来创建和部署Web服务,以及如何在客户端消费这些服务,包括SOAP请求的构建和响应的处理。 第十讲至第十三讲:Web服务的安全性 涵盖Web服务安全的关键议题,如HTTPS、SOAP...

    C# WCF Demo程序

    6. **负载均衡和故障转移**: 通过多宿主和WS-Discovery,可以实现服务的负载均衡和故障转移。 7. **性能优化**: 可以通过调整绑定配置,如增大缓冲池大小、禁用消息验证等,来提高服务性能。 **四、WCF Demo程序**...

    Windows Communication Foundation 4 Step by Step

    此外,WCF还支持多种服务发现机制,如UDDI(Universal Description, Discovery, and Integration)和WS-Discovery,帮助客户端找到并连接到服务。 对于故障诊断和调试,WCF提供了详细的跟踪和日志记录功能。通过...

    WCF服务编程中文版.pdf

    7. **安全性(Security)**:WCF提供多种安全机制,包括传输安全(如HTTPS)、消息安全(如WS-Security)、身份验证和授权。安全特性确保服务只能被授权的客户端访问,并且通信内容受到保护。 8. **事务...

    《WCF技术剖析》[1][1].(蒋金楠).[PDF]&ckook;

    1. **与ASP.NET的集成**: WCF可以创建Web服务,兼容ASMX和WS-*标准。 2. **与.NET Remoting的集成**: WCF提供了向.NET Remoting的迁移路径,保持与旧系统的兼容性。 3. **与MSMQ的集成**: 支持基于消息队列的消息...

    WCF解密中文版

    11. **互操作性**:WCF设计时考虑到了与其他平台和标准的兼容性,如SOAP、WS-*规范,以及与非.NET环境的互操作。 12. **性能优化**:通过缓存、数据压缩和会话管理等策略,可以优化WCF服务的性能。 通过阅读《WCF...

    WebService小教程

    - JAX-WS(Java API for XML Web Services)是Java平台上用于创建和消费WebService的标准,它简化了开发过程。 - .NET Framework提供了ASMX和WCF(Windows Communication Foundation)等工具,支持.NET应用程序...

Global site tag (gtag.js) - Google Analytics