【问题标题】:How to override WebServiceHostFactory MaxReceivedMessageSize?如何覆盖 WebServiceHostFactory MaxReceivedMessageSize?
【发布时间】:2012-01-13 21:57:01
【问题描述】:

那里有很多类似的问题,但我已经尝试了每个解决方案,但都无济于事。

我们有一个使用 WebServiceHostFactory 初始化的 Web 服务,但如果向它抛出超过 64k 的数据,我们会收到“400 Bad Request”。通常,这可以通过提高 MaxReceivedMessageSize、MaxBufferSize 和 MaxBufferPoolSize 来解决。问题是使用 WebServiceHostFactory,Web.Config 被完全忽略。我在 ServiceModel 部分所做的任何更改都没有反映在服务中。

完全放弃 WebServiceHostFactory 并从头开始设置 web.config 会很好,但是没有它我们的服务将无法运行。其中一种方法具有流参数以及其他一些字符串参数。没有工厂,我们得到 ​​p>

System.InvalidOperationException: For request in operation Test to be a stream the operation must have a single parameter whose type is Stream

因此,删除工厂不是一种选择。我无法确切知道工厂正在做什么来修复这个错误,但我花了 4 天的时间解决了这个问题,却一无所获。

我也尝试过以编程方式覆盖 MaxReceivedMessageSize,并附上一些我在该地方找到的示例:

protected override void OnOpening()
        {
            base.OnOpening();
            foreach (var endpoint in Description.Endpoints)
            {

                //var binding = endpoint.Binding as WebHttpBinding;
                //if (binding != null)
                //{
                //    binding.MaxReceivedMessageSize = 20000000;
                //    binding.MaxBufferSize = 20000000;
                //    binding.MaxBufferPoolSize = 20000000;
                //    binding.ReaderQuotas.MaxArrayLength = 200000000;
                //    binding.ReaderQuotas.MaxStringContentLength = 200000000;
                //    binding.ReaderQuotas.MaxDepth = 32;
                //}


                //var transport = endpoint.Binding.CreateBindingElements().Find<HttpTransportBindingElement>();
                //if (transport != null)
                //{
                //    transport.MaxReceivedMessageSize = 20000000;
                //    transport.MaxBufferPoolSize = 20000000;
                //}


                var newTransport = new HttpTransportBindingElement();
                newTransport.MaxReceivedMessageSize = 20000000;
                newTransport.MaxBufferPoolSize = 20000000;
                endpoint.Binding.CreateBindingElements().Add(newTransport);
            }
        }

第一个不起作用,因为工厂创建了一个不能转换为 WebHttpBinding 的 CustomBinding。第二个不起作用,因为绑定元素似乎是只读的 - 无论我将元素设置为什么,都没有任何变化,我通过在“更改”它们后读回值来验证这一点。第三次是最后一次尝试在其中添加一个新的绑定元素,但当然也失败了。

现在我们完全不知所措。我们怎样才能让这个东西运行呢?你以为就这么简单!

谢谢大家

Web.Config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <compilation targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="rest" maxReceivedMessageSize="500000000" />
      </webHttpBinding>
    </bindings>
    <services>
      <service name="SCAPIService" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" binding="webHttpBinding" bindingConfiguration="rest" contract="ISCAPIService" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
</configuration>

编辑,使用迄今为止不成功的建议修复:

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 ApplyConfiguration()
        {
            base.ApplyConfiguration();
            APIUsers.TestString += "here" + Description.Endpoints.Count.ToString();
            foreach (var endpoint in this.Description.Endpoints)
            {
                var binding = endpoint.Binding;
                APIUsers.TestString += binding.GetType().ToString();
                if (binding is WebHttpBinding)
                {
                    var web = binding as WebHttpBinding;
                    web.MaxBufferSize = 2000000;
                    web.MaxBufferPoolSize = 2000000;
                    web.MaxReceivedMessageSize = 2000000;
                }
                var myReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas();
                myReaderQuotas.MaxStringContentLength = 2000000;
                myReaderQuotas.MaxArrayLength = 2000000;
                myReaderQuotas.MaxDepth = 32;
                binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null);
            }
        }
    }

    class MyWebServiceHostFactory : WebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new MyServiceHost(serviceType, baseAddresses);
        }
    }

【问题讨论】:

    标签: wcf rest wcf-binding maxreceivedmessagesize webservicehost


    【解决方案1】:

    如果您正在实现自己的自定义服务主机,您应该能够覆盖一个名为“ApplyConfiguration”的方法,您可以在其中关联绑定所需的所有配置属性。部分示例代码如下所示:

    编辑:添加我的服务主机工厂实现

    public class MyServiceHost : System.ServiceModel.ServiceHost
    {
        public MyServiceHost () { }
    
        public MyServiceHost (Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
        {
    
        }
    
        public MyServiceHost (object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
        {
    
        }
    
    protected override void ApplyConfiguration()
                {
                    Console.WriteLine("ApplyConfiguration (thread {0})", System.Threading.Thread.CurrentThread.ManagedThreadId);
                    base.ApplyConfiguration();
                    foreach (ServiceEndpoint endpoint in this.Description.Endpoints)
                    {
                        Binding binding = endpoint.Binding;
                        var binding = endpoint.Binding;
                        if(binding is WebHttpBinding)
                        {
                            var web = binding as WebHttpBinding;
                            web.MaxBufferSize = 2000000;
                            web.MaxReceivedMessageSize = 2000000;
                        }
                        var myReaderQuotas = new XmlDictionaryReaderQuotas();
                        myReaderQuotas.MaxStringContentLength = 5242880;
                        binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null); 
                    }
                }
    
    }
    

    上面确实覆盖了您对每个绑定的配置并设置了 MaxStringContentLength。

    public sealed class MyServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
        {
            public override System.ServiceModel.ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
            {
                return base.CreateServiceHost(constructorString, baseAddresses);
            }
    
            protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
            {
                return new MyServiceHost(serviceType, baseAddresses);
            }
        }
    

    现在我的 Service.svc 文件标记是这样的:

    <%@ ServiceHost Language="C#" Debug="true" Factory="Sample.MyServiceHostFactory" Service="Sample.ReaderQuotasService" CodeBehind="ReaderQuotasService.svc.cs" %>
    

    【讨论】:

    • 谢谢拉杰什。不过,这对我来说仍然不太有效-由于某种原因,调用 ApplyConfiguration 时没有端点-因此它甚至从未进入 foreach 循环。由于工厂正在创建所有描述,您将如何让它在 ApplyConfiguration 被触发之前创建端点?
    • 能否贴出你所拥有的工厂代码以提供更多帮助。
    • 当然,我已经用代码更新了问题。声明如下所示: 在我的代码中, APIUsers.TestString 被打印出来,只是为了确保这段代码正在运行。结果是here0(0 =端点计数)
    • 您是否在服务器端的 web.config 中定义了端点?
    • 我已经用我的 Web.config 更新了这个问题,但答案是肯定的。我在某处读到,当您使用 webservicehostfactory 时,servicemodel 部分基本上被忽略了。还要注意声明现在是
    【解决方案2】:

    为了他人的利益,上述答案走上了正确的道路,但其中有很多错误,如果不进行更改将无法正常工作(因此 OP 无法使解决方案正常工作)。使用以下内容,它将为您“开箱即用”。

    注意 - 提供以下所有构造函数并使用工厂中演示的构造函数重载是极其重要的,否则您将收到以下错误消息: p>

    InitializeRuntime 要求对 Description 属性进行初始化。在 CreateDescription 方法中提供有效的 ServiceDescription 或覆盖 InitializeRuntime 方法以提供替代实现

    自定义ServiceHost实现:

    public class CustomServiceHost : ServiceHost
    {
        public CustomServiceHost()
        {
        }
    
        public CustomServiceHost(object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
        {
        }
    
        public CustomServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
        {
        }
    
        protected override void  OnOpening()
        {
            base.OnOpening();
    
            foreach (var endpoint in this.Description.Endpoints)
            {
                var binding = endpoint.Binding;
                var web = binding as WebHttpBinding;
    
                if (web != null)
                {
                    web.MaxBufferSize = 2147483647;
                    web.MaxReceivedMessageSize = 2147483647;
                }
    
                var myReaderQuotas = new XmlDictionaryReaderQuotas { MaxStringContentLength = 2147483647 };
    
                binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, myReaderQuotas, null);
            }
        }
    }
    

    自定义 ServiceHostFactory 实现:

    public sealed class CustomServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            return new CustomServiceHost(serviceType, baseAddresses);
        }
    }
    

    只要类型正确,上面的 Service1.svc 标记就可以工作。我实际上使用这种技术来覆盖 WebServiceHost 并允许更大的 JSON 响应大小,但这些原则也应该适用于 ServiceHost。

    【讨论】:

    • 我不是要覆盖任何绑定属性,而是 +1 关于构造函数和 InitializeRuntime 错误的注释。这正是我想要的!
    • 在 VB .Net 中,我会为构造函数使用 .New() 关键字吗?
    • 非常有帮助。我试图使用ApplyConfiguration() 添加端点行为,但WebServiceHost 直到OnOpening() 才创建它的端点,所以这让我开始了。
    猜你喜欢
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    • 2012-12-17
    • 2020-07-28
    • 2012-02-25
    相关资源
    最近更新 更多