How do I change the HTTP status code of the response that is sent back when using a one-way contract?
The result of using a one-way contract is to automatically send back an empty HTTP response when the service method is called. Sending back this response is independent of executing your service code. This means that the normal method of attaching a message property to set the HTTP status code and other HTTP headers can't be applied. There is no reply channel waiting for you to set up a message with the appropriate properties.
However, there is another mechanism for sending back an empty HTTP response where you do have control over the HTTP headers. When you're using the standard request-reply contract with HTTP, you can manipulate the HTTP message that gets sent back for the reply. On that message you can put an HttpResponseMessageProperty that has SuppressEntityBody set to true. SuppressEntityBody produces equivalent messages to a one-way contract that have HTTP headers but no body contents.
You should think of one-way messages and empty messages as having the same appearance but different semantics during processing. The other way around the problem is to find a lower processing layer to apply your HTTP headers. If you get below the processing layer that knows about one-way messaging, then one-way messages and empty messages are not distinguishable. It is the processing layer that recognizes the one-way protocol that creates the distinction.
Next time: Binary Encodings and Addressing
More than six years after the submission of WSDL 1.1, parts of a new version of WSDL have reached the Proposed Recommendation stage. WSDL is the common definition language for abstractly describing web services. Reviews of the proposal will continue through June 20th.
The core pieces of the standard have a proposed recommendation.
The remaining pieces of the standard will be turned into notes once the core pieces are finished.
I have many tools for measuring and analyzing reader habits. I'm not sure if this is actually a good use of time. I don't think any of the tools give me particularly useful information that I can trust.
For example, MSDN gives me both continuous counts on the number of readers and a monthly sum. The two simply don't agree in any meaningful way. The continuous counts can show a huge increase throughout the month but the monthly total doesn't move significantly and vice versa. I've seen the continuous count be flat for several weeks but the summary number claims that there was significant month-over-month growth.
I've tried external services like Google and Technorati as well to see how they perform. Google has a very slick interface for analyzing data but the data itself is just as suspect as what comes from MSDN. Each data source simply disagrees with all the others about both the magnitude and percentage change. They occasionally don't even agree with each other on the direction of movement. Technorati and Feedburner give me different kinds of data but inspecting that data in context makes me skeptical of its accuracy.
The sampling of demographic data is probably the most correct. When Google tells me the top countries and cities of origin, I think they can do a reasonably accurate job of guessing that information from the traffic data. It's not possible to be completely accurate because they have to infer the information from an IP address and the networking technology involved will introduce uncertainty. These inferences have gotten pretty good over the last few years though because there's a certain amount of locality to the data. Your IP address may not perfectly associate to your hometown but it most likely associates with a geographically nearby location. This bit of noise is irrelevant at a large scale. I care more about distinguishing San Francisco from Paris than San Francisco from Oakland. Of course, the numbers are from an unknown subset of readers but it may seem reasonable to assume that there is no significant bias between the ability to sample and the reader's locale.
In the end, it turns out that the least detailed source of information is the one that I have the most confidence in. The monthly MSDN number gives a single value summing all readers across all pages for all days in the month. It doesn't tell me a thing about who or where those readers are. I have no clue if the magnitude is actually correct. However, the way the number moves over time is the closest to matching the reactions I get from talking to actual people. All of the tools at hand don't make the picture any clearer.
Hey! Call Close on your client proxy objects once you're done using them! This is always a good idea, but it's a tremendously good idea when using sessionful channels. Your client takes up resources on the server until you either close the proxy object or the server reaches the idle timeout for the connection. Resource usage on the server is bounded by server quotas that limit the number of outstanding sessions before additional clients get queued up. The garbage collector will close your proxies once it gets around to it but who knows how long in the future it will be before the garbage collector runs?
Having a well-written client allows you to pack more people on a single server without having to aggressively time out idle clients. Aggressive timeout values will disconnect poorly-written clients but will also disconnect clients that are just slow rather than idle. All you have to do is:
Next time: Just the Headers
After TechEd goes to Orlando, there's still more to come. I hope no one actually has to travel to all the stops. It would be a really long trip.
The following error is one that could be commonplace at any time during the last ten years. "SSPI negotiation has failed". "Login failed for user NT AUTHORITY\ANONYMOUS". My service isn't running as an anonymous user. Why isn't it able to connect?
There is a particular bit of behavior for making network requests that differs depending on whether you're using NTLM or Kerberos for authentication. With NTLM, there are some commonly seen circumstances under which you'll end up running as an anonymous user when you may not have expected to. The general issue is that the service principal being used for the outbound call is not correct for what you're trying to do. The specific issue can vary. For example, your service may have impersonated the client caller before trying to make an outbound connection. If you don't have explicit credentials to use for the service and you don't have permission to delegate the client credentials, then you'll have a null user session associated with the call. As another example, your service may be running as a local system account and trying to make an outbound call. NTLM doesn't support using this highly privileged machine account remotely so if you don't have explicit credentials to use for the service, then you will again end up as an anonymous caller.
Next time: Close Your Proxies
Here's a selection of webcasts over the next two weeks that I thought you might be interested in. The majority of these are going to be done in association with the online presence of TechEd this year.
MSDN Webcast: Applying Service-Orientation to Your Development Process (Level 300)
Tuesday, June 5, 2007
7:15 A.M. - 8:30 A.M. Pacific Time
MSDN Webcast: How to Select the Right Combination of Microsoft Office SharePoint Server, Windows Workflow Foundation, and BizTalk for All Your Workflow and Orchestration Needs (Level 300)
Thursday, June 7, 2007
5:00 A.M. - 6:15 A.M. Pacific Time
MSDN Webcast: A Lap around Microsoft Visual Studio Code Name "Orcas" (Level 200)
Monday, June 4, 2007
7:30 A.M. - 8:45 A.M. Pacific Time
MSDN Webcast: .NET Framework 3.0 End-to-End: Putting the Pieces Together (Level 300)
2:30 P.M. - 3:45 P.M. Pacific Time
MSDN Webcast: Building Microsoft Windows Communication Foundation and Windows Workflow Foundation Applications with Microsoft Visual Studio Codename "Orcas" (Level 300)
Wednesday, June 6, 2007
MSDN Webcast: ASP.NET AJAX Client Libraries: Development Tips and Tricks (Level 200)
Tuesday, May 29, 2007
9:00 A.M. - 10:00 A.M. Pacific Time
MSDN Webcast: ASP.NET AJAX Client Libraries: Session Review (Level 200)
Thursday, May 31, 2007
10:00 A.M. - 11:00 A.M. Pacific Time
MSDN Webcast: A Lap Around SilverLight (Level 300)
1:45 P.M. - 3:00 P.M. Pacific Time
Since we've spent some time talking about what doesn't work with serializers, let's look at some techniques for using an alternative serializer that I believe do work. At least, I don't know of a reason why these techniques don't work. You may find a reason why one of these doesn't work. If so, I'd be interested in knowing what goes wrong.
Next time: Security Failures as SYSTEM
Last time on the topic of serialization, we were looking at some issues with commonly replicated sample code for preserving object references. Another bit of serializer sample code that gets linked to frequently is Aaron Skonnard's article on an attribute-based method for replacing DataContractSerializer with NetDataContractSerializer. The issue with this code is much more subtle and harder to correct.
The basic premise of the sample is to build a behavior that gets tagged onto operations via an attribute. That behavior then replaces the standard serializer with NetDataContractSerializer at runtime. Let's look at the piece that actually does the replacement.
public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy) { ReplaceDataContractSerializerOperationBehavior(description); } public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch) { ReplaceDataContractSerializerOperationBehavior(description); } private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description) { DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); if (dcsOperationBehavior != null) { description.Behaviors.Remove(dcsOperationBehavior); description.Behaviors.Add(new NetDataContractSerializerOperationBehavior(description)); } }
When the behavior executes on the client or server, the ReplaceDataContractSerializerOperationBehavior method is run. That method fishes the old serialization behavior out of the description and replaces it with a behavior for NetDataContractSerializer. The issue here is that we are modifying the service description from within ApplyClientBehavior and ApplyDispatchBehavior. Although the service description is still mutable at this time, modifying the description has undefined behavior. This is called out in the documentation for using behaviors. Other bits of service description code may have already run that have no way to be fixed up when the behavior is swapped out.
Next time: Replacing the Serializer, Part 3
When I was doing release announcements a few weeks ago I meant to include some of the video interviews related to the projects in addition to the project descriptions and download links. Better late than never.
Can I get the IP address of a client connecting to my service?
No. Sorry. In most cases this information is not available. Exposing such functionality is left to the transport to be done in an implementation-specific manner. The most popular transports we supply out of the box do not offer this. You can ask the client to supply that information as part of its identity, although you need a way of making sure that the client isn't lying before taking action based on the IP address. However, it is possible under some circumstances for the client to lie about its address even when you can directly query the socket.
A natural progression from yesterday's article about creating a new serializer is to put that serializer into the message processing pipeline. There have been several people that have already described how to do this. It's evidently not too uncommon. First though, I want to correct some recurring issues I've seen with these demonstrations.
The earliest writing that talks about the current model for replacing the serializer is by Sowmy. At least, that's the earliest writing that I know about. I'm pretty sure that Sowmy is just writing some really quick sample code here to illustrate the point. However, I've seen that same code copied elsewhere, such as Ingo Rammer's MSDN article on migrating to WCF. If you look at the snippet of code, you may notice a few issues.
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes) { return CreateDataContractSerializer(type, name, ns, knownTypes); } private static XmlObjectSerializer CreateDataContractSerializer(Type type, string name, string ns, IList<Type> knownTypes) { return CreateDataContractSerializer(type, name, ns, knownTypes); } public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes) { return new DataContractSerializer(type, name, ns, knownTypes, 0x7FFF /*maxItemsInObjectGraph*/, false/*ignoreExtensionDataObject*/, true/*preserveObjectReferences*/, null/*dataContractSurrogate*/); }
The first issue is that the overload taking string parameters isn't going to work. It just calls itself in an infinite loop. The second issue is that creation of the DataContractSerializer has substituted defaults for many of the parameters rather than passing through the settings of the behavior. The code should look more like this:
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes) { return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate); } public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes) { return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate); }
Next time: Replacing the Serializer, Part 2
How do I write out an object that contains a reference to itself?
Using the default options with the standard serializer for data contracts gives you a configuration where object references are replaced by an actual instance of the object being referenced. In essence, the data contract serializer expands object references into copies of the original object. Implementing object references by making a copy solves one of the problems of contract-based data transfer- describing an object reference requires a description language that is a level abstracted from the user-controlled description of the data contents. After all, there are some pretty flexible description languages, like XML, that don't include object references in their minimal, core definitions.
Implementing object references by making a copy also creates a problem for data transfer- every time we want to insert a reference to an object, we have to make a whole new copy of that object. For some cases, that is simply wasteful. For other cases, such as circular object references, a copy-on-reference policy is entirely unworkable. The copy approach leads to an object graph of infinite size whereas the reference approach leads to an object graph of finite size. Clearly, that is a situation where we would prefer implementing object references with object references despite the other consequences.
WCF supports both copying and preserving object references. The default data contract serializer uses copies to implement object references. If you want to use object references to implement object references, then you can toggle the PreserveObjectReferences setting when creating the serializer to enable this behavior. Each serializer is free to solve this problem in its own way. For example, although DataContractSerializer defaults to copying references, the NetDataContractSerializer defaults to preserving references.
Next time: Replacing the Serializer
Larry Osterman has written about the collection of small gifts that were given to people who worked on Windows Vista. WCF was included as a Windows component but we've been lagging behind on the gifts. They have been trickling in for a few months now. This week though, everything is good as we are caught up. Here is the gift list:
How do I control the generation of XML processing instructions during serialization?
XML processing instructions include the little bits at the top of an XML document that are meant to describe how the XML document is to be handled. These processing instructions are a way to pass information to the parser that is outside the scope of the prescribed structure of the document. However, it is not uncommon to want to suppress processing instructions. For example, many applications that perform text manipulation on the XML document deal poorly with this extra information. A particular stumbling block is the XML declaration at the start of the document since that is the most common processing instruction that an XML generator might provide by default.
When using an XmlSerializer, you can disable the XML declaration by providing a customized XML writer to the serializer. The serializer takes an instance of the writer when calling the Serialize method. The writer takes an instance of XmlWriterSettings when the writer is created. And finally, the writer settings include a setting controlling the generation of the XML declaration.
XmlWriterSettings settings = new XmlWriterSettings();settings.OmitXmlDeclaration = true;XmlWriter writer = XmlWriter.Create(output, settings);serializer.Serialize(writer, data);
Next time: Serializing Object Graphs
WCF supports message transfers using either a streamed or buffered data model. A buffered model uses contiguous blocks of memory to store the data. A streamed model provides an extra layer of indirection to buffers. The streamed model uses an interface for reading and writing portions of the data to buffers but abstracts the data storage. Working with streamed data is more complicated than working with buffered data but the benefit is that the streamed data model does not have to fit the data into a contiguous block of memory. The streamed data model is free to use multiple blocks, multiple types of stores, or just throw away parts of the data once they're no longer needed.
Most of the data access methods in WCF hide the distinction between buffering and streaming by offering both data models regardless of the native underlying model. However, as a user of the data model, you should care about the underlying model even though the API doesn't seem to make it a big deal. If you treat a large streamed message like it was buffered, then you are basically losing the advantages of having streamed the content.
The ToString method on the other hand is ambiguous about its treatment of streamed messages. Normally, asking to read the complete contents of a streamed message would result in buffering. Although there is no contract for what ToString produces, it would be unexpected to perform a tremendous amount of work, such as this buffering. Therefore, calling ToString on a standard streamed message skips over the contents of the message. This also allows ToString to work without consuming the contents of the message and requiring that you make a copy of the message beforehand.
Some people want to always see the contents of the message in ToString because they're using the ToString output for some purpose, such as message logging. I have seen suggestions that calling CreateBufferedCopy works around this difficulty because ToString gives you the whole message when the message is buffered. These suggestions are incorrect. Despite the name, CreateBufferedCopy isn't guaranteed to give you a buffered message or a message that you can ToString in this way. The contract of CreateBufferedCopy is to create a MessageBuffer from which you can stamp out many copies of the message contents. There are no promises about whether those stamped messages will be buffered or streamed. The correct way to read all of the contents of a streamed message is to read all of the contents. For example, attach an XML reader to your copy of the message and keep calling read until the message is done. There is no shortcut around consuming the message.
Next time: XML Processing Instructions
Today's post was supposed to be a response to the article last night by Jeff Atwood on programming quotations. Evidently I screwed things up by trying to insert it too close to the regular posting time. Since this is an off-topic post, I'll just run it late rather than waiting for tomorrow.
Jeff Atwood put up an article last night about quotes and influencers in the field of computer science. It's mostly a modern (last 15 years) collection so I thought I'd point to the original quote machine, Alan Perlis. Perlis was an early researcher in the field of computing with the US Army and received the first ACM Turing Award in 1966. In 1982 he published a collection of epigrams about his experiences in computing. Some of them are funny, some of them are serious, but there's almost always something of value you can pull out of each.
For instance, these two make a nice description of a certain battle that has been going on for the last few years:
Around computers it is difficult to find the correct unit of time to measure progress. Some cathedrals took a century to complete. Can you imagine the grandeur and scope of a program that would take as long?
Is it possible that software is not like anything else, that it is meant to be discarded: that the whole point is to see it as a soap bubble?
How can I speed up message processing when using MSMQ with WCF?
For small gains, it is generally possible to eke out a few percentage points of performance by tuning parameters and settings according to the application domain knowledge you have. For large gains, you are likely going to have to think about larger design issues. In particular, a type of design issue that you should consider in your quest for large gains is to question what features are truly needed to build your application.
This article is about a few of those feature decisions that you can make when using MSMQ together with WCF. Since these design decisions require building your application with a restricted set of features, there's no guarantee that these techniques are going to be applicable for you. It really just depends on the queue features you need versus the features you don't. I'm not going to mention features not primarily related to the queue, such as whether to use message security, although obviously the same type of analysis can be applied.
Next time: Streaming and ToString
The simplest programming patterns are those that don't require a lot of thought to apply the pattern. The way that you can get to one of these simple programming patterns is to smooth out the rough edges until almost every interesting case can be handled by a direct application of the pattern. The client communication objects that you commonly use with WCF have one of these simple patterns.
try{ // Use the thing ... thing.Close();}catch (TimeoutException){ thing.Abort();}catch (CommunicationException){ thing.Abort();}
I refer to this as the Try-Catch-Abort pattern because that's the distinctive sequence of elements that appear in the code. The normal path is for client objects to be used for a while and then gracefully closed. The abnormal path is for something to go wrong with the client object. Once the client object is no good, it is no longer possible to perform a graceful close. Instead, it is mandatory to perform an ungraceful shutdown by aborting the client object.
However, what does it mean for the client object to not be good? There are two classes of expected exceptions to come out of client objects: TimeoutException and CommunicationException. There are unexpected exceptions that can come out of client objects but you shouldn't try to handle those because they weren't expected. Even the expected exceptions are things you can't handle unless you know something more specific about what went wrong. You need more information, such as recognizing a specific exception type, before you can understand the semantics of the exception, such as whether trying again is likely to succeed.
There is a particularly useful bit of information that you can look at in this case but I see very few people doing it in their programs. That useful bit of information is to look at the State property of the communication object. The state of a functional communication object is Opened. This is the only state where sending messages is valid. Every other state indicates that the communication object is not currently functional. When deciding how to treat the object after an exception, examining the communication state is a crucial data point for making that decision. Not every exception will invalidate the communication object. However, once a client object is no good, there is nothing you can do with it but abort it and throw it away.
Next time: Optimizing MSMQ
It feels like there have been a lot of these announcement posts lately, but that's because a lot of software is getting released. This online release of the Orcas samples should take care of everything relevant to WCF developers that has come out in the last week. My understanding is that you should use the online version of the samples in preference to other sources, such as the Orcas install download.
There are quite a few readme issues related to the samples. You can get all of the details about these issues from my earlier post on the Orcas release.
Astoria and Jasper are two project announcements that have been somewhat overshadowed by all the attention that Silverlight is getting. Both projects are related to ADO and data services although they have a very different focus. Astoria is a service framework for mapping a data model to HTTP operations in a standard way. Jasper is a development aid for building interactive applications that expose a data model. Both have a CTP out at MIX.
After an earlier article about receiving messages, Kenny Wolf suggested that I talk about the exception model for TryReceive. As you'll recall, Receive works by waiting for a message and then throwing an exception if no message arrives. TryReceive uses a softer failure model, where the failure to receive a message does not result in an exception. If no message arrives during the call to TryReceive, then that is indicated with a boolean return value from the method. This failure model doesn't mean that TryReceive will never throw an exception. If a message arrives but it is malformed and cannot be processed, then a boolean return value is not rich enough to describe that (remember, the return value only tells us whether or not a message arrived). In that case, TryReceive will throw an exception just like any other variation of the Receive method. You can apply the same reasoning to BeginTryReceive and EndTryReceive to figure out how those methods must work compared to BeginReceive and EndReceive.
Next time: The Try-Catch-Abort Pattern