|
|
Browse by Tags
All Tags » Proxies » Answers (RSS)
-
I have a schema file that describes a choice between multiple layout formats for a type. How do I build a proxy that matches this schema? The reason that this is probably not working is because DataContractSerializer for the most part does not support ambiguous, optional, or multiply-described sections of types. Using svcutil and specifying the serializer to be XmlSerializer is more likely to generate the expected proxy type. Here's a rough guide to what DataContractSerializer does not support for complex type content. If you're using any of these features in your schema, then it's likely that you'll need to use XmlSerializer instead. Attributes (pretty much everything related to attributes including groups and wildcards) Group, all, or choice selections Extensions or restrictions of simple content (except for restrictions from anySimpleType) Sequences that are optional or repeating (minOccurs or maxOccurs not equal to 1) Sequences that contain other sequences or wildcard content Next time: Using ETW Tracing Read More...
|
-
How do I specify that the client proxy should not have a setter for a particular data member? It doesn't make sense for the service to be able to dictate what the client can do with a piece of data. Once data has been put on the wire, you can't stop the other side that is receiving the message from doing whatever they want with that data. Schema and metadata don't have any notion of access modifiers, but let's say that they did. You might say in the metadata that a certain piece of data has restricted access. First, there's nothing requiring me to use the same metadata and tools that you are, so I may not even know about your access modifiers. The representation that gets written to the wire is the truth about how your service works, not the metadata. Second, even if I am using the same metadata and tools as you are, I can always change the client after it's created because the generated code is something that I own rather than you as the service author. If the client author and the service author are the same person, then there are much more effective ways of providing a preferred programming model than trying to describe those preferences through some aspect of the service description. Instead, just change the client library directly to do what you want and give people that. Next time: Certificate Stores Read More...
|
-
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...
|
-
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...
|
-
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...
|
-
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...
|
-
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...
|
-
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...
|
-
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...
|
-
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...
|
-
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...
|
-
When the service sends a fault message with a large detail, my client is unable to read the fault. Changing the standard settings for the maximum message size doesn't help. How can I read large fault messages? Fault messages have their own special quota that can be configured on the client proxy. For changing the settings of a proxy, you should immediately think about using a behavior. Luckily, that happens to work in this case. There is a MaxFaultSize property on the ClientRuntime, which we can get access to by supplying an IEndpointBehavior. public class SetMaxFaultSizeBehavior : IEndpointBehavior { int size; public SetMaxFaultSizeBehavior( int size) { this .size = size; } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MaxFaultSize = size; } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } } Let's use our new behavior to play with fault sizes. I've got a service that sends back a fault with no content, but we still have to deal with however big the rest of the fault message is. Then, the client will try connecting to the service with different maximum fault sizes to see what sizes work and what sizes don't. [ServiceContract] public interface IService { [OperationContract] void Operation(); } public class Service : IService { public void Operation() { throw new FaultException< string >( "" ); } } class Program { static void Main( string [] args) { Binding binding = new BasicHttpBinding(); string uri = "http://localhost:8000/" ; ServiceHost host = new ServiceHost( typeof (Service)); host.AddServiceEndpoint( typeof (IService), new BasicHttpBinding(), uri); host.Open(); int maxFaultSize = 1; while ( true ) { ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress(uri)); factory.Endpoint.Behaviors.Add( new SetMaxFaultSizeBehavior(maxFaultSize)); factory.Open(); IService proxy = factory.CreateChannel(); try { proxy.Operation(); } catch (FaultException fault) { Console.WriteLine( "Received fault with maxFaultSize={0}." , maxFaultSize); break ; } catch (QuotaExceededException exception) { Console.WriteLine( "Exceeded quota with maxFaultSize={0}." , maxFaultSize); } finally { factory.Close(); } maxFaultSize++; } host.Close(); Console.ReadLine(); Read More...
|
-
Two answers in one today on the subject of svcutil. How do I merge together configuration files like Visual Studio does with multiple web references? Use svcutil.exe with the /mergeConfig option. How do I pass credentials when accessing metadata from a secure endpoint with svcutil? You can create a configuration file for svcutil.exe that allows you to specify options such as credentials just like any other application. If your credentials can only be set through code rather than configuration, then create a behavior that sets up the credentials and add that behavior to the configuration file for svcutil.exe. Next time: Listener Won't Start Read More...
|
-
You have talked in the past about how a service has both local settings and settings that are shared through policy. How can I transmit all settings through policy to the client? The two types of settings are clearly distinguishable. Shared settings are required to have agreement between the client and server for the two to interoperate. Examples of shared settings are the protocols and formats being used to transmit messages. Local settings are not required to have agreement between the client and server for the two to interoperate. Examples of local settings are the limits for the time and space allowed to process a message. Local settings can not only be in disagreement between the client and server, but they frequently do not make sense to share between the two. The messages sent between the client and server are rarely symmetric. The processing resources available to the client and server are rarely the same. The security concerns of the client and server are rarely in agreement. You can transmit local settings by creating your own policy assertions that both sides implement. This will involve a lot of hassle, particularly if the service wants to have local setting values that are different than those sent in the policy. Finally, the client will need to absolutely trust the service because you are asking the user to run with settings that were supplied by a third party. Why do you want to do this using policy? It seems that if you have such a level of trust with the client, then you probably already have more direct ways of pushing configuration and executables to the client machine. Next time: Enabling Performance Counters Read More...
|
-
How do I attach a custom behavior to a dynamically generated proxy object? This one should be easy if you've read the past two articles about modifying a ChannelFactory after creation. Although behaviors can't be specified while creating the ChannelFactory, the ChannelFactory has a local endpoint object that can have behaviors attached. Changing the endpoint for behaviors works exactly the same as changing the endpoint for contracts. As with all modifications to endpoints though, you need to make all changes prior to calling Open (or the first call with proxies) or you'll find that the endpoint has become immutable. Next time: Reader Quotas with Untyped Messages Read More...
|
|
|
|