Ошибка ошибочного запроса HTTP при запросе контракта службы WCF

У меня есть служба WCF со следующей конфигурацией:

<system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MetadataEnabled">
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
     </behaviors>
      <services>
          <service behaviorConfiguration="MetadataEnabled" name="MyNamespace.MyService">
              <endpoint name="BasicHttp"
                        address=""
                        binding="basicHttpBinding"
                        contract="MyNamespace.IMyServiceContract" />
              <endpoint name="MetadataHttp"
                        address="contract"
                        binding="mexHttpBinding" 
                        contract="IMetadataExchange" />
              <host>
                  <baseAddresses>
                      <add baseAddress="http://localhost/myservice" />
                  </baseAddresses>
              </host>
          </service>
    </services>
</system.serviceModel>

При размещении службы в WcfSvcHost.exe, если я просматриваю URL-адрес:

http://localhost/myservice/contract

где доступны метаданные службы, я получаю ошибку HTTP 400 Bad Request.

Проверяя журналы WCF, я обнаружил, что при вызове System.Xml.XmlException возникает сообщение: "Тело сообщения не может быть прочитано, потому что оно пусто".
Здесь является извлечением файла журнала:

<Exception>
<ExceptionType>
System.ServiceModel.ProtocolException, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</ExceptionType>
<Message>There is a problem with the XML that was received from the network. See inner exception for more details.</Message>
<StackTrace>
at System.ServiceModel.Channels.HttpRequestContext.CreateMessage()
at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, ItemDequeuedCallback callback)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult result)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<InnerException>
<ExceptionType>System.Xml.XmlException, System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The body of the message cannot be read because it is empty.</Message>
<StackTrace>
at System.ServiceModel.Channels.HttpRequestContext.CreateMessage()
at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, ItemDequeuedCallback callback)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult result)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContext(IAsyncResult result)
at System.ServiceModel.Diagnostics.Utility.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.ListenerAsyncResult.WaitCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
</InnerException>
</Exception>

Если я вместо этого перейду к URL-адресу:

http://localhost/myservice?wsdl

все работает отлично, и я получаю контракт WSDL. На этом этапе я также могу полностью удалить конечную точку метаданных MetadataHttp, и это не имеет никакого значения.

Я использую .NET 3.5 SP1. Кто-нибудь имеет представление о том, что здесь может быть неправильно?

Ответ 1

Я думаю, что выяснил, в чем проблема.

Если я перейду к URL-адресу:

http://localhost/myservice/contract

с помощью приложения WcfTestClient, я могу успешно получить метаданные службы.
Таким образом, ошибка действительно возникает, когда я запрашиваю URL-адрес через веб-браузер.

Ошибка HTTP Bad Request возникает из-за того, что браузер выдает запрос HTTP GET, где содержимое сообщения находится в заголовках HTTP, а тело пусто.
это именно то, о чем жалуется WCF mexHttpBinding!

Чтобы получить контракт на обслуживание через веб-браузер, вам придется явно включить его в поведение службы:

<serviceBehaviors>
    <behavior name="MetadataEnabled">
        <serviceMetadata httpGetEnabled="true" />
    </behavior>
</serviceBehaviors>

URL-адрес для запроса будет затем:

http://localhost/myservice?wsdl

Итак, оказывается, я слишком быстро опубликовал этот вопрос. Тем не менее, я сохраню его в любом случае только для записи.

Ответ 2

Как правило, это проблема с размером оболочки SOAP. Проверьте конфигурацию привязки, чтобы изменить MaxBufferPoolSize, MaxReceivedMessageSize, чтобы обеспечить огромное количество содержимого. Помните, что вы должны изменить как на стороне клиента, так и на стороне сервера.

Другой проблемой является MessageEnconding (другой параметр привязки), убедитесь, что клиент и сервер используют одну и ту же кодировку.

Наконец, проверьте параметры свойств Quotas Reader.

Ответ 3

Я смог исправить проблему "400 Bad Request", переключив службу WCF с запуска Visual Studio Development Server на использование локального веб-сервера IIS (щелкните правой кнопкой мыши по проекту → свойства → веб-вкладка - → в разделе "Серверы" ). Я надеюсь, что это поможет кому-то, потому что мне понадобилось два дня, чтобы понять это.

Ответ 4

У меня возникли проблемы с HTTP 400 при использовании HTTPS-мкс-URL из SvcUtil, в то время как httpsGetEnabled был установлен в true. Сообщение об ошибке было далеко от того, что действительно было проблемой, поэтому я публикую здесь, если кто-то еще сталкивается с той же проблемой.

У меня был собственный сертификат CA (TestRootCA), который был эмитентом сертификата сервера (localhost). На клиенте я импортировал CER файл TestRootCA, но я не импортировал CRL (Список отзыва сертификатов). Похоже, что когда вы используете самозаверяющий ЦС, вы должны также импортировать CRL, иначе аутентификация сервера терпит неудачу странными способами, ни одна из которых не указывает на реальную проблему. Хуже всего то, что ошибка происходит во время установления связи SSL, прежде чем запрос даже достигнет вашей службы, поэтому вы не увидите ошибок в журналах трассировки WCF.

Ответ 5

Если вы не знаете, почему ваш код WCF вызывает ошибку, я настоятельно рекомендую MS Trace Viewer. Это очень полезно при определении таких проблем коммуникации и транспорта. Посмотрите на С# Corner для более подробной информации.