Как базовые HttpBinding, webHttpBinding и mexHttpBinding могут сосуществовать в одной службе WCF - PullRequest
2 голосов
/ 30 ноября 2011

У меня есть служба WCF (цель .NET 4), и мне нужно предоставить 4 конечных точки: SOAP, POX, JSON & MEX.

Мой файл конфигурации выглядит следующим образом:

<system.serviceModel>
    <!-- bindings -->
    <bindings>
      <basicHttpBinding>
        <binding name ="soapBinding">
          <security mode="None">
          </security>
        </binding>
      </basicHttpBinding>
      <webHttpBinding>
        <binding name="webBinding">
        </binding>
      </webHttpBinding>
    </bindings>
    <!-- behaviors -->
    <behaviors>
      <endpointBehaviors>
        <!-- plain old XML -->
        <behavior name="poxBehavior">
          <webHttp/>
        </behavior>
        <!-- JSON -->
        <behavior name="jsonBehavior">
          <enableWebScript  />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="defaultBehavior">
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="PubtranService.Service" behaviorConfiguration="defaultBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://192.168.1.102:8080/PT/"/>
          </baseAddresses>
        </host>
        <endpoint name="soap"
                  address="soap"
                  binding="basicHttpBinding"
                  bindingConfiguration="soapBinding"
                  contract="PubtranService.IService" />
        <endpoint name="pox"
                  address="pox"
                  binding="webHttpBinding"
                  bindingConfiguration="webBinding"
                  behaviorConfiguration="poxBehavior"
                  contract="PubtranService.IService" />
        <endpoint name="json"
                  address="json"
                  binding="webHttpBinding"
                  bindingConfiguration="webBinding"
                  behaviorConfiguration="jsonBehavior"
                  contract="PubtranService.IService" />
        <endpoint name="mex"
                  address="mex" 
                  binding="mexHttpBinding" 
                  bindingConfiguration=""
                  contract="IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>

И когда я запускаю службу, тестовый клиент WCF возвращает Не удалось добавить службу msg с System.NullReferenceException - Ссылка на объект не установлена ​​для экземпляра объекта и трассировки стека:

System.ServiceModel.Description.ServiceMetadataBehavior.MetadataExtensionInitializer.GenerateMetadata()
System.ServiceModel.Description.ServiceMetadataExtension.EnsureInitialized()   System.ServiceModel.Description.ServiceMetadataExtension.WSMexImpl.GatherMetadata(String dialect, String identifier)   System.ServiceModel.Description.ServiceMetadataExtension.WSMexImpl.Get(Message request)
SyncInvokeGet(Object , Object[] , Object[] )
System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

Но конечные точки JSON и POX доступны и работают просто отлично.С другой стороны, когда я закомментирую их из конфигурации, тестовый клиент WCF правильно показывает службу SOAP.

На данный момент в службе реализован только один простой метод:

[ServiceContract(Namespace="http://192.168.1.102:8080/")]
public interface IService
{

    [OperationContract]
    [WebGet]
    Tram[] GetOverview(string id);

}

Почему я тормозю конечную точку mex, добавляя конечные точки pox и json?

Ответы [ 2 ]

3 голосов
/ 30 ноября 2011

Если ваша цель состоит в том, чтобы иметь 1 метод для обслуживания как XML, так и JSON, я мог бы добиться этого, как показано ниже:

<service name ="XMLService.MultipleEndpointService">        
        <endpoint name="soap" address="soap" binding="basicHttpBinding" contract="XMLService.IMultipleEndpointService" />
        <endpoint name="pox" address="pox" binding="webHttpBinding" behaviorConfiguration="web" contract="XMLService.IMultipleEndpointService" />
        <endpoint name="mex" address="mex"  binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

<endpointBehaviors>
    <behavior name="web">          
      <webHttp/>          
    </behavior>        
 </endpointBehaviors>

Теперь в вашем классе, который реализует интерфейс, я сделал следующее:

public Tram[] GetOverview(string id)
        {
            IList<ContentType> acceptHeaderElements = WebOperationContext.Current.IncomingRequest.GetAcceptHeaderElements();
            for (int x = 0; x < acceptHeaderElements.Count; x++)
            {
                string normalizedMediaType = acceptHeaderElements[x].MediaType.ToLowerInvariant();
                switch (normalizedMediaType)
                {
                    case "application/xml":
                        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Xml;
                        break;
                    case "application/json":
                        WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json;
                        break;
                }
            }

            return new[] { new Tram() { TramName = "Tram 1" }, new Tram() { TramName = "Tram 2" } };
        }

Теперь, когда я выполняю указанную выше службу, используя Fiddler:

GET http://localhost/XMLService/multipleendpointservice.svc/pox/GetOverview HTTP/1.1
User-Agent: Fiddler
Host: localhost
Accept: application/json

Мой ответ

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 79
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 30 Nov 2011 11:39:16 GMT

[{"<TramName>k__BackingField":"Tram 1"},{"<TramName>k__BackingField":"Tram 2"}]

Аналогично, когда я выполняю:

GET http://localhost/XMLService/multipleendpointservice.svc/pox/GetOverview HTTP/1.1
User-Agent: Fiddler
Host: localhost
Accept: application/xml

Мой ответ:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 334
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 30 Nov 2011 11:39:09 GMT

<ArrayOfTram xmlns="http://schemas.datacontract.org/2004/07/XMLService" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Tram><_x003C_TramName_x003E_k__BackingField>Tram 1</_x003C_TramName_x003E_k__BackingField></Tram><Tram><_x003C_TramName_x003E_k__BackingField>Tram 2</_x003C_TramName_x003E_k__BackingField></Tram></ArrayOfTram>

ПРИМЕЧАНИЕ. Заголовок Accept может отличаться от application / xml или application / json. в таких случаях вам нужно справиться с этим.

Другой альтернативой является использование WebServiceHostFactory и использование элемента webHttpEndpoint , который имеет атрибут automaticFormatSelection для выполнения вышеуказанного действия

0 голосов
/ 29 июля 2012

Что ж, простое дублирование конфигурации привязки webBinding с другим именем webBinding2 позволит выставить метаданные.По крайней мере, я попробовал это, и это сработало, хотя странно, что WCF ведет себя так.

    <endpoint name="pox"
              address="pox"
              binding="webHttpBinding"
              bindingConfiguration="webBinding"
              behaviorConfiguration="poxBehavior"
              contract="PubtranService.IService" />
    <endpoint name="json"
              address="json"
              binding="webHttpBinding"
              bindingConfiguration="webBinding2"
              behaviorConfiguration="jsonBehavior"
              contract="PubtranService.IService" />
...