I have a WCF service (target .NET 4) and I need to expose 4 endpoints: SOAP, POX, JSON & MEX.
My configuration file looks like this:
<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>
And when I run the service the WCF Test Client returns failed to add service msg with a System.NullReferenceException - object reference not set to an instance of an object and a stack trace:
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[]& outputs)
System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
But the JSON and POX endpoints are accessible and work just fine. On the other hand when I comment them out from the configuration the WCF Test Client properly shows the SOAP service.
At the moment there is only one simple method implemented in the service:
[ServiceContract(Namespace="http://192.168.1.102:8080/")]
public interface IService
{
[OperationContract]
[WebGet]
Tram[] GetOverview(string id);
}
Why do I brake the mex endpoint by adding the pox and json endpoints?
If your aim is to have 1 method to serve for both xml and json i could achieve it as shown below:
<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>
Now in your class that implements the Interface i did the following:
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" } };
}
Now when i perform a get on the above service using Fiddler :
GET http://localhost/XMLService/multipleendpointservice.svc/pox/GetOverview HTTP/1.1
User-Agent: Fiddler
Host: localhost
Accept: application/json
My response is
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"}]
Similarly when i perform :
GET http://localhost/XMLService/multipleendpointservice.svc/pox/GetOverview HTTP/1.1
User-Agent: Fiddler
Host: localhost
Accept: application/xml
My response is :
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>
NOTE: The Accept header can be other than application/xml or application/json. in such cases you need to handle it.
The other alternative is to use the WebServiceHostFactory and use the webHttpEndpoint element that has the automaticFormatSelection attribute to perform the above action
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With