WCF 响应太长 - 身份验证错误

发布于 2024-08-17 15:53:14 字数 3142 浏览 3 评论 0原文

在我当前工作的项目中,公开了一个 WCF 服务,它返回一个业务实体数组,我们称之为发票:

Invoice[] GetInvoicesByTypeAndTime(InvoiceType invoiceType, byte startHour, byte? endHour);

使用的身份验证机制是 Windows 身份验证,WCF 服务托管在 IIS 6 上托管的 Web 应用程序中 起初,

当我获取超过 64kB 的数据时,会引发 CommunicationException,指出“已超出传入消息的最大消息大小配额 (65536)。要增加配额,请在相应的绑定元素上使用 MaxReceivedMessageSize 属性。”

好吧,我只是在 App.config 中将 maxReceivedMessageSize 和 maxBufferSize 的值增加到 65536000(我在末尾公然添加了三个零)(后者是因为它在 ArgumentException 中抱怨“对于 TransferMode.Buffered,MaxReceivedMessageSize 和 MaxBufferSize 必须是相同的值。 参数名称:绑定元素”)。

现在我可以收到更大的响应...

直到我达到另一个限制(我认为),在 624 个元素(大约 2.2 MB)之后,抛出一个奇怪的异常:

System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'. ---> System.Net.WebException: The remote server returned an error: (401) Unauthorized.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

服务器堆栈跟踪:

   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory factory)
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException)
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

异常重新抛出在 [ 0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Test2.DBS.IDbService.GetInvoicesByTypeAndTime(InvoiceType invoiceType, Byte startHour, Nullable`1 endHour)
   at Test2.DBS.DbServiceClient.GetInvoicesByTypeAndTime(InvoiceType invoiceType, Byte startHour, Nullable`1 endHour) in D:\TEMP\Test2\Test2\Service References\DBS\Reference.cs:line 1445
   at Test2.Program.Main(String[] args) in D:\TEMP\Test2\Test2\Program.cs:line 19

经过身份验证的响应是否有限制? ASP.NET 设置是否有限制?

In the project that I currently work for, there is exposed a WCF service which returns an array of a business entity, let's call it Invoice :

Invoice[] GetInvoicesByTypeAndTime(InvoiceType invoiceType, byte startHour, byte? endHour);

The authentication mechanism used is Windows Authentication, the WCF service is hosted in a Web Application hosted on IIS 6.

At first when I used to get data more than 64kB a CommunicationException was thrown stating that "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."

Fine, I just increased in App.config the values to 65536000 (I blatantly added three zeros at the end) for both maxReceivedMessageSize and maxBufferSize (the latter because it complained in an ArgumentException that "For TransferMode.Buffered, MaxReceivedMessageSize and MaxBufferSize must be the same value.
Parameter name: bindingElement").

Now I could receive larger responses...

Until I hit another limit (I THINK) in that after 624 elements (approx. 2.2 MB) a strange exception is thrown :

System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'. ---> System.Net.WebException: The remote server returned an error: (401) Unauthorized.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

Server stack trace:

   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateAuthentication(HttpWebRequest request, HttpWebResponse response, WebException responseException, HttpChannelFactory factory)
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory factory, WebException responseException)
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Test2.DBS.IDbService.GetInvoicesByTypeAndTime(InvoiceType invoiceType, Byte startHour, Nullable`1 endHour)
   at Test2.DBS.DbServiceClient.GetInvoicesByTypeAndTime(InvoiceType invoiceType, Byte startHour, Nullable`1 endHour) in D:\TEMP\Test2\Test2\Service References\DBS\Reference.cs:line 1445
   at Test2.Program.Main(String[] args) in D:\TEMP\Test2\Test2\Program.cs:line 19

Is there a limit on authenticated responses? Is there a limit from the ASP.NET settings?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一指流沙 2024-08-24 15:53:14

我猜您正在使用 Windows 身份验证,因此会出现 401,而不是一条解释您如何超出消息限制的消息。当您通过 Windows 身份验证请求发送时,WCF 会发送 SOAP 请求两次,一次是失败并返回 Accept 标头,第二次是与 Windows 身份验证标头一起发送。

然而,根据我的测试,如果消息确实发送失败,您似乎仍然会收到 401。

为了解决这个问题,我必须输入服务器跟踪日志记录:

<system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.ServiceModel" switchValue="Critical, Error, Warning">
        <listeners>
          <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="C:\Logs\ServiceTrace.svclog"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

然后,我必须输入更大的读者配额,如上所述(但我使用了较小的值):

然后,您通常必须添加自定义行为以增加对象图中的最大项目数:

<behaviors>
  <serviceBehaviors>
    <behavior name="MaximumItemsBehaviour">
      <dataContractSerializer maxItemsInObjectGraph="2147483647" />
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
      <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>

您需要将“behaviourConfiguration”属性添加到您的“<” ;service>”元素,其值为“MaximumItemsBehaviour”。

我读过但不需要我自己的其他建议是添加:

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpRuntime maxRequestLength="2097151" />
  </system.web>

并且:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="209715200"/>
      </requestFiltering>
    </security>
  </system.webServer>

I'm guessing that you're using Windows Authentication hence the 401 rather than a message explaining how you've blown your message limits. When you send through a Windows Authenticated request, WCF sends the SOAP request twice, once for it to fail and return an accepts header, and the second time to send it with the Windows Authentication headers.

However, from my testing, it looks like you still get the 401 if the message would have actually failed if it did get through.

To troubleshoot this, I had to put server trace logging in:

<system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.ServiceModel" switchValue="Critical, Error, Warning">
        <listeners>
          <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="C:\Logs\ServiceTrace.svclog"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

Then, I had to put in larger reader quotas, as above (but I used smaller values):

Then you generally have to put in a custom behaviour to increase the maximum number of items in an object graph:

<behaviors>
  <serviceBehaviors>
    <behavior name="MaximumItemsBehaviour">
      <dataContractSerializer maxItemsInObjectGraph="2147483647" />
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
      <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>

You'll need to add a "behaviourConfiguration" attribute to your "<system.serviceModel><services><service>" element with the value "MaximumItemsBehaviour".

Other advice I read, but didn't need myself was to add:

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpRuntime maxRequestLength="2097151" />
  </system.web>

And:

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="209715200"/>
      </requestFiltering>
    </security>
  </system.webServer>
岛歌少女 2024-08-24 15:53:14

如果您想要,请查看客户端的 readerQuotas TLDR 版本 - 要查看这是否确实是您的问题,您可以设置最大值 (Int32.MaxValue),如下所示。

<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />

Take a look at readerQuotas on the client side, if you want the TLDR version - to see if this is indeed your issue, you can set the max's (Int32.MaxValue) as shown below.

<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文