January 2012 - Posts
Today I answered a question in the Hebrew MSDN forums about consuming WCF from a .NET 2 client, using the “Add Web Reference” option of Visual Studio.
Just in case you don’t know Hebrew I’ll sum it up for you – when adding a web reference to a WCF service that exposes a method of the following sort:
int UseScalarTypes(int value1, int value2)
The generated method signature in the client app will look like so:
public void UseScalarTypes(
int value1, bool value1Specified,
int value2, bool value2Specified,
out int UseScalarTypesResult, out bool UseScalarTypesResultSpecified)
The question was why this happens and how this can be fixed to look like the service’s method signature.
Before we continue to see why this happens and how to fix it, the short answer is – Yes, you can make it look like the original contract by using message contracts. Continue reading to see how.
Why this happens:
In WCF the WSDL generated for the above method looks like so:
<xs:element name="UseScalarTypes">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="value1" type="xs:int" />
<xs:element minOccurs="0" name="value2" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
Notice the minOccurs? int is a value type which means it doesn’t accept null values, but still WCF marks it as optional. When you use the “Add Service Reference” option of WCF in Visual Studio, the generator ignores that attribute and creates the method declaration in the client side the same way it is declared in the service contract. However, if you use the old “Add Web Reference” option, the generator checks the minOccurs, realizes that the variable is optional, and since this is a value type, it translates the optional into a set of variables: value + xxxSpecified.
By the way, this is how the WSDL is created for the same method declaration when it is used in an ASMX-style web service:
<s:element name="UseScalarTypes">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="value1" type="s:int" />
<s:element minOccurs="1" maxOccurs="1" name="value2" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
Note 1: With ASMX web service, the minOccurs/maxOccurs is set properly because the “Add Web Reference” expects that, and therefore we don’t see this behavior with ASMX web service + add web reference.
Note 2: Since WCF ignores the minOccurs, using the “Add Service Reference” to consume that ASMX web service will result in a client-side method with the same signature as declared in the service (without the xxxSpecified).
So now that we know why this happens, let’s see how to fix it.
Step 1: Create a set of message contracts, one for the request and one for the response (if you have one).
Step 2: In the request message contract class, apply the MessageContract attribute and set the IsWrapped parameter to false, like so:
[MessageContract(IsWrapped = false)]
public class UseScalarTypesRequest
Setting the IsWrapped to false will create the XML without a wrapping element, making the properties look like they are actually method parameters.
Step 3: Add each parameter of the method to the class as a property, and apply the MessageBodyMember attribute to it. You can use this step to rename the property to use the naming convention of parameters by using the Name parameter in the attribute. The result should look like so:
[MessageContract(IsWrapped = false)]
public class UseScalarTypesRequest
{
[MessageBodyMember(Name = "value1")]
public int Value1 { get; set; }
[MessageBodyMember(Name = "value2")]
public int Value2 { get; set; }
}
Step 4: Do the same for the response message contract, this time you just need one property for the return type of the method, for example:
[MessageContract(IsWrapped = false)]
public class UseScalarTypesResponse
{
[MessageBodyMember]
public int Result { get; set; }
}
Step 5: Change the method signature in the contract and service from using parameters to using the message contracts you’ve created, like so:
UseScalarTypesResponse UseScalarTypes(UseScalarTypesRequest parameters)
Of course the immediate step will be to also change the implementation of your code to reflect the parameters being moved to a wrapper object - for convenience, you can leave your existing code in the service as is, change the contract, and then create the new methods which will simply call the older ones, like so:
UseScalarTypesResponse UseScalarTypes(UseScalarTypesRequest parameters)
{
UseScalarTypesResponse result = new UseScalarTypesResponse();
result.Result = UseScalarTypes(parameters.Value1, parameters.Value2);
return result;
}
That’s it, update your web reference in the client side, and watch how the method signature in the client side is without the xxxSpecified.
לפני מספר חודשים נפתחו באתר מיקרוסופט MSDN ישראל פורומים לפיתוח ו-IT. בחודש האחרון חל שינוי בפורומים, בקטלוג שלהם, וברשימת מנהלי הפורומים. כחלק מהשינוי אני שמח לבשר לכם על פתיחתו של פורום חדש לתחום הווב בניהולם של שלמה גולדברג (הרב דוטנט) ועבדכם הנאמן.
בפורום ננסה לתת מענה לשאלות בנושאי פיתוח לעולמות הווב של מיקרוסופט – ASP.NET, ASP.NET MVC, Web Services, WCF, IIS, HTML/JS ועוד.
להבדיל מהפורומים של MSDN, הפורומים במיקרוסופט ישראל מיועדים לקהל הישראלי, כתובים בעברית, ומעודדים כתיבה בעברית של שאלות ותשובות.
למה בעברית? למה פורומים נוספים על אלו של MSDN? ובכן:
1. אנחנו לא היחידים – להרבה מדינות יש פורומים מקומיים, בשפה מקומית, שמיועדים לקהל המקומי.
2. עברית כשפת אם - לחלקנו קל להתבטא יותר בעברית במקום באנגלית. אני מכיר מפתחים מצויינים שעדין משתמשים בבודק איות לפני שליחת מייל באנגלית. כתיבה בעברית גם מאפשרת גישה לפורומים לקהל היותר צעיר של מפתחים.
3. יצירת קהילה – השתתפות בפורום תאפשר שיתוף פעולה יותר הדוק בין הקהל הישראלי והנציגים בארץ של מיקרוסופט. דרך הפורום נוכל ליידע אתכם על הרצאות בבתים פתוחים, כנסים בארץ,קורסים והכשרות. במקרים מסוימים ייתכן ואף נוכל לבצע אסקלציה של שאלות לגורמים במיקרוסופט ישראל ואף יותר מכך.
לצערנו, עד כמה שנרצה, פורום לא יכול להסתמך אך ורק על המנהלים שלו שיענו, ולכן ההשתתפות שלהם חיונית להצלחת הפורום. אז גם אם אין לכם שאלה ספציפית, אתם מוזמנים להכנס לפורום מדי פעם, להגיב על שאלות, ללמוד משאלות של אחרים, וגם לספר לנו על משהו מעניין שמצאתם שאולי יכול לשמש אנשים אחרים. אם אתם נוהגים לעבוד עם RSS, אתם מוזמנים להוסיף את לינק ה-RSS של הפורום לרשימות שלכם.
אז נתראה בפורום, בבלוג, בטוויטר ובאירועים השונים השנה.
As promised in my previous post, I’m continuing my mission to inform you of new changes in WCF 4.5.
This is the ninth post in the WCF 4.5 series. This post continues the previous posts on web-hosting features, and this time it is about the improved streaming capabilities of WCF when it is hosted in IIS.
Previous posts:
1. What’s new in WCF 4.5? let’s start with WCF configuration
2. What’s new in WCF 4.5? a single WSDL file
3. What’s new in WCF 4.5? Configuration tooltips and intellisense in config files
4. What’s new in WCF 4.5? Configuration validations
5. What’s new in WCF 4.5? Multiple authentication support on a single endpoint in IIS
6. What’s new in WCF 4.5? Automatic HTTPS endpoint for IIS
7. What’s new in WCF 4.5? BasicHttpsBinding
8. What’s new in WCF 4.5? Changed default for ASP.NET compatibility mode
If you’ve ever tried creating a WCF service that uses streamed requests (for example a file upload service) and host it in IIS, you may have noticed a strange behavior in your WCF service – it would seem that WCF is late in receiving the request, as if it was entirely loaded into the memory, and then passed to WCF. So is it streamed? or is it actually buffered? well, it’s both.
When you host a WCF service in IIS you also get a bit of the ASP.NET pipeline on the side, even if you don’t use the ASP.NET compatibility mode, this is documented in the WCF Services and ASP.NET article on MSDN (look for the part about the PostAuthenticateRequest event). In .NET 4, there is a design flaw in ASP.NET which causes the requests sent to WCF to be buffered in ASP.NET. This buffering behavior causes several major side-effects:
1. There is a latency between the time the streamed message is received by ASP.NET and the time the WCF service method is actually invoked.
2. There is some memory consumption due to the buffering – the exact amount of memory consumed depends on the size of the message sent by the client, but it can even get to several hundred MBs if you increase the MaxRequestLength of ASP.NET, the MaxAllowedContentLength of IIS 7, and of course the MaxReceivedMessageSize and MaxBufferSize of WCF.
3. When ASP.NET buffers the request, it uses both memory and disk. The requestLengthDiskThreshold configuration setting of ASP.NET controls when ASP.NET starts to use the disk. If you upload multiple files to WCF at once, you will start to see some delays due to multiple files being written to the disk at once. BTW, the files are written to an “upload” folder under the web application’s temporary asp.net folder (under c:\windows\Microsoft.NET\Framework\vX.X.XXXX\Temporary ASP.NET Files\) and are removed after the request is handled.
To show this behavior, I have created a client application that uploads a 500MB file to a WCF service. The WCF service is hosted in IIS and is set to a streamed request (you can download the StreamingInIIS sample solution from here). The following output shows some information about the time it took for the service to receive and handle the request, and the consumed memory:
1 Client started upload on 17/01/2012 19:03:25
2 Available memory before starting is: 2701MB
3 Client finished upload on 17/01/2012 19:03:44
4 Available memory after finishing is: 2699MB
5 Available memory on ASP.NET is: 2701MB
6 ASP.NET received upload at: 17/01/2012 19:03:28
7 Available memory on WCF is: 2122MB
8 WCF started receiving file at: 17/01/2012 19:03:38
9 WCF finished receiving file at: 17/01/2012 19:03:43
File size is: 524288000
Press any key to continue . . .
Some things to note about these results:
1. Client started / Client finished (line 1+3) – the total time the client waited for the service was 19 seconds; this includes the upload time, the buffering time of ASP.NET, and the time WCF handled the received stream.
2. ASP.NET started receiving the stream 3 seconds after the client began sending it (line 6).
3. WCF started receiving the stream 10 seconds after ASP.NET received started receiving it, and a total of 13 seconds from the time the client started sending it (line 8). In total, it took WCF 5 seconds to read the entire stream from ASP.NET (line 8+9).
4. Before the client sent the message, the available memory in the machine was 2701MB, which is also the available memory when ASP.NET first received the message. By the time WCF got the request and started handling it, the available memory was 2122MB – about 580MB were consumed from the memory for this operation (lines 2, 5, and 7).
5. As for the generated temp file, here is a screenshot of the temporary ASP.NET folder content:

Note: to show the ASP.NET information I used the ASP.NET compatibility mode. You can turn it off in the sample code if you want to verify that the problem also exists when we don’t use the compatibility mode (look at the difference between the time the client sent the request and the time WCF actually started handling the request – there should be a big latency).
So we get that WCF 4 doesn’t handle well streamed content over IIS, but what about WCF 4.5? what has changed?
In WCF 4.5 this just doesn’t happen – with .NET 4.5, ASP.NET doesn’t buffer the request, but rather forwards it directly to WCF, so we don’t get any latency, no memory consumption, and no disk usage.
Want to see some proof? I ran the same demo code in Windows Server 8 with WCF 4.5 over IIS. I used a smaller file size (200MB), since this is a VM with less memory, however you can still see the difference quite clearly:
1 Client started upload on 11/27/2011 7:23:18 AM
2 Available memory before starting is: 942MB
3 Client finished upload on 11/27/2011 7:23:46 AM
4 Available memory after finishing is: 942MB
5 Available memory on ASP.NET is: 941MB
6 ASP.NET received upload at: 11/27/2011 7:23:20 AM
7 Available memory on WCF is: 942MB
8 WCF started receiving file at: 11/27/2011 7:23:20 AM
9 WCF finished receiving file at: 11/27/2011 7:23:46 AM
File size is: 209715200
Press any key to continue . . .
First thing to note – memory consumption hasn’t changed throughout the execution – remains steady at ~942MB (lines 2+4+5+7).
As for the latency – WCF received the request at the same time ASP.NET received it (lines 6+8), which is 2 seconds after the client begins sending it.
Oh, and since ASP.NET passed the stream directly to WCF, no temp file was created !!
So there you have it – proper streaming in WCF 4.5 over IIS.
Stay tuned for more posts about the new features of WCF 4.5. You can also follow me on Twitter (@IdoFlatow) to get updates as soon as new posts are published.
If you’ve been wondering where I disappeared to in the last couple of weeks, and if you are still waiting anxiously for my next post about WCF 4.5, fear not, I’m here, I’m alive, and I’m still kicking.
It’s been quite a rough month, as I have been occupied knee deep in home renovations. If you’ve ever dealt with contractors, technicians, and handyman, you know the type of frustration I’m talking about.
Between re-tiling my floors, replacing my kitchen cabinets, and re-painting my entire home, I also managed to find the time to deliver some courses on Windows Azure, IIS, Advanced WCF, Windows HPC Server, AppFabric Cache, and PowerShell.
2012 is going to be very productive year – this year is going to be a lot about the new releases of .NET 4.5, VS11, and Windows Server 8. I’m guessing you’ll see many more posts about the new features of WCF 4.5 (soon to come – a new post about the new streaming features of WCF 4.5 over IIS), .NET 4.5, and VS11.
I’m also continuing my voyage with BigData solutions which I’ve started last year with my work on the Windows HPC Server 2008 R2, and the new HPC labs we’ve created in Sela for the Windows Azure Platform Training Kit. This year is mostly going to be about Hadoop on Azure, so expect new labs and demos soon on the WAP TK (Windows Azure Platform Training Kit).
This year I will continue to manage the Israeli Web Developer Community (WDCIL) along with Gal Kogman, and in a couple of days I will also start to moderate the WebDev IL MSDN forum with Sholomo Goldberg, AKA the DotNet Rabbi.
I’m also continuing my speaking engagements this year, which ended last year with my sessions at VSLive Redmond and MCT Summit in October and VSLive Orlando in December. Other than my usual appearances at Sela’s SDP conferences in Israel, I will also be speaking this April in the Great Indian Developer Summit (GIDS) in Bangalore (India of course), and hopefully in additional conferences in Europe and the US (more information to come in the next couple of weeks).
So check out for my posts, my tweets, my courses, and my speaking engagements, and don’t forget – if you need me, just turn on the bat signal, and I’ll come to your rescue, just kidding – you can always contact me through my blog, my tweeter account, or send me an email, and I’ll do my best to answer you promptly.
Happy new year to y’all, enjoy the new leap year, and hopefully we’ll still be here to see 2013.