Nicholas Allen's Indigo Blog

Windows Communication Foundation From the Inside

January, 2008

  • Nicholas Allen's Indigo Blog

    Differences in Guid Serialization

    • 5 Comments

    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

  • Nicholas Allen's Indigo Blog

    30 Years of IP

    • 1 Comments

    In January 1978, Vint Cerf and Jon Postel released a draft for Version 3 of the Specification of Internetwork Transmission Control Program (I'll just refer to it as TCP-3). TCP-3 is an ancestor of the modern TCP/IP protocol and this draft is the first specification I know of that has a split between what's called in TCP-3 the Internetwork Packet Format and the TCP Packet Format. You might recognize these names as resembling the distinct IP and TCP layers. Earlier versions did not have a clear separation of responsibilities and describe a fatter TCP protocol. The actual division of IP into its own specification came a few weeks later.

    This breakup into the two protocols didn't come entirely out of thin air. There are articles by Jon Postel from several months prior based on the TCP-2 draft that outlined the different characteristics between point-to-point messaging and end-to-end messaging and why two protocols were needed.

  • Nicholas Allen's Indigo Blog

    Finding Data in Client Certificates

    • 1 Comments

    Can I pass additional user data, such as identity information, in a message secured with a client certificate?

    This question looks like an earlier one about Windows credentials but has some subtle differences that make it come out with a different answer. The two key differences are:

    We're talking about securing messages rather than transport connections. Message security headers provide a means of tunneling additional information about the caller.

    We're talking about passing identity information together with a certificate rather than with Windows credentials. Independent of the particular security protocol, the certificate infrastructure is a way to sign and encrypt data streams so that additional client information can be safely included.

    With either approach, client information can be included as supporting tokens on the message (typically as either incoming supporting tokens with the message or with the transport token). The supporting tokens sample gives a rundown of supporting tokens for message security.

    Next time: Differences in Guid Serialization

  • Nicholas Allen's Indigo Blog

    A Proxy Proxy Factory

    • 3 Comments

    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 channel turns out to be good enough for most people.

    Note: I don't actually remember whether the question was about building a proxy proxy factory or a proxy factory factory. The original question had too many levels of indirection to keep track of. It doesn't really change the answer whether it's a proxy or a factory for proxy factories.

    Next time: Finding Data in Client Certificates

  • Nicholas Allen's Indigo Blog

    Importing and Exporting WSDL Annotations

    • 2 Comments

    How do I add custom annotations to the contracts that are generated from WSDL?

    You first need to start with an IWsdlImportExtension. Your extension gets called each time a contract is discovered during import. Processing happens in multiple passes so we aren't quite ready to mess with generated contract yet. Instead, this is the opportunity to setup some deferred work that can be run once the contract is fully resolved.

    class MyWsdlImporter : IWsdlImportExtension
    {
    public void BeforeImport(ServiceDescriptionCollection wsdlDocuments, XmlSchemaSet xmlSchemas, ICollection<XmlElement> policy)
    {
    }

    public void ImportContract(WsdlImporter importer, WsdlContractConversionContext context)
    {
    context.Contract.Behaviors.Add(new MyServiceContractGenerator());
    foreach (Operation operation in context.WsdlPortType.Operations)
    {
    OperationDescription description = context.Contract.Operations.Find(operation.Name);
    if (description != null)
    {
    description.Behaviors.Add(new MyOperationContractGenerator());
    }
    }
    }

    public void ImportEndpoint(WsdlImporter importer, WsdlEndpointConversionContext context)
    {
    }
    }

    You'd probably want to be a little bit more discriminating about which contracts you attach to and you'd probably want to actually pass some data to the contract generator so that it knows how to modify the contracts. Let's ignore those little problems and look at the contract generators. The contract generator gets invoked once it's time to actually mess with the generated contract.

    class MyServiceContractGenerator : IServiceContractGenerationExtension, IContractBehavior
    {
    public void GenerateContract(ServiceContractGenerationContext context)
    {
    // muck with generated service contract
    }

    #region IContractBehavior Members
    ...
    #endregion
    }

    class MyOperationContractGenerator : IOperationContractGenerationExtension, IOperationBehavior
    {
    public void GenerateOperation(OperationContractGenerationContext context)
    {
    // muck with generated operation contract
    }

    #region IOperationBehavior Members
    ...
    #endregion
    }

    The IWsdlImportExtension plugs in through the configuration file of the WSDL importer (typically svcutil.exe).

    <client>
    <metadata>
    <wsdlImporters>
    <extension type=" ... " />
    </policyImporters>
    </metadata>
    </client>

    You should be able to figure out how the reverse process works starting from some strategic examination of IWsdlExportExtension.

    Next time: A Proxy Proxy Factory

  • Nicholas Allen's Indigo Blog

    Reading Messages for Validation

    • 2 Comments

    How do I perform XML validation against an entire message? There is a method to read the body of the message but it's only possible to read headers one at a time.

    Although it sounds more complicated than it really is, a straightforward way to read an entire message is to write it instead. With the Message interface, you have more flexibility when writing a message to an XmlWriter than when reading from a generated XmlReader. Exchanging the roles of readers and writers is a common trick used in XML processing.

    Here's a really short example of using an XmlWriter with some seekable storage. I've replaced the validation step with dumping out the contents of the message.

    Message message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "action!", "body");
    MemoryStream stream = new MemoryStream();
    using (message)
    {
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false)) {
    writer.WriteStartDocument();
    message.WriteMessage(writer);
    writer.WriteEndDocument();
    }
    }
    stream.Seek(0L, SeekOrigin.Begin);
    Console.WriteLine(new StreamReader(stream).ReadToEnd());

    Obviously I'm leaving out more details here than just the validation step. For example, you'd probably want to harvest the original message for things like the message version and message properties so that you could reconstruct the message on the other side, rather than just throwing everything away.

    Next time: Importing and Exporting WSDL Annotations

  • Nicholas Allen's Indigo Blog

    Debugging Framework Source

    • 0 Comments

    Other people have told me they're now successfully debugging into .NET Framework source code although I haven't gotten it to work. The program currently doesn't cover WCF although it does give you access to source for many common framework classes that you'll see elsewhere in the call stack.

  • Nicholas Allen's Indigo Blog

    Throwing Exceptions from Service Authorization Manager

    • 2 Comments

    When writing your own service authorization manager, you override the CheckAccess or CheckAccessCore methods to put in your logic for granting access. CheckAccess returns a boolean, which means that the options for expressing yourself are limited. If the result is true, then access is granted. If the result is false, then access is denied.

    However, you can actually be much more expressive if you'd like.

    If you trace through the authorization process a bit, then you'll see that returning false simply translates into the infrastructure throwing an exception. That exception is a FaultException that represents a sender fault for failing to properly authenticate. A little bit of thinking shows that rather than returning true or false, you could instead throw your own fault exception. It turns out that your fault exception does get propagated through, just like the system one, and a FaultException lets you be a lot more verbose than a boolean.

    Other types of exceptions will also get through although I don't recommend getting too adventurous. Being expressive is an advantage for the sender but a liability for the receiver. The receiver actually has to handle what you throw at it and try to do something intelligent with it. As you become more creative as a sender, receivers become less likely to actually do what you want them to.

    Next time: Reading Messages for Validation

  • Nicholas Allen's Indigo Blog

    Controlling Certificate Validation

    • 2 Comments

    How do I configure the validation process for certificates specified in the service credentials section?

    There are several configuration settings for controlling certificate validation although they appear in different places depending on what credentials you're talking about. I'll talk about the settings first and then talk about where they appear.

    The four configuration settings you'll see are:

    • certificateValidationMode for controlling how certificates get validated (ChainTrust/None/PeerTrust/PeerOrChainTrust/Custom)
    • customCertificateValidatorType for specifying the type used by the Custom validation mode ("namespace.typeName, [,AssemblyName] [,Version=version number] [,Culture=culture] [,PublicKeyToken=token]")
    • revocationMode for controlling how the certificate revocation list is checked (NoCheck/Online/Offline)
    • trustedStoreLocation for controlling which system store is checked for negotiated certificates (CurrentUser/LocalMachine)

    Here's where you'll find those settings. All of these XML paths are relative to the serviceCredentials section.

    • When talking about a certificate for the client half of a duplex service, clientCertificate/authentication
    • When talking about a certificate for a custom issued token, issuedTokenAuthentication. Controlling certificate validation through configuration for issued tokens is only available starting with the Orcas release.
    • When talking about a certificate for a peer node, peer/peerAuthentication

    Next time: Throwing Exceptions from Service Authorization Manager

  • Nicholas Allen's Indigo Blog

    WCF Beta Exam Extended

    • 1 Comments

    The beta period for certification exams on the Orcas releases of the foundation technologies (WCF, WPF, and WF) has been extended. Depending on your location you might still be able to grab a seat for next week to take one of these exams. Full details are available here.

  • Nicholas Allen's Indigo Blog

    Custom Cookie Handling

    • 3 Comments

    Cookies are the de facto correlation protocol for web applications, which means HTTP applications rather than SOAP. Most uses of cookies in web services are quite simplistic with the standard cookie container behavior sufficiently up to the task of handling the exchange. Today's article covers the times when the automatic cookie handling behavior is insufficient.

    To get started with custom cookie handling you first need to turn off cookies. This may sound terribly confusing but that's because the AllowCookies property is so badly named. This property controls whether a CookieContainer is setup and used to automatically copy cookies around and set the value of the Cookie header. It should really be called the AutomaticCookieHandling property. You would probably understand what was going on if the instructions said "to get custom control over cookie handling, set the AutomaticCookieHandling property to false". Instead, the instructions say to set the AllowCookies property to false.

    Once you've turned off automatic cookie handling, you have free access to the cookie headers on incoming and outgoing messages using the standard HTTP message properties. Here's some uninteresting code for a client showing bouncing a cookie off of a server.

    using (new OperationContextScope(client.InnerChannel))
    {
    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
    requestProperty.Headers.Add("Cookie", "MyCookie=value");
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
    client.DoOperation();
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name];
    string cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie];
    }

    Code on the server would look very similar with the roles of Cookie and Set-Cookie reversed.

    Next time: Controlling Certificate Validation

  • Nicholas Allen's Indigo Blog

    Flowing Additional Identity Information

    • 4 Comments

    I want to provide some additional information about the user within the client credentials. Can I do this with Windows credentials?

    No. Although you can create custom claims and try attaching them to the credentials, the credentials on the wire only contain the information that's part of the standard Windows token. Any additional information gets lost. The same is true for many other types of credentials that weren't designed for extensibility in the wire format.

    SAML tokens were designed for extensibility and permit attaching additional data. If you've got a mechanism to attach SAML tokens to a message, such as with message security, then you can load the token up with claims and additional identity information and flow the token to the other party. The token helps support the client credentials and other security information. You can read about SAML tokens on MSDN to get started.

    Next time: Custom Cookie Handling

  • Nicholas Allen's Indigo Blog

    Not Omitting the XML Declaration

    • 1 Comments

    Why doesn't a message start with an XML declaration?

    The XML declaration is a processing instruction at the beginning of an XML document that gives information about the format and logical structure of the document. You've probably seen the most commonly used XML declaration on many documents.

    <?xml version="1.0" encoding="UTF-8" ?>
    

    Both the version and the encoding in this example declaration are the default values. XML documents aren't required to start with a declaration because default values are assumed. Processors that are sensitive to the size of the produced document omit the declaration to avoid transmitting redundant information. The text encoder is an example of an XML processor that can recognize when the default values are being used and omit the declaration to save space.

    In some cases you want the XML declaration even when it's unnecessary because the receiver is expecting the document to start with a particular sequence of characters. Since the optimization in the text encoder isn't the result of a configuration setting, some amount of manual work is required to produce messages that contain unnecessary processing instructions. You can recreate this effect using a custom message encoder that is even simpler than the sample custom text encoder. You don't need to support a custom content type or to do any special processing when reading a message. You do need the shell for a message encoder and message encoder factory plus the logic in WriteMessage to insert the processing instruction. The sample writes the processing instruction using XmlWriterSettings although you can choose any method you wish.

    Next time: Flowing Additional Identity Information

  • Nicholas Allen's Indigo Blog

    Custom Password Validation for HTTP

    • 1 Comments
    Phil Henning has written about creating a custom username/password validator for HTTP, which is another new feature in Orcas. Like getting access to client IP addresses, creating a custom password validator is a feature added as a result of direct customer feedback. In fact, the two features were added during the same week and were among the last features we did in Orcas for messaging. Before Orcas you could only create a custom password validator if you were using message security.
  • Nicholas Allen's Indigo Blog

    Suppressing Transactions During an Operation

    • 1 Comments

    Service operations have a declarative attribute for automatically placing the operation within a transaction. Is it possible to do non-transactional work within a transacted operation without having to do everything by hand?

    Yes. This is most easily done by creating a transaction scope that suppresses the ambient transaction. Here's a code example that uses TransactionScopeOption.Suppress:

    using (TransactionScope s = new TransactionScope(TransactionScopeOption.Suppress))
    {
    ...
    s.Complete();
    }

    Creating the transaction scope excludes the contained operations from the ambient transaction but doesn't have any effect if no transaction is present. Calling Complete in this case isn't required but is good form.

    Next time: Not Omitting the XML Declaration

  • Nicholas Allen's Indigo Blog

    Demanding Permissions

    • 2 Comments

    How do I restrict access to an operation to particular Windows users?

    There are three standard ways of doing something in WCF: through code, through attributes, and through configuration. Let's try to solve the problem using each of these methods.

    Restricting access through code is done by creating a custom ServiceAuthorizationManager. Restricting access to a service operation could be done this way by looking up the service operation during the access check and comparing the caller's SID to the list of approved users. This method seems pretty clunky because it brings in a lot of service machinery unrelated to the service operation we want to secure. However, this method also seems pretty flexible because we can be very creative about how the authorization is performed if we want to go beyond simply evaluating membership.

    Restricting access through attributes is done by making PrincipalPermission demands. Restricting access to a service operation could be done this way by decorating the service operation with role or user based demands. The best practice recommends using roles instead of specific users because it helps with administration, which is probably good advice for all of these approaches. Using principal permissions requires actually having the right principal for the current thread. Some extra code may end up being required anyways if the client invocation doesn't propagate the right kind of information.

    Restricting access through configuration is done by setting up an external authorization provider. When in compatibility mode, there is some handy functionality provided by the ASP.NET pipeline to provide authorization integrated with ASP.NET membership providers. Even without ASP.NET though, the generic Authorization Manager can be used to manage and provide roles.

    I like using the attributed-based method but that's because I don't like to type a lot of code and because I rarely need to worry about deploying services on multiple systems. Each of the methods has its own strengths and weaknesses so there isn't a universal choice that's best for everyone.

    Next time: Suppressing Transactions During an Operation

  • Nicholas Allen's Indigo Blog

    What's New in Orcas

    • 2 Comments

    The official list is a little hard to find but here's the overview of the big new WCF features in Orcas.

  • Nicholas Allen's Indigo Blog

    Basing Authorization on the Message Body

    • 2 Comments

    How do I use a field in the message to answer an authorization request in ServiceAuthorizationManager?

    There are two ways to go about doing this. The first makes use of a new feature in Orcas while the other is potentially more flexible and definitely requires more work.

    There’s a new overload for CheckAccess in ServiceAuthorizationManager that gives you a Message instance for the current request. This allows you to access the body contents by reading the message. Reading the message consumes it so you’ll need to replace the message when you’re done. You should be aware that this is going to be a significant speed bump unless you were already buffering messages. Even so, touching the body contents is almost guaranteed to take noticeably longer than you’re used to for performing authorization checks.

    public virtual bool CheckAccess(OperationContext operationContext, ref Message message);

    The other option is to insert a transformation step prior to ServiceAuthorizationManager being invoked. The transformation step takes the contents of the message and extracts the information needed for the authorization decision into a message header or property. This allows you to use ServiceAuthorizationManager exactly as before. Adding the transformation is a lot harder than overriding a method but you can potentially be doing other protocol work at the same time that also uses the contents of the message. You may be able to amortize some of the overhead of touching the message body in this way although in the worst case you’re no better off than with CheckAccess.

    Next time: Demanding Permissions

  • Nicholas Allen's Indigo Blog

    Taking Action on Client Close

    • 1 Comments

    How do I clean up resources on the server when a duplex client closes its half of the connection?

    Duplex services sometimes need to be a little bit more aggressive cleaning up after clients. Unlike with other channel shapes, a duplex client can decide to stop sending requests but continue to receive responses from the server. When that happens, the polite thing for the client to do is to close its half of the connection so that the server knows that no more requests are coming.

    The server has to do some extra work to handle this half close case. Since a half close doesn't permit the server to dispose of the channel or the instance yet, cleanup may need to be split into multiple parts so that the request infrastructure can be torn down sooner. The server also needs some way to detect that a half close is taking place. You can't rely on the client sending a terminating message because the client might time out or decide not to send the message. The server should try to avoid letting client problems tie up resources unnecessarily.

    The IInputSessionShutdown extensibility point allows a service to run code on client disconnection regardless of whether the disconnection was graceful or unexpected. You can insert your code by writing a behavior that adds to the InputSessionShutdownHandlers collection of the DispatchRuntime. There are two methods that will get call backs depending on whether a particular disconnection was graceful or unexpected.

    public interface IInputSessionShutdown
    {
    void ChannelFaulted(IDuplexContextChannel channel);
    void DoneReceiving(IDuplexContextChannel channel);
    }

    In the case of unexpected disconnections it may take some time for the server to realize that the client has disconnected. However, this is better than always having to wait for the full idle timeout to expire.

    Next time: Basing Authorization on the Message Body

  • Nicholas Allen's Indigo Blog

    Accessing the Query String

    • 4 Comments

    How do I get access to the query string of an HTTP request when processing a message?

    The query string isn't one of the properties available on the new WebOperationContext but you can still get access to it through the HTTP request message property.

    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpRequestMessageProperty requestProperty = (HttpRequestMessageProperty)properties[HttpRequestMessageProperty.Name];
    string queryString = requestProperty.QueryString;

    Next time: Taking Action on Client Close

  • Nicholas Allen's Indigo Blog

    Get a Real XML Parser

    • 1 Comments

    Today's post is more observational than informational. Enjoy.

    It's sometimes possible to write XML without having an XML library. If your XML documents are sufficiently similar and templated, then you can craft validly formed XML through little more than string manipulation. The trivial case is where the string is a constant expression and the XML document is actually the same every time through. The more interesting case is where the string has many spots where you can fill-in-the-blank with arbitrary content. Once that content becomes constrained instead of arbitrary, you'll almost always want to make use of an XML library assuming that you want your emitted messages to be validated.

    It's pretty much impossible to read XML without having an XML library. XML simply has too many rules about whitespace handling, processing instructions, character formats, and nested elements to realistically build hand-crafted parsers in an application. A hand-crafted parser likely supports exactly the message that you saw one day looking at the wire but contains numerous bugs that prevent all of the equivalent ways of writing the same message from being accepted. Even seemingly unimportant changes to the network configuration can result in literal changes, such as the text encoding or the division of text into text nodes expected by a DOM. If you want to understand XML, then you'll need to get a real XML parser. Using an XML parser instead of string manipulation is more expensive but if you can't afford this cost, then you probably can't afford the benefits that XML provides either.

    Next time: Accessing the Query String

  • Nicholas Allen's Indigo Blog

    25 Years of TCP/IP on the Internet

    • 1 Comments

    On January 1st, 1983 the ARPANET officially switched over from using NCP (Network Control Protocol) to TCP/IP (Transmission Control Protocol over Internet Protocol). This followed a year where the ARPANET supported a mix of NCP and TCP/IP machines using relay servers that supplied Telnet, FTP, and mail services across the two protocols. While the Telnet and FTP services were very similar between the two protocols, mail service was much improved thanks to the recently developed SMTP standard. Before that, mail messages were moved around using a protocol on top of FTP. Although NCP only lasted about 12 years, TCP/IP has lasted more than twice as long with no signs of going away any time soon.

Page 1 of 1 (22 items)