You can expose the service in two different endpoints.
the SOAP one can use the binding that support SOAP e.g. basicHttpBinding, the RESTful one can use the webHttpBinding. I assume your REST service will be in JSON, in that case, you need to configure the two endpoints with the following behaviour configuration
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript/>
</behavior>
</endpointBehaviors>
An example of endpoint configuration in your scenario is
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="json" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="ITestService"/>
</service>
</services>
so, the service will be available at
Apply [WebGet] to the operation contract to make it RESTful.
e.g.
public interface ITestService
{
[OperationContract]
[WebGet]
string HelloWorld(string text)
}
Note, if the REST service is not in JSON, parameters of the operations can not contain complex type.
Reply to the post for SOAP and RESTful POX(XML)
For plain old XML as return format, this is an example that would work both for SOAP and XML.
[ServiceContract(Namespace = "http://test")]
public interface ITestService
{
[OperationContract]
[WebGet(UriTemplate = "accounts/{id}")]
Account[] GetAccount(string id);
}
POX behavior for REST Plain Old XML
<behavior name="poxBehavior">
<webHttp/>
</behavior>
Endpoints
<services>
<service name="TestService">
<endpoint address="soap" binding="basicHttpBinding" contract="ITestService"/>
<endpoint address="xml" binding="webHttpBinding" behaviorConfiguration="poxBehavior" contract="ITestService"/>
</service>
</services>
Service will be available at
REST request
try it in browser,
http://www.example.com/xml/accounts/A123
SOAP request
client endpoint configuration for SOAP service after adding the service reference,
<client>
<endpoint address="http://www.example.com/soap" binding="basicHttpBinding"
contract="ITestService" name="BasicHttpBinding_ITestService" />
</client>
in C#
TestServiceClient client = new TestServiceClient();
client.GetAccount("A123");
Another way of doing it is to expose two different service contract and each one with specific configuration. This may generate some duplicates at code level, however at the end of the day, you want to make it working.
Actually, although I blogged (see Luke's answer), I think this is better than my IDisposable wrapper. Typical code:
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
});
(edit per comments)
Since Use
returns void, the easiest way to handle return values is via a captured variable:
int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
{
newOrderId = orderService.PlaceOrder(request);
});
Console.WriteLine(newOrderId); // should be updated
Best Solution
Typically, you don't have any state between calls. Each call is totally autonomous, each call gets a brand new instance of your service class created from scratch. That's the recommended best practice.
If you need to pass that piece of information (language, settings, whatever) to a second, third, fourth call, do so by passing it in their headers, too. Do not start to put state into the WCF server side! WCF services should always be totally autonomous and not retain any state, if at ever possible.
UPDATE: ok, after your comments: what might be of interest to you is the new
RoutingService
base class that will be shipped with WCF 4. It allows scenarios like you describe - getting a message from the outside and forwarding it to another service somewhere in the background. Google for "WCF4 RoutingService" - you should find a number of articles. I couldn't find antyhing in specific about headers, but I guess those would be transparently transported along.There's also a two-part article series Building a WCF Router Part 1 (and part 2 here) in MSDN Magazine that accomplishes more or less the same in WCF 3.5 - again, not sure about headers, but maybe that could give you an idea.