Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Use an Envelope Element in RESTful WCF Service Response

DZone's Guide to

Use an Envelope Element in RESTful WCF Service Response

·
Free Resource

Yesterday I participated in a Twisation (the replacement term for “Twitter Conversation” founded by me!) about a solution to embed the XML response of a Windows Communication Foundation RESTful service in an envelope element.

There should be several solutions to be offered here because by nature WCF gives a great level of flexibility and the power to customize everything in different levels. The difference is in the amount of work and the quality of the implementation. Here I want to show a rudimentary solution that in my opinion isn’t very beautiful, and may write a separate post with a more professional solution to complement it.

Here the solution is pretty simple and is nothing but embedding a data contract inside an envelope data contract, but I try to embellish it with walking through the process of implementing a sample RESTful WCF service. Most likely you can remember my post about testing a RESTful Windows Communication Foundation service using Fiddler where I showed a detailed example as well.

First of all, let me implement a very simple RESTful service in WCF 3.5. Here I have a service contract like the below code. It has a single method that responds to GET verbs.

using System.ServiceModel;
using System.ServiceModel.Web;

namespace EnvelopeSample
{
[ServiceContract]
public interface ISampleService
{
[OperationContract]
[WebInvoke(Method = "GET",
UriTemplate = "{id}/methods/getdata",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml)]
ServiceResult GetData(string id);
}
}

And here is the simple implementation of the service:

namespace EnvelopeSample
{
public class SampleService : ISampleService
{
#region ISampleService Members

public ServiceResult GetData(string id)
{
ServiceResult result = new ServiceResult();
result.Message = string.Format("Your id is {0}.", id);

return result;
}

#endregion
}
}

The structure of ServiceResult class is pretty simple as well. Here I use my own names for object elements.

using System.Runtime.Serialization;

namespace EnvelopeSample
{
[DataContract(Name = "result", Namespace = "")]
public class ServiceResult
{
[DataMember(Name = "message")]
public string Message { get; set; }
}
}

Besides, I also need a HttpModule to rewrite requests to the service.

using System;
using System.Web;

namespace EnvelopeSample
{
public class Rewriter : IHttpModule
{
#region IHttpModule Members

void IHttpModule.Dispose()
{
return;
}

void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}

void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;

string requestPath = context.Request.Path.ToLower();

if (requestPath.Contains(".svc"))
return;

context.Request.Headers.Add("X-REWRITE-URL", context.Request.Url.AbsolutePath);

// TODO: Customize this line based on your hosting variables
context.RewritePath("~/service.svc", requestPath.Replace("/sampleservice", ""),
context.Request.QueryString.ToString(), false);
}

#endregion
}
}

Now using the following configuration file, I deploy the service to test it.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>

<system.serviceModel>
<services>
<service behaviorConfiguration="MetadataBehavior" name="EnvelopeSample.SampleService">
<endpoint address="" behaviorConfiguration="WebBehavior"
binding="webHttpBinding"
bindingConfiguration="restBinding"
contract="EnvelopeSample.ISampleService"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8732/Design_Time_Addresses/EnvelopeSample/SampleService/" />
</baseAddresses>
</host>
</service>
</services>

<bindings>
<webHttpBinding>
<binding name="restBinding" />
</webHttpBinding>
</bindings>

<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>

</system.serviceModel>

<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRewriter" type="EnvelopeSample.Rewriter, EnvelopeSample" />
</modules>
</system.webServer>
</configuration>

I use Fiddler to test the response for the single method available on this service.

Test the output in Fiddler

As you see, the response is an XML that you could expect.

<result xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<message>Your id is 5.</message>
</result>

Now suppose that you want to embed this response in a parent envelope, say <envelope />.

Before showing my solution (that would be the simplest one), let me say that I’m not very positive about such structures for a public service, specifically a web-based service. There are some logical reasons for this. First and foremost reason is that simplicity should be a primary goal in software development and this envelope doesn’t add anything but complexity. Moreover, this additional piece of XML is making the response larger even very small but when applied to many requests, it may be a notable overhead. Finally, this envelope element makes it harder for client developers to parse the response, so it’s a disadvantage for the usability of your API. When implementing the Waegis API, I tried to test several structures, and finally chose the current structures that are pretty simple and straightforward, and in my opinion this is one of the most important points for a web-based public service.

To embed my response in another element, I simply embed my data contract class in a parent data contract as a property which simply gives me the response that I’d like.

First I create a data contract class called Envelope which has a single property of ServiceResult type. I control the naming of my XML elements to have the relevant output.

using System.Runtime.Serialization;

namespace EnvelopeSample
{
[DataContract(Name = "envelope", Namespace = "")]
public class Envelope
{
[DataMember(Name = "result")]
public ServiceResult Result { get; set; }
}
}

Now I alter my service classes to apply this new return type. Here is the new service contract interface:

using System.ServiceModel;
using System.ServiceModel.Web;

namespace EnvelopeSample
{
[ServiceContract]
public interface ISampleService
{
[OperationContract]
[WebInvoke(Method = "GET",
UriTemplate = "{id}/methods/getdata",
ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml)]
Envelope GetData(string id);
}
}

My service implementation needs minor changes to apply the Envelope class as well.

namespace EnvelopeSample
{
public class SampleService : ISampleService
{
#region ISampleService Members

public Envelope GetData(string id)
{
Envelope envelope = new Envelope();

ServiceResult result = new ServiceResult();
result.Message = string.Format("Your id is {0}.", id);

envelope.Result = result;

return envelope;
}

#endregion
}
}

I can deploy this new service implementation with the exact same configuration and test it with Fiddler to get my desire output.

Test the output in Fiddler

This is the new response that I was looking for:

<envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<result>
<message>Your id is 5.</message>
</result>
</envelope>

This technique is applicable to multiple service contracts as well. You can define relevant envelope classes with any class name that you desire, and then customize the XML element names to get what you need. Usually people like to have a constant envelope element for all their service responses.

Of course, this is not a beautiful solution that I use it in my own projects, but it’s actually a fast and simple solution that may be helpful for some situations. I try to give a second solution based on the power of WCF customization very soon.

I have uploaded the source code sample for this post, so you can download it as well.

 

Topics:

Published at DZone with permission of Keyvan Nayyeri. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}