Introduction
I finally found the solution for a rather expected feature in a web service: receive raw XML in a WCF service. This is pretty useful when using contracts is not possible or must be avoided.
Using the Code
Here is a demonstration with 2 projects (VS 2013), one console app to consume the WCF REST Service and send an XML from a file and a WCF service application implemented as a REST service.
1. WCF Service Application
First, a custom mapper for the binding is needed to set the format to „RAW“ for everything coming as XML, so add this to the WCF service project:
public class RawContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
try
{
if (contentType.Contains("text/xml") ||
contentType.Contains("application/xml"))
{
return WebContentFormat.Raw;
}
else
{
return WebContentFormat.Default;
}
}
catch (Exception ex)
{ }
return WebContentFormat.Default;
}
}
The method for receiving data and sending response to the client (Stream is received and sent back):
public Stream PostData(Stream data)
{
byte[] response = null;
try
{
NameValueCollection coll =
WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters;
string sys = coll["System"].ToUpper();
StreamReader sr = new StreamReader(data);
var request = sr.ReadToEnd();
sr.Close();
response = System.Text.Encoding.Default.GetBytes(request);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return new MemoryStream(response);
}
In order to have access to the HTTP context, decorate the WCF class with ASPNet Compatibility attributes:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestWCF : ITestWCF
{
public Stream PostData(Stream data)
{....
The contract is in the expected form:
[ServiceContract]
public interface ITestWCF
{
[OperationContract]
Stream PostData(Stream data);
}
In web.config, the following changes are needed: the custom mapper declared for the endpoint and ASPNET compatibility set to true
if access to HTTP context is needed:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service behaviorConfiguration="Default" name="TESTWCFService.TestWCF">
<endpoint address="" behaviorConfiguration="webBehavior"
contract="TESTWCFService.ITestWCF" binding="customBinding"
bindingConfiguration="CustomMapper" />
</service>
</services>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<bindings>
<customBinding>
<binding name="CustomMapper">
<webMessageEncoding webContentTypeMapperType="TESTWCFService.RawContentTypeMapper,
TESTWCFService" />
<httpTransport manualAddressing="true"
maxReceivedMessageSize="524288000" transferMode="Streamed" />
</binding>
</customBinding>
</bindings>
</system.serviceModel>
2. Client Application for Testing
Console application that reads an XML file from disk and sends it to the WCF REST service. Notice that no contracts or references are needed, only the service address, method to call and optional query string
parameters. Any changes to the XML will be automatically received at the other end.
class Program
{
static void Main(string[] args)
{
SendXml();
}
private static void SendXml()
{
HttpWebRequest req = null;
HttpWebResponse resp = null;
string baseAddress = "http://localhost:51234/TestWCF.svc";
try
{
string fileName = @"D:\Temp\test.xml";
string qs = "?System=TEST";
req = (HttpWebRequest)WebRequest.Create(baseAddress + "/PostData" + qs);
req.Method = "POST";
req.ContentType = "application/xml";
req.Timeout = 600000;
StreamWriter writer = new StreamWriter(req.GetRequestStream());
writer.WriteLine(GetTextFromXMLFile(fileName));
writer.Close();
Encoding enc = System.Text.Encoding.GetEncoding("utf-8");
resp = req.GetResponse() as HttpWebResponse;
Console.WriteLine("HTTP/{0} {1} {2}",
resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
StreamReader sr = new StreamReader(resp.GetResponseStream(), enc);
string result = sr.ReadToEnd();
Console.WriteLine(result);
sr.Close();
}
catch (WebException webEx)
{
Console.WriteLine("Web exception :" + webEx.Message);
}
catch (Exception ex)
{
Console.WriteLine("Exception :" + ex.Message);
}
finally
{
if (req != null)
req.GetRequestStream().Close();
if (resp != null)
resp.GetResponseStream().Close();
}
}
private static string GetTextFromXMLFile(string file)
{
StreamReader reader = new StreamReader(file);
string ret = reader.ReadToEnd();
reader.Close();
return ret;
}
}