Welcome to Windows Communication Foundation (WCF)
Top Tasks :

WCF Team Bloggers

Browse by Tags

All Tags » Proxies   (RSS)

  • Finding a Client Channel

    Where can I get the IContextChannel that OperationContextScope requires? OperationContextScope allows you to create a temporary scope in which context for a service operation can build up before and after the operation is actually called. The constructor for OperationContextScope takes an instance of IContextChannel, which is a type that you've probably never seen before. Why are you expected to have this unknown type? It's because you have instances of it floating around all the time even though there's no particular hint of this. There are different ways to get an IContextChannel depending on whether you're using a proxy generated by svcutil or a proxy generated at runtime. In either case, pretend that I've got service contract called IService with a single method called Foo. When I generate a service client using svcutil, the client object has a member called InnerChannel that works as an IContextChannel. ServiceClient client = new ServiceClient(binding, new EndpointAddress(address)); using ( new OperationContextScope(client.InnerChannel)) { WebOperationContext.Current.OutgoingRequest.Headers[ "X" ] = "from compiled proxy" ; client.Foo(); } client.Close(); Otherwise, if I'm using a ChannelFactory to create the proxy at runtime, the channel that I get back happens to be an IContextChannel as well. ChannelFactory<IService> factory = new ChannelFactory<IService>(binding); factory.Open(); IService proxy = factory.CreateChannel( new EndpointAddress(address)); using ( new OperationContextScope((IContextChannel)proxy)) { WebOperationContext.Current.OutgoingRequest.Headers[ "X" ] = "from runtime proxy" ; proxy.Foo(); } factory.Close(); Next time: Standards Guide Read More...
  • Adding Headers to a Call (HTTP Version)

    Yesterday I talked about adding SOAP headers to an outgoing request using a variety of different methods. The most straightforward method was to create an OperationContextScope in your application code to establish an OutgoingMessageHeaders collection. Although HTTP headers are similar in spirit to SOAP headers, manipulating an HTTP header through code looks a bit different. SOAP headers are elevated to a special significance in the programming model. Everything else, including HTTP headers, is relegated to a general-purpose but distinctly second-class collection of message properties. On the OperationContextScope you'll find a parallel OutgoingMessageProperties collection that can be used for HTTP headers. In Orcas, the plain OperationContext also works as a WebOperationContext that gives the same first-class programming model to HTTP headers as you get with SOAP headers. Here's a comparison of the two approaches. using ( new OperationContextScope((IClientChannel)proxy)) { HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty(); requestProperty.Headers[ "X-header" ] = "value1" ; OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty; proxy.Operation(); } using ( new OperationContextScope((IClientChannel)proxy)) { WebOperationContext.Current.OutgoingRequest.Headers[ "X-header" ] = "value2" ; proxy.Operation(); } Next time: Configuring SSL Host Headers Read More...
  • Adding Headers to a Call

    How do I add SOAP headers to an outgoing request? There are a few different ways to add headers to a message depending on how you need to control the header content and where you need to insert the header. I like to think of these methods as being split among the application, the proxy, and the protocol. In your application code you can create an OperationContextScope around the request in order to change some of the request properties. Inside an OperationContextScope, you have a valid instance of OperationContext.Current, which allows manipulation of the message headers through the OutgoingMessageHeaders collection. Use of this method deeply bakes control of the headers into the application code. You would have to be responsible for copying the appropriate code wherever it was needed. Now, assume that you want the header to be present whenever you're talking to a particular service and the header value can be determined consistently. Rather than having to put the same code at each call site, you can centralize the code in the proxy or in a protocol. The simplest way to centralize header manipulation in the proxy is to create an instance of the IClientMessageInspector and attach that to the proxy. This gives you a hook for every message going through the proxy to modify the message headers. An instance of IChannel similarly gives you a hook for every message going through the channel stack to modify the message headers. Using the Message Interceptor sample gives you an extensibility point in the binding that is similar in spirit to the extensibility point provided by a message inspector. The primary difference from your perspective of a message inspector and a channel is a matter of timing. A message inspector always runs before any of the protocols in the binding while a channel can be positioned precisely in the protocol stack. In most cases you don't need precise positioning, so you should go with the simpler approach. Next time: Adding Headers to a Call (HTTP Version) Read More...
  • Faster Known Types in Orcas

    When I talked about some of the enhancements in Orcas, I left out a performance improvement for services that use a large number of known types. There are various ways of defining the known types for a service operation, and all of the known type collections are aggregated together for use the first time that an unknown type needs to become a known type. The performance of that first call grew increasingly worse rather quickly as the number of known types increased, although the performance of successive calls was not affected. This slowdown was fixed in Orcas (you don't need Orcas SP1 to get it). If you are seeing a pattern of slow first calls that is improved by not declaring known types, then you may want to see if installing Orcas makes your first call faster. Next time: Common Setup Tasks Read More...
  • Customizing Proxy Configuration

    In the past I've written about overriding ApplyConfiguration on a service to take control of the configuration process. There is a similar technique that you can use for client proxies although getting started is not quite as obvious. I'll talk today about the typed proxies generated by constructing a ChannelFactory<T>. When you're using ChannelFactory<T>, you are midway between the tool-based automatic proxy generation and the channel-based manual proxy construction. Everything here also applies to the base ChannelFactory if you don't need the supplied type parameter. On ChannelFactory there are two interesting methods that you can override in subclasses. protected virtual void ApplyConfiguration( string configurationName); protected abstract ServiceEndpoint CreateDescription(); ApplyConfiguration is similar in spirit to the ApplyConfiguration on a service but has a little bit of a different interaction with CreateDescription. All of the heavy lifting for building the endpoint (the address, binding, and contract) is done in CreateDescription. All that is done in ApplyConfiguration is to load behaviors for the client proxy from configuration. Since ApplyConfiguration is not as interesting on the client, there are going to be more cases where you need to override both ApplyConfiguration and CreateDescription. If you only need to fix up the generated proxy, then you may be able to use the base implementation for both ApplyConfiguration and CreateDescription, and apply your changes to the description in an override of ApplyConfiguration. If you want to make more extensive changes to the configuration or client proxy generation process, then you're less likely to be able to use the base implementation of ApplyConfiguration and may need to override CreateDescription as well. Next time: Pointing to External Metadata Read More...
  • Generating Types with Lists

    I have a data contract that contains a collection type but the generated proxy appears as an array. How can I make the proxy use a collection type as well? I've talked in the past about how the representation of a type in metadata is decoupled from the CLR representation of a type in the service. For example, if I have a data contract that uses a List: [DataContract] class Data { [DataMember] public List< string > data; } Then, the metadata representation of this data contract is actually described as an array because arrays are the only primitive type for collections in schema. < xs:schema xmlns:tns ="http://schemas.datacontract.org/2004/07/" elementformdefault ="qualified" targetnamespace ="http://schemas.datacontract.org/2004/07/" xmlns:xs ="http://www.w3.org/2001/XMLSchema" > < xs:import namespace ="http://schemas.microsoft.com/2003/10/Serialization/Arrays" > < xs:complexType name ="Data" > < xs:sequence > < xs:element xmlns:q1 ="http://schemas.microsoft.com/2003/10/Serialization/Arrays" minoccurs ="0" name ="data" nillable ="true" type ="q1:ArrayOfstring" > </ xs:element > </ xs:sequence > < xs:element name ="Data" nillable ="true" type ="tns:Data" > </ xs:element > </ xs:complexType ></ xs:import ></ xs:schema > However, just as the metadata representation isn't coupled to the service, the metadata representation also isn't coupled to the client. You can on the client generate proxies with any type for this collection that similarly can be serialized or deserialized to an array. The mechanism for doing this with svcutil.exe is the /ct switch. The /ct switch, which stands for collectionType, allows you to give a qualified type name that is used for collection data types when generating a proxy. As an example, to get back to the original collection class used by the server, the proxy would need to be constructed using /ct:System.Collections.Generic.List`1 as the option passed to svcutil.exe. However, you could leave the proxy using arrays or provide a different collection class such as /ct:System.Collections.ObjectModel.Collection`1 and with any of these configurations the proxy would be able to exchange messages with the server. Next time: Setting the Configuration Name Read More...
  • Private Data Members

    Why does a data contract with private or internal members generate a proxy with public fields? The obvious answer is that the representation for data contracts doesn't contain information about member visibility but that just leads to the question of why the information isn't preserved by the representation. If we take a data contract that contains both public and private members, [DataContract] class Data { [DataMember] public int i; [DataMember] private string s; } Then, the type representation used to generate a proxy is based on an XML schema. < xs:schema xmlns:tns ="http://schemas.datacontract.org/2004/07/" elementFormDefault ="qualified" targetNamespace ="http://schemas.datacontract.org/2004/07/" xmlns:xs ="http://www.w3.org/2001/XMLSchema" > < xs:complexType name ="Data" > < xs:sequence > < xs:element minOccurs ="0" name ="i" type ="xs:int" /> < xs:element minOccurs ="0" name ="s" nillable ="true" type ="xs:string" /> </ xs:sequence > </ xs:complexType > < xs:element name ="Data" nillable ="true" type ="tns:Data" /> </ xs:schema > A schema is a type system that is independent of the type system used by the proxy and has no concept of member visibility. However, by saying that a member is part of the data contract, you've effectively said that that member is as intrinsically part of the data as any other public facing member. Member visibility is a facet of information hiding to suppress details that are not needed by other parts of the system, but a data member by definition is needed by other parts of the system. Therefore, regardless of how one of the parties has chosen to represent that data, it's more likely than not that the other side will need to manipulate that data to uphold the contract. Next time: Generating Types with Lists Read More...
  • Manual Context Management

    How do I manually manage the context when sharing a client object? The default mode when using a context binding is for the context to be managed internally by the context channel underneath the client proxy. This is similar to how by default cookies are managed by an HTTP channel to send and receive cookie context. With an HTTP channel you can disable automatic cookie management and control the context yourself. There is a similar process that you can use to take control for a context binding. Here's a comparison of the two processes. You can get the code for HTTP by using the link above and with the further details on custom cookie handling so I won't print it again. With HTTP, you first need to turn off automatic cookie handling by setting the AllowCookies property on the HTTP transport binding element to false. With a context binding, you first need to turn off automatic context handling by setting the Enabled property on the context manager to false. IContextManager contextManager = channel.GetProperty<IContextManager>(); contextManager.Enabled = false ; Then, for HTTP you attach an HttpRequestMessageProperty that contains the desired cookies to a message using an OperationContextScope. With a context binding, you use the same OperationContextScope approach but attach the appropriate ContextMessageProperty instead. using ( new OperationContextScope(client.InnerChannel)) { ContextMessageProperty contextProperty = new ContextMessageProperty(contextData); OperationContext.Current.OutgoingMessageProperties[ContextMessageProperty.Name] = contextProperty; client.DoOperation(); } Next time: Messaging Additions in Orcas Read More...
  • Passing Around Endpoints

    Can I construct a proxy object on one machine and pass it to another? No, there's no concept in WCF of sending a fully constructed proxy object from one place to another. Consider that there are two different things that "passing" a proxy object could mean: passing a reference to the object or passing a value by constructing an equivalent object in another location. If you passed a proxy by reference, then what you really would be doing is sending messages from your local machine to the remote machine on each invocation, to be sent by the real proxy. However, that's just a service that forwards messages between the two proxies, and that's something that you can build yourself. If you passed a proxy by value, then what you really would be doing is sending some description of the proxy to be created locally. Again though, that is something that you can build yourself by passing the endpoint description for the proxy you want to recreate and constructing a local proxy factory. Next time: One Shot Serialization Read More...
  • Differences in Guid Serialization

    Why do the guids in my contract turn into strings when generating a client? You're probably mixing different types of serializers between the client and service. There's nothing wrong with this and the generated client will work correctly but you don't get the user-friendly types. To see why, let's look at the metadata. A guid in a contract with the DataContractSerializer generates a type in the http://schemas.microsoft.com/2003/10/Serialization/ namespace that looks like this: < xs:element name ="guid" nillable ="true" type ="tns:guid" /> < xs:simpleType name ="guid" > < xs:restriction base ="xs:string" > < xs:pattern value ="[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}" /> </ xs:restriction > </ xs:simpleType > On the other hand, a guid in a contract with the XmlSerializer generates a type in the http://microsoft.com/wsdl/types/ namespace that looks like this: < xs:simpleType name ="guid" > < xs:restriction base ="xs:string" > < xs:pattern value ="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" /> </ xs:restriction > </ xs:simpleType > These generated types are needed because a guid is not a primitive type. DataContractSerializer came after XmlSerializer so it recognizes both definitions but XmlSerializer has to rely on the schema when it sees a DataContractSerializer guid. Since the schema is based on a string type, the generated client field is a string. The same thing happens with other serializers that don't know how to map a particular schema pattern to a user-friendly type. Next time: TCP Throttling Read More...
  • A Proxy Proxy Factory

    I have a system that sometimes uses a fast local object and sometimes needs to communicate over a network. I have built a proxy object that wraps the proxy factory for creating typed proxies together with a proxy factory for creating local objects. Are there any downsides to this strategy? Historically, there have been a number of attempts to hide whether objects are local or remote from programmers. These attempts have had varying degrees of success. Ultimately, the sticky issue is that it's difficult to prevent network abstractions from leaking. A leaky abstraction allows the environmental details that the abstraction is supposed to be hiding surface into the calling code. Like a leaky basement, a leaky abstraction can lay in wait for a long time before you realize that it's a problem. Problems with leaky abstractions show up when the abstraction author tries to make the surface layer completely seamless. Programmers love seamless abstractions because it makes their code very simple. However, implementers haven't yet figured out how to make any interesting abstraction be truly seamless. WCF attempts to deal with this issue by defining standard behaviors for channels. These standard behaviors are an escape valve so that when the abstraction leaks, it can leak in a controlled manner. For example, channels allow almost any operation to fail but restrict the exception types that the implementer can use and gives those types particular meanings. Or, channels require the programmer specify timeouts and quotas even when the application would rather trust the other side to behave. Or, and this is the most relevant one to the original question, channels require that the sender and receiver decouple their view of message data. Decoupling the sender and receiver means that there can be no way for the sender to modify the receiver's view of the data after a message is sent. In practical terms, achieving this decoupling requires that the data almost always be copied even when using direct object calls. While you can shortcut a lot of things with local objects, the system can't guarantee the abstraction if you bypass channels. There's not a big speed difference between a channel optimized for local communication and a local object that obeys all of the channel rules. Another way of saying that is that channels are extremely cheap if they don't have underlying network resources. There's currently no channel truly optimized for local communication although the named pipe Read More...
  • Sharing Contracts Across Services

    I've deployed several services that share some of their data contracts. When I build a client application that calls more than one of the services, each service contributes a copy of the data contract during proxy generation. This causes a compile error because the same type is defined multiple times. How do I resolve the conflict? Assuming that you don't want to change the services, there are four obvious ways to fix the conflict. Three of the ways are mostly manual and one of the ways is mostly automatic. Manual resolution: split up the client application into separate compile units so that each of the compile units references only one of the services. This method is the most invasive and tedious solution. Manual resolution: edit the output of proxy generation to place each service proxy in its own namespace. This method requires very little work but makes writing the client application inconvenient because types need to be namespace qualified and passing objects between different services becomes harder. Manual resolution: edit the output of proxy generation to remove extra copies of types. This method requires the most work every time you want to regenerate the proxies but gives you the most freedom for building the client application the way you want. Automatic resolution: treat proxy generation as an incremental process and use svcutil /r to reference type assemblies generated by earlier processed services. This method is possible to fully automate but introduces complications into the proxy generation process. This method is the best long-term solution but requires infrastructure work that may be too much overhead for smaller projects. Next time: Cleaning up Async Read More...
  • Better Proxy Clients

    I was in a meeting last week with a few WCF users at Microsoft when they asked about performance issues creating client proxies. The first service pack for WCF, which ships at the same time as Orcas, includes some performance fixes for the most frequently seen issues, including the one they described. Wenlong Dong from the WCF performance team was at that meeting and has written up an in-depth description of the changes to client proxy creation , along with some best practices for using client objects. I'll be at the Ask the Experts reception tonight for the SOA and Business Process conference that Microsoft is hosting. I expect regular articles to resume tomorrow since I've done announcements for the first two days this week already. Read More...
  • Service Contract Generation

    In the post on custom namespaces a few days ago, I used svcutil to generate the service WSDL and schema description. This use of svcutil is apparently not as well understood so I thought I'd give some more details. The typical use of these programs is to generate the necessary client files, proxy code and configuration, from an existing service. Rather than generating the client files directly, the same programs can be used to save a copy of the service description. Having the service description decouples downloading the metadata from generating the client files. If you would normally use svcutil [service-address] to generate client files, then you would instead use svcutil /t:metadata [service-address] to generate the metadata files. The followup command would be to run svcutil *.wsdl *.xsd to collect all of the generated metadata files and create the client files. Another option that exists is to run svcutil against local files rather than a running service. You'll get some of the metadata from svcutil /t:metadata [files] . However, this misses collecting information about the binding or the actual service class (as opposed to the service interface type). Processing this service description still gets you something similar but not entirely like the generated client files you would have gotten from the running service. The missing information can be supplied by a reference to the configuration. Using the /serviceName option with the name of the configuration section that defines the service, svcutil will be able to complete the service description. The configuration file that gets searched is the standard one based on the executable file name. It's important to remember that the service name is not actually the name of the service but rather the name of the service section in the configuration file. Next time: Creating Sessions over HTTP Read More...
  • Calling Services Without a Contract

    Contracts are largely an illusion about the kinds of messages that can be exchanged between a client and a server. From a practical perspective, a service can describe itself using any contract it likes but the true measure of compatibility comes from being able to exchange data. The easiest way to experience this observation is to build and send some messages without using any contracts. I've talked a lot in the past about sending messages directly using channels, which are a very thin wrapper around the semantics of sending and receiving. You don't have to go all the way to using channels to experience contract-less programming though. The standard ChannelFactory class for building proxy objects has a limited built-in knowledge about the IRequestChannel shape. In essence, this is a way to send messages in a contract-oriented programming model without actually using contracts. Quite a few systems require sending and receiving messages but lack any support for dealing with contracts. It can be difficult to acclimate yourself to this style of programming, but it can be done to a large degree without having to give up the conveniences of a nice programming model. Next time: Serializing UniqueId Read More...
More Posts Next page »

Copyright © 2006 Microsoft Corporation. All Rights Reserved. | Terms of Use | Privacy Statement | Contact Us