Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
670 views
in Technique[技术] by (71.8m points)

asp.net 3.5 - WCF WebServiceHostFactory MaxReceivedMessageSize configuration

I have a RESTful WCF web service called "Palladium" as a project in my VS2008 solution. It is hosted in an ASP.Net 3.5 Web Application using the WebServiceHostFactory implementation via a page called "Palladium.svc".

My service works in a manner similar to the one explained here, whereby POSTs can be received by the service along with other parameters as defined in the URITemplate.

The service works well, and I can receive posted information and work with it.
My problem occurs when the post data exceeds 65k and I get the following error (obtained using system.diagnostics in the web.config and Microsoft Service Trace Viewer).

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.

Because the service is hosted via the WebServiceHostFactory implementation, the service has default bindings set up for it by the factory. I attempted to override these bindings by providing binding settings and endpoints in the web.config file. When I did this however, I got an error message saying:

System.InvalidOperationException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

For request in operation LogStartingDetails to be a stream the operation must have a single parameter whose type is Stream.

LogStartingDetails is the method I'm calling in my RESTful service.

Obviously the LogStartingDetails method doesn't need to have a single parameter whose type is Stream, as when the factory was creating the bindings for me the service was responding well (or more to the point, it didn't need to have a single parameter when the factory was doing the work for me).

After much research and hitting several brick walls, I decided to create my own class that inherits from WebServiceHostFactory and overrides some of the implementation in order to specify the MaxReceivedMessageSize property on the binding.
When I step through the service creation in my factory class via debug, I can see the transport receiving the new MaxReceivedMessageSize and MaxBufferSize values, but they don't appear to do anything and I still end up getting the same The maximum message size quota for incoming messages (65536) has been exceeded. exception thrown.

Below are examples of my service code. If someone could help me figure out what I'm doing wrong here, it would be much appreciated.

Palladium.svc (hosted in the ASP.Net Web Application)

<%@ ServiceHost Language="C#" Debug="true" Service="CDS.PalladiumService.Palladium" Factory="CDS.PalladiumService.MyWebServiceHostFactory" %>

MyWebServiceHostFactory.cs (in the CDS.PalladiumService project)

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;

namespace CDS.PalladiumService
{
    public class MyServiceHost : WebServiceHost
    {
        public MyServiceHost()
        {
        }

        public MyServiceHost(object singletonInstance, params Uri[] baseAddresses)
            : base(singletonInstance, baseAddresses)
        {
        }

        public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }


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

            if (base.Description != null)
            {
                foreach (var endpoint in base.Description.Endpoints)
                {
                    var transport = endpoint.Binding.CreateBindingElements().Find<TransportBindingElement>();
                    if (transport != null)
                    {
                        transport.MaxReceivedMessageSize = 5242880;
                        transport.MaxBufferPoolSize = 5242880;
                    }
                }
            }
        }
    }
    
    class MyWebServiceHostFactory : WebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost(serviceType, baseAddresses);
        }
    }
}

IPalladium.cs (in the CDS.PalladiumService project)

using System.IO;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace CDS.PalladiumService
{
    // NOTE: If you change the interface name "IPalladium" here, you must also update the reference to "IPalladium" in Web.config.
    [ServiceContract]
    public interface IPalladium
    {
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = UriTemplate.LogStartingDetails)]
        void LogStartingDetails(string truckId, string palladiumId, Stream postData);
    }
}

Palladium.cs (in the CDS.PalladiumService project)

using System.IO;
using System.ServiceModel.Activation;

namespace CDS.PalladiumService
{
    // NOTE: If you change the class name "Palladium" here, you must also update the reference to "Palladium" in Web.config.
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Palladium : IPalladium
    {
        public void LogStartingDetails(string truckId, string palladiumId, Stream postData)
        {
            string contents = string.Empty;
            using (var reader = new StreamReader(postData))
            {
                contents = reader.ReadToEnd();
            }

            StreamWriter sw1 =
                File.AppendText(@"C:log.txt");
            sw1.WriteLine(contents);
            sw1.WriteLine("");
            sw1.Close();

            return;
        }
    }
}

URITemplate.cs (in the CDS.PalladiumService project)

namespace CDS.PalladiumService
{
    public static class UriTemplate
    {
        public const string LogStartingDetails = "/log-starting/{truckId}/{palladiumId}";
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I managed to get this working by setting the 3 settings below on the endpoint binding in the OnOpening method of my WebServiceHost:

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

  foreach (var endpoint in Description.Endpoints)
  {
    var binding = endpoint.Binding as WebHttpBinding;
    if (binding != null)
    {
      const int fiveMegaBytes = 5242880;
      binding.MaxReceivedMessageSize = fiveMegaBytes;
      binding.MaxBufferSize = fiveMegaBytes;
      binding.MaxBufferPoolSize = fiveMegaBytes;
    }
  }
}

I need a large buffer size because I can't enable streaming.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...