Asked  7 Months ago    Answers:  5   Viewed   27 times

I have a WCF service and I want to expose it as both a RESTfull service and as a SOAP service. Anyone has done something like this before?

 Answers

42

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

  • http://www.example.com/soap
  • http://www.example.com/json

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

  • http://www.example.com/soap
  • http://www.example.com/xml

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.

Tuesday, June 1, 2021
 
Corsair
answered 7 Months ago
77

Introduction

I'm posting this as an answer because comments just don't suffice. Here is what I want to summarize for you.

First, we'll start with these two references:

http://spf13.com/post/soap-vs-rest

http://blog.smartbear.com/apis/understanding-soap-and-rest-basics/

Lastly, I want to start this post off by saying the following:

SOAP and REST were both designed to solve the following problem: how do two disparate applications, programmes or devices interchange and share data between each other, in an extensible and easily-understood manner?


RESTful Services

By design RESTful (Representational State Transfer) services use HTTP and the HTTP verbs (GET, POST, PUT, DELETE) to indicate intent. These verbs very clearly indicate to the user what is going to happen when they are used. The server can use them to make preemptive decisions. That is, it can make a decision long before the action is ready to take place.

Consider this, you have to access a small bit of data from a users Insert Service account. Which is easier, a GET endpoint/users/account/id request, or a POST endpoint/users/account request that has a body of id? By definition of REST, the POST request violates the basic agreement that REST implies. That is: the server is expected to know, before the data has arrived, what intentions with it the user has. This is the basic fundamental that REST attempts to guarantee.

This fact, no, this fundamental, mandates that RESTful communication be permitted to indicate what intention the client has before the client begins to send data. This allows the server to accept and reject messages long before they arrive, thus reducing processing load.

Another aspect of REST (especially with the Twitter, Facebook and Google APIs): RESTful services, with the focus and mandate on HTTP, can take advantage of HTTP response headers. That is, they may respond with an HTTP 403 Forbidden message if the client is not permitted access. SOAP-based services may not. The resulting message must indicate such a result.

RESTful services tend to associate HTTP verbs (or actions) with nouns (or entities/objects.) Generally speaking, plurality and singularity imply more about the action. I.e. GET RootEndpoint/Employees would be expected to return all employees (or at least a large group matching a specific criteria.) Whereas GET RootEndpoint/Employee/12 would be expected to return only one employee. (Generally, Employee with ID 12.)

RESTful services make a direct correlation between the HTTP verb (GET, POST, PUT, DELETE) and the action. This is the purpose of the tie between the two: there is nothing special that needs added to the message body to indicate what the user intends to do. (I'll continue to stress this point throughout.)

REST was designed entirely for HTTP. And it is very good at it's job.

RESTful Filtering

Generally speaking, to filter REST service requests you would include multiple URL segments with each segment indicating what parameter follows it.

I'll take an example from the Spotify API: https://developer.spotify.com/web-api/get-playlist/:

Get a Playlist

Get a playlist owned by a Spotify user.

Endpoint

GET https://api.spotify.com/v1/users/{user_id}/playlists/{playlist_id}

Request Parameters

+---------------------------------------------------+
| Path parameter | Value                            |
+---------------------------------------------------+
| user_id        | The user's Spotify user ID.      |
| playlist_id    | The Spotify ID for the playlist. |
+---------------------------------------------------+

In that API endpoint, you specify that you are looking for a users object with user_id of {user_id}, and a playlists object (within that users object) with the playlist_id of {playlist_id}.

Some RESTful services allow combination flags on parameters.

Take the Stack Exchange API, for example. You can fetch multiple questions or answers by separating them with semicolons, and it will essentially filter to just those questions or answers.

If we analyze this endpoint (/questions/{ids}/answers), you'll see that it specifies:

Gets the answers to a set of questions identified in id.

This method is most useful if you have a set of interesting questions, and you wish to obtain all of their answers at once or if you are polling for new or updates answers (in conjunction with sort=activity).

{ids} can contain up to 100 semicolon delimited ids, to find ids programatically look for question_id on question objects.

The sorts accepted by this method operate on the follow fields of the answer object:

This is also a good example of an API that allows additional GET requests to filter/sort the results even further.

Example of usage: https://api.stackexchange.com/2.2/questions/30581530/answers?order=desc&sort=activity&site=stackoverflow

Now, if we do the same with the /answers/{ids} endpoint, we can come up with something along the lines of: https://api.stackexchange.com/2.2/answers/30582379;30581997;30581789;30581628?order=desc&sort=activity&site=stackoverflow. This pulls the four specified answers for us.

We can combine even more, for example, with the SE API and include filters to restrict the fields returned: https://api.stackexchange.com/2.2/questions/30581530/answers?order=desc&sort=activity&site=stackoverflow&filter=!)V)P2Uyugvm. (See this link to /2.2/filters for an explanation of that filter parameter.)


SOAP-based Services

Enter SOAP (Simple Object Access Protocol), which was the predecessor to REST. SOAP solved this problem by sending messages back and forth. They use XML (though you could build a SOAP-based service without it, similarly to being able to build a RESTful service without JSON) to exchange a message, whereby the server has no initial indication of what to do.

SOAP-based services solve this issue in a manner that is agnostic of transport medium. The server and client need not use HTTP, or even TCP at all. They just need to use the same, or compatible transport mediums. In fact, you could think of the modern-day corporate environment as a SOAP-based service. When you need to get new supplies, you put in a requisition to your office manager, who then responds with a message. Upon receiving the initial requisition, your manager has no idea if it is permitted or not. They have to read the rest of the requisition in order to determine whether it is a valid request or if it is invalid.

SOAP was designed around RPCs (Remote-Procedure Calls), many firewalls block these. So, as a result, SOAP was modified to work over HTTP. It was designed to integrate vastly different technologies.

Because SOAP is designed around messages, it is a much more verbose service. It is generally easier to represent compound actions in SOAP services. That is to say, if you are requesting objects based on many criteria (instead of just one) SOAP tends to have better interface for this.

SOAP-based Filtering

SOAP-based services filter with additional fields in the RPC. How these fields are combined is up to the provider.

I'll take an example from the Global Weather API: http://www.webservicex.net/globalweather.asmx?op=GetWeather:

GetWeather

Get weather report for all major cities around the world.

Test

To test the operation using the HTTP POST protocol, click the 'Invoke' button.

+---------------------------------------------------+
| Parameter      | Value                            |
+---------------------------------------------------+
| CityName:      |                                  |
| CountryName:   |                                  |
+---------------------------------------------------+

If you specify, for example, "Blanding" and "United States" you will see the generated XML looks like the following:

<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <GetWeather xmlns="http://www.webserviceX.NET">
      <CityName>Blanding</CityName>
      <CountryName>United States</CountryName>
    </GetWeather>
  </soap12:Body>
</soap12:Envelope>

This would be submitted (for an HTTP SOAP request) as a POST-based call to http://www.webservicex.net/globalweather.asmx/GetWeather.


Back to the original question:

Can a SOAP-based webservice be RESTful?

This was your original question, and I believe it stands to reason that it cannot, based on the information I have provided. These two services are mutually-exclusive. REST intends to solve the issue with the exchange of headers that indicate intent, and message bodies that indicate purpose. SOAP intends to solve the issue with the exchange of messages that indicate intent and purpose.

Will it be a violation of REST architecture to use HTTP POST to get data from a resource? Yes. The RESTful service architecture is designed to use the term POST to represent a specific action. Each HTTP verb in REST represents what that action intends to do.

As I said in the comments on the initial question:

You can use HTTP POST to get the data, but it's not a RESTful service then, as the HTTP verb has no meaning. RESTful services are RESTful because the verb indicates the action.


What do I choose, SOAP or REST?

This part exists primarily for future readers.

Both protocols have advantages and disadvantages, and you should choose which protocol you are using based on the requirements of the problem. Instructing you on how to accomplish that is beyond the scope of this question and answer. That said, there are three things to consider: know your project, know your requirements, and most of all, correctly document it for your audience.

Tuesday, August 10, 2021
 
adjco
answered 4 Months ago
71

I know you will don't like the answer and I think I repeat myself because it is not the first time I'm posting it. The way to warm-up anything in IIS prior to version 7.5 is using scheduled console application to ping your web site / services and warm them up. It is ugly solution but it works, it is easy and I saw it on every project which had to deal with this requirement.

Saturday, August 28, 2021
 
user336786
answered 4 Months ago
56

Working solution:

namespace Tfs.NotificationService
{
    [ServiceContract(Namespace = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03")]
    public interface INotifyService
    {
        [OperationContract(Action = "http://schemas.microsoft.com/TeamFoundation/2005/06/Services/Notification/03/Notify")]
        [XmlSerializerFormat(Style = OperationFormatStyle.Document)]
        void Notify(string eventXml, string tfsIdentityXml);
    }

    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class NotifyService : INotifyService
    {
        void INotifyService.Notify(string eventXml, string tfsIdentityXml)
        {
            // do something
        }
    }
}

Web.config:

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="NotifyServiceBinding">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="NotifyServiceBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="NotifyServiceBehavior" name="Tfs.NotificationService.NotifyService">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="NotifyServiceBinding"
                  contract="Tfs.NotificationService.INotifyService" />
      </service>
    </services>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
Sunday, October 24, 2021
 
nkron
answered 2 Months ago
58

The service can be both REST and SOAP, in a way that a WCF service can have multiple endpoints, including a mix of both SOAP and REST. On the WSDL, the SOAP endpoints will show up in the wsdl:definitions/wsdl:service/wsdl:port element; the REST endpoints will not. So if you only have one endpoint in the service, if there is a wsdl:port entry in the WSDL, then it's a SOAP endpoint; otherwise it's REST.

You can run the code below and look at the wsdl to see that it only shows up one wsdl:port element, for the SOAP endpoint.

public class StackOverflow_6414181
{
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        [WebGet]
        string Echo(string text);
    }
    public class Service : ITest
    {
        public string Echo(string text)
        {
            return text;
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "soap");
        host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "rest").Behaviors.Add(new WebHttpBehavior());
        host.Open();
        Console.WriteLine("Host opened");

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
Wednesday, November 10, 2021
 
Klausos Klausos
answered 4 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share