WCF REST Service accepting Raw Xml- WebContentTypeMapper
Posted by vivekcek on June 14, 2012
My Problem
———-
I want to develop a WCF-REST service that accept XML through POST method. Process the xml and send an xml response back. Different types of xml string are posted to my service. My service need to accept any format like text/xml,appilcation/xml etc.
How i am going to solve
————————————–
I am planning to use .NET 4.0 for my WCF service. In .NET 4.0 WCF support Raw data in the form of Stream.
To Code
——-
1. Create a WCF Service application.
2. In the Service contract write below code.
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.ServiceModel.Web; using System.IO; using System.Xml.Linq; namespace RestRaw { [ServiceContract] public interface IService1 { [OperationContract] [WebInvoke(Method = "POST", UriTemplate = "Push", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)] XElement DoWork(Stream xml); } }
3. In the Service implementation write the following code.
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.IO; using System.Xml.Linq; namespace RestRaw { public class Service1 : IService1 { public XElement DoWork(Stream xml) { StreamReader reader = null; XDocument xDocRequest = null; string strXmlRequest = string.Empty; reader = new StreamReader(xml); strXmlRequest = reader.ReadToEnd(); xDocRequest = XDocument.Parse(strXmlRequest); string response = "<Result>OK</Result>"; return XElement.Parse(response); } } }
4. Now create a class named RawContentTypeMapper.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Channels; namespace RestRaw { public class RawContentTypeMapper : WebContentTypeMapper { public override WebContentFormat GetMessageFormatForContentType(string contentType) { if (contentType.Contains("text/xml") || contentType.Contains("application/xml")) { return WebContentFormat.Raw; } else { return WebContentFormat.Default; } } } }
5. Change your Web.config as below.
<configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> <system.serviceModel> <services> <service behaviorConfiguration="" name="RestRaw.Service1"> <endpoint address="" behaviorConfiguration="web" contract="RestRaw.IService1" binding="customBinding" bindingConfiguration="RawReceiveCapable"></endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> <serviceMetadata httpGetEnabled="true"/> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="web"> <webHttp/> </behavior> </endpointBehaviors> </behaviors> <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> <bindings> <customBinding> <binding name="RawReceiveCapable"> <webMessageEncoding webContentTypeMapperType="RestRaw.RawContentTypeMapper, RestRaw, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <httpTransport manualAddressing="true" maxReceivedMessageSize="524288000" transferMode="Streamed" /> </binding> </customBinding> </bindings> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> </system.webServer> </configuration>
6. Code to test service
private static string PostXml(string xml, string url) { // Restful service URL //string url = txtURL.Text; // declare ascii encoding ASCIIEncoding encoding = new ASCIIEncoding(); string strResult = string.Empty; // sample xml sent to Service & this data is sent in POST string SampleXml = xml; string postData = SampleXml.ToString(); // convert xmlstring to byte using ascii encoding byte[] data = encoding.GetBytes(postData); // declare httpwebrequet wrt url defined above HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url); // set method as post webrequest.Method = "POST"; // set content type webrequest.ContentType = "text/xml"; // set content length webrequest.ContentLength = data.Length; // get stream data out of webrequest object Stream newStream = webrequest.GetRequestStream(); newStream.Write(data, 0, data.Length); newStream.Close(); // declare & read response from service HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse(); // set utf8 encoding Encoding enc = System.Text.Encoding.GetEncoding("utf-8"); // read response stream from response object StreamReader loResponseStream = new StreamReader(webresponse.GetResponseStream(), enc); // read string from stream data strResult = loResponseStream.ReadToEnd(); // close the stream object loResponseStream.Close(); // close the response object webresponse.Close(); return strResult; }
Solution
DOWNLOAD
http://sdrv.ms/M0AunA
Marvin said
In testing, why am I getting this error “WebException was unhandled. The remote server returnedan error: (404) Not Found.”
when passing to this part of the code.. HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();
Please help! Thanks in advance
Marvin said
Okay I got it. I must update the Web.config by defining the endpoint address.
But now I’m having a new error. “WebException was unhandled. The remote server returned an error: (500) Internal Server Error.”
vivekcek said
post the exception.Check service using fiddler
vivekcek said
down load this code and use http://sdrv.ms/M0AunA
Marvin said
Yeah, I downloaded your code and that’s what I’m using.
Here’s what my console test program looks like.
class Program
{
static void Main(string[] args)
{
Console.WriteLine(PostXml(“OK”, “http://localhost/RestRaw/Service1.svc”));
Console.ReadLine();
}
private static string PostXml(string xml, string url)
{
// Restful service URL
//string url = txtURL.Text;
// declare ascii encoding
ASCIIEncoding encoding = new ASCIIEncoding();
string strResult = string.Empty;
// sample xml sent to Service & this data is sent in POST
string SampleXml = xml;
string postData = SampleXml.ToString();
// convert xmlstring to byte using ascii encoding
byte[] data = encoding.GetBytes(postData);
// declare httpwebrequet wrt url defined above
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
// set method as post
webrequest.Method = “POST”;
// set content type
webrequest.ContentType = “text/xml”;
// set content length
webrequest.ContentLength = data.Length;
// get stream data out of webrequest object
Stream newStream = webrequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
// declare & read response from service
HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();
// set utf8 encoding
Encoding enc = System.Text.Encoding.GetEncoding(“utf-8”);
// read response stream from response object
StreamReader loResponseStream =
new StreamReader(webresponse.GetResponseStream(), enc);
// read string from stream data
strResult = loResponseStream.ReadToEnd();
// close the stream object
loResponseStream.Close();
// close the response object
webresponse.Close();
return strResult;
}
}
here’s my web.config from RestRaw project.
I’ve just updated the endpoint address and set multipleSiteBindingsEnabled to “false”
And here’s the exception I’m getting
System.Net.WebException was unhandled
HResult=-2146233079
Message=The remote server returned an error: (404) Not Found.
Source=System
StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at TestService.Program.PostXml(String xml, String url) in D:\PlayingAround\SystemMonitorWebService_test\TestService\Program.cs:line 44
at TestService.Program.Main(String[] args) in D:\PlayingAround\SystemMonitorWebService_test\TestService\Program.cs:line 14
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
Thanks again!
Marvin said
My config didn’t post.
Again, here’s my web.config.
Thanks
Marvin said
Finally!! I was able to make it run!
I’ve missed the “/Push” at the end of the URL
Console.WriteLine(PostXml(“OK”, “http://localhost/RestRaw/Service1.svc/PUSH”));
Thanks!!
vivekcek said
nice
Harry said
I copied all your code, when I compile I receive below exception, any idea what cause this?
Could not load file or assembly ‘RestRaw, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.
Harry said
Got it working, great blog!.
Mohammed Khadeer said
How you solve the above issue Could not load file or assembly ‘RestRaw, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.
vivekcek said
Check your framework version and library version,
i recommend create project from scratch, than copying my config file
Harry said
Thank You 🙂
Rick said
Hi – thanks a lot for this post – exactly what I needed for some code I am working. Can you tell me how to have this called by Https? When I change the entry in Web.Config for CustomBinding to this, it complains about Mode attribute not being allowed. Thanks R
Rick said
kk said
Thanks for the Post. It resolved my issue, raising another 🙂
New Issue: am using this in a Webservice, while request it converts the text to RAW fine but for response too… it responding back in RAW and the response is in encoded format, how can i get back to normal format (I mean decode it).
Note: assume the response is a string/stream which is not encoded, but the http response messagebody has encoded version of my return. because of this RAW
I believe its because of the config <webMessageEncoding ….
plz Suggest, thanks in advance
kk said
Update:
response looks like
DATA
f72
Session state has created a session id, but cannot save it because the response was already flushed by the application.
body bla bla bla
Want to get rid of the added html in the response messagebody
Note: tries to place below statement in global.asax.cs – didn’t worked
string sessionId = Session.SessionID;
sagarreddy123Sagar said
Hi , I followed you article but am getting 400 bad request while getting the response. By trace log I found the exception is ServiceModel.CommunicationException and message is Unrecognized Message version. Please find my code below
Service
[ServiceContract]
public interface IXMLFileProcessService
{
[OperationContract]
[WebInvoke(Method = “POST”,
UriTemplate = “PUSH”,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare)]
XElement ProcessFileDataByFile(Stream document);
}
public class XMLProcessService : IXMLFileProcessService
{
public XElement ProcessFileDataByFile(Stream document)
{
Logger.WriteLog(LogLevel.INFO, “Call Started-> ProcessFileDataByFile”);
StreamReader reader = null;
XDocument xDocRequest = null;
string strXmlRequest = string.Empty;
reader = new StreamReader(document);
strXmlRequest = reader.ReadToEnd();
xDocRequest = XDocument.Parse(strXmlRequest);
string response = “OK”;
Logger.WriteLog(LogLevel.INFO, “Call Ended-> ProcessFileDataByFile”);
return XElement.Parse(response);
}
}
Client
string serviceUrl = “http://” + Environment.MachineName + “/FileReadPOC/XMLProcessService.svc”;
XmlDocument document = new XmlDocument();
document.Load(@”D:\My Projects\SampleXML_1.xml”);
string xml = document.InnerXml;
ASCIIEncoding encoding = new ASCIIEncoding();
string strResult = string.Empty;
string SampleXml = xml;
string postData = SampleXml.ToString();
byte[] data = encoding.GetBytes(postData);
HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
webrequest.Method = “POST”;
webrequest.ContentType = “text/xml;charset=utf-8”;
webrequest.ContentLength = data.Length;
Stream newStream = webrequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
HttpWebResponse webresponse = (HttpWebResponse)webrequest.GetResponse();
Encoding enc = System.Text.Encoding.GetEncoding(“utf-8”);
StreamReader loResponseStream = new StreamReader(webresponse.GetResponseStream(), enc);
strResult = loResponseStream.ReadToEnd();
loResponseStream.Close();
webresponse.Close();
Please Help
Kdud said
You are one Legend… Keep up the good work