Silverlight – How to support uploading files larger than 16K in WCF RIA services

3 באוקטובר 2011

תגיות: , , , , ,
3 תגובות

This article applies to the following technologies: Silverlight, WCF RIA, Azure

 

exception1

 

exception2

press here to view live example

Intro

I have written this article after spending some time configuring WCF RIA service in my application. I wanted to create a service which will allow uploading files larger than 16KB. The problem was that Silverlight doesn't handle exceptions in WCF very well, which makes it hard to troubleshoot. In this article I will cover three major exceptions that I had encountered during the implementation.  

In this article I plan to cover the following topics.

  • Section 1 – Revealing the actual exception behind 'HTTP/1.1 500 Internal Server Error' / 'The remote server returned an error: NotFound'.
  • Section 2 – Solving the annoying exception 'The maximum array length quota (16384) has been exceeded while reading XML data…'.
  • Section 3 – Overcoming the exception 'HTTP/1.1 415 Unsupported Media Type' while calling a WCF Silverlight service.

Download Sample

Press here to download demo solution. In this solution you will find a working service as shown above.

Section 1 – Revealing the actual exception behind 'The remote server returned an error: NotFound'

Silverlight fails to report on WCF exceptions correctly. Most of the exceptions being thrown, end up as a with general exception which conceal the actual problem.  Some exceptions can be seen using Fiddler on the client side. A better and more profound way should be logging the details of the actual exception on the server side.

In this section I will show you how to enable WCF logging on the server. I will use some tools that can be found in VS2010.

s1.1 Open the requested project in VS2010.

s1.2 In the upper menu select 'Tools –> WCF service configuration tools'. The tool will be opened.

s1.3 Open the file 'web.config' located in the web project ('File –> Open –> Config file').

s1.4 In the left panel named 'Configuration' expand the node 'Diagnosis'.

s1.5 Enable WCF 'Tracing' as shown in the following image.

image

s1.6 Remember the path of the log file that will be used to store the log entries. In the example above the file path is 'c:\web_tracelog.svclog'. You can leave the default path as is.

s1.7 Save your changes in the tool and return to vs2010. The 'web.config' file should be updated.

s1.8 Run your application and reproduce the exception.

In order to read the log file you will use another tool which has already been installed on your machine as part of the VS2010 installation and is called 'Service Trace Viewer Tool'.

s1.9 Use the Windows explorer to open the log file. The tool is mapped as default for files with extension ‘.svclog’ thus the tool should be opened automatically.

This tool is used to read the log easily. In the ‘Activity’ table each row represents a WCF activity in the server. Rows marked in red indicate that the activity reported an exception. Select the last row marked in red. In the right panel select the message which is also marked in red… 

image

The actual exception should be shown in the tool. Don’t forget to remove the log from the ‘web.config’ file before going to production (Removing can be done by the tool by setting 'Tracing' to off).

Section 2 – Solving the annoying exception “The maximum array length quota (16384) has been exceeded while reading XML data

This exception is raised when trying to send messages in a wcf service larger which are larger than 16KB. In regular WCF usage you are registering the services in the 'web.config'. When using Silverlight WCF RIA you don't register the services because the Silverlight framework performs it for you during run-time using the default configuration. If you want to customize one of the services  (i.e a service which retrieves a file or some other huge chunk of data) you should perform the following steps:

s2.1 Open file 'ServiceReferences.ClientConfig' in the Silverlight application project. This file contains all the services which are used in the Silverlight application. 

s2.2 Create a custom binding as shown in the attached code sample. Modify the sample according to your service information such as service address, contract and binding/endpoint names. The important part in this step is that in lines 3-8 you create a custom binding with the attributes 'maxReceivedMessageSize' and 'maxBufferSize' set to their maximum value. In line 12 you configure the service to use the new custom binding.

<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_ILargeBufferService">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="../Services/LargeBufferService.svc" contract="LargeBufferService.ILargeBufferService"
binding="customBinding" bindingConfiguration="CustomBinding_ILargeBufferService"
name="CustomBinding_ILargeBufferService" />
</client>
</system.serviceModel>

s2.3 Open file 'web.config' in the Silverlight web project.

s2.4 Modify node 'system.serviceModel' to include the following code sample.

<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="LargeBufferServiceCustomBinding">
<binaryMessageEncoding>
<readerQuotas maxArrayLength="2147483647" />
</binaryMessageEncoding>
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" />
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="WCFLargeBuffer.Web.Services.LargeBufferService">
<endpoint address="" binding="customBinding" bindingConfiguration="LargeBufferServiceCustomBinding"
contract="WCFLargeBuffer.Web.Services.ILargeBufferService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>

Where:

  • Lines 3-8 – This is the default behavior and most probably already exists in your file.
  • Lines 11-18 – Define a custom binding whose definitions match those we defined in the Silverlight application project.
  • Lines 23-27 – Define the service which should support the large message size. Notice that the 'address' attribute is empty. The connection to the service is done by mapping the attributes 'name' and 'contract' to the concrete implementation of the service and its interface (contract). In line 24  you configure the service to use the binding which was defined in lines 11-18.

 

Section 3 – Overcoming the exception 'HTTP/1.1 415 Unsupported Media Type' when calling a WCF Silverlight service

This exception is a bit tricky since the exception doesn't indicate the source of the problem. It usually means there's a problem with the way the service is configured.  If you followed section 2 you should not encounter that problem. The solution of this exception  in Silverlight WCF RIA applications is quite simple.

When configuring the service in the 'web.config' file we set the attribute 'address' to be the empty string. This causes Silverlight difficulties in finding the concrete service implementation. This is where conventions come into consideration. You must ensure that the 'name' attribute of the service contains the full namespace of the service concrete implementation (class). I formatted the relevant attribute in bold in the provided sample code (line 1).

<service name="WCFLargeBuffer.Web.Services.LargeBufferService">
<endpoint address="" binding="customBinding" bindingConfiguration="LargeBufferServiceCustomBinding"
contract="WCFLargeBuffer.Web.Services.ILargeBufferService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

Article Recap

In this article I covered 3 known exceptions which many developers dealt with while developing Silverlight WCF RIA services. In addition this article introduced a way to log WCF for troubleshooting handling in section 1.

press here to view live example

Appendix A

This is the full listing of the exception handled in section 2:

There was an error deserializing the object of type WCFLargeBuffer.Web.Services.DoWorkArgs. The maximum array length quota (16384) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 1, position 38134.'.  Please see InnerException for more details.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

3 תגובות

  1. Asif Syed1 בנובמבר 2011 ב 10:58

    Amazing script…It helped me allot.

    הגב
  2. Ashok N1 בנובמבר 2011 ב 11:15

    Excellent … It's works fine !!!

    הגב
  3. Janet25 באפריל 2012 ב 17:03

    Thanks so much, exactly what I needed to fix my problem, plus the tool for debugging. This is great.

    הגב