Search This Blog

Monday, June 17, 2013

Send Large data with SharePoint Webservice


When ever you need to send lots of lots of data in WCF REST service using custom SharePoint MultipleBaseAddressWebServiceHostFactory then you will encounter following error 

(400) HTTP Bad Request


When you look into service trace you will find the actual root cause of this issue is that the data sent is not supported by default and its failing internally in deserialize process

<ExceptionType>System.ServiceModel.Dispatcher.NetDispatcherFaultException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:ADXML. The InnerException message was 'There was an error deserializing the object of type System.String. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.'.  Please see InnerException for more details.</Message>
<StackTrace>

Now if you try to override the settings in web.config then web service will complain about multiple settings for the same end point because factory it self creates the dynamic end points so web.service changes can't be used unless you remove the factory class and do it conventional way.

So what is the solution :

Its easy that we need to just extend two classes

Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory 
Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHost


 public class CustomMultipleBaseAddressWebServiceHostFactory : Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory
    {
        protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new CustomMultipleBaseServiceHost(serviceType, baseAddresses);
        }

      
    }

    public class CustomMultipleBaseServiceHost : Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHost
    {
        public CustomMultipleBaseServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }


        protected override void OnOpening()
        {
            base.OnOpening();

            System.Diagnostics.Debug.Assert(false);

            foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
            {
                Binding binding = endpoint.Binding;
                if (binding is WebHttpBinding)
                {
                    var web = binding as WebHttpBinding;
                    web.MaxBufferSize = Int32.MaxValue;
                    web.MaxReceivedMessageSize = Int32.MaxValue;
                }
                var myReaderQuotas = new XmlDictionaryReaderQuotas();
                myReaderQuotas.MaxStringContentLength = Int32.MaxValue;
                binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null);
            }
        }
    }

Now if you see we can make the changes to any parameters like maxBufferSize or MaxrecievedMessageSize at the time of opening of channel.

Now instead of using default Microsoft class in the svc file we will use our custom dll reference. Deploy your solution. DO an IISRESET and you will be able to transmit huge data now :)

<%@ ServiceHost Language="C#" 
Service="Custom.Assembly.Classname,$SharePoint.Project.AssemblyFullName$" 
CodeBehind="CustomClass.cs"
Factory="CustomMultipleBaseAddressWebServiceHostFactory, $SharePoint.Project.AssemblyFullName$"  %> 

4 comments:

  1. Gday,
    Your code works beautifully.
    I was getting the following exception trying to upload a file using the default 'Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory':

    System.ServiceModel.ProtocolException: The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.

    I am not sure about the last part of your code where you are setting maxstringcontentlength?
    I was able to upload large files without this being set. And also, why not just set it directly off your 'WebHttpBinding' object?

    Thanks!

    Peter

    ReplyDelete
  2. Peter,

    You can skip that part. Just a precaution to handle bad request.

    Nitin

    ReplyDelete
  3. Thank you so very much... worked for me :D

    ReplyDelete