title: ServiceStack RESTful WebService and passing data in message body
body: <p>I am evaluating ServiceStack at the moment. I am in need to create bunch of RESTful webservices. I have the initial code running, and I am quite happy with that. What I was struggling a bit was how to create a service that could consume POST (or PUT) HTTP request that has data in its body.</p>
  
  <p>I've found this thread on ServiceStack forum (<a href="http://groups.google.com/group/servicestack/browse_thread/thread/693145f0c3033795" rel="nofollow noreferrer">http://groups.google.com/group/servicestack/browse_thread/thread/693145f0c3033795</a>) and folliwng it I've been guided to have a look at the following thread on SO (<a href="https://stackoverflow.com/questions/8046538/json-format-data-from-console-application-to-service-stack/8046734#8046734">Json Format data from console application to service stack</a>) but it was not really helpful - it described how to create a request, and not how to create a service that can consume such a HTTP request.</p>
  
  <p>When I tried to pass additional data (in the HTTP message body) my servuce returned following error (HTTP 400):</p>
  
  <pre><code>&lt;TaskResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns=""&gt;
  &lt;ResponseStatus&gt;
  &lt;ErrorCode&gt;SerializationException&lt;/ErrorCode&gt;
  &lt;Message&gt;Could not deserialize 'application/xml' request using ServiceStackMVC.Task'
  Error: System.Runtime.Serialization.SerializationException: Error in line 1 position 8.Expecting element 'Task' from namespace 'http://schemas.datacontract.org/2004/07/ServiceStackMVC'..    
  Encountered 'Element'  with name 'Input', namespace ''. 
  at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
  at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)
  at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(XmlDictionaryReader reader)
  at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(Stream stream)
  at ServiceStack.Text.XmlSerializer.DeserializeFromStream(Type type, Stream stream) in  C:\src\ServiceStack.Text\src\ServiceStack.Text\XmlSerializer.cs:line 76
  at ServiceStack.WebHost.Endpoints.Support.EndpointHandlerBase.CreateContentTypeRequest(IHttpRequest httpReq, Type requestType, String contentType) in C:\src\ServiceStack\src\ServiceStack\WebHost.Endpoints\Support\EndpointHandlerBase.cs:line 107&lt;/Message&gt;
  &lt;StackTrace&gt;   at ServiceStack.WebHost.Endpoints.Support.EndpointHandlerBase.CreateContentTypeRequest(IHttpRequest httpReq, Type requestType, String contentType) in C:\src\ServiceStack\src\ServiceStack\WebHost.Endpoints\Support\EndpointHandlerBase.cs:line 115
  at ServiceStack.WebHost.Endpoints.RestHandler.GetRequest(IHttpRequest httpReq, IRestPath restPath) in C:\src\ServiceStack\src\ServiceStack\WebHost.Endpoints\RestHandler.cs:line 98
  at ServiceStack.WebHost.Endpoints.RestHandler.ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, String operationName) in C:\src\ServiceStack\src\ServiceStack\WebHost.Endpoints\RestHandler.cs:line 60&lt;/StackTrace&gt;
  &lt;/ResponseStatus&gt;
  &lt;/TaskResponse&gt;
  </code></pre>
  
  <p>This led me to <a href="https://github.com/ServiceStack/ServiceStack/wiki/Serialization-deserialization" rel="nofollow noreferrer">https://github.com/ServiceStack/ServiceStack/wiki/Serialization-deserialization</a> I thought that I will give <code>IRequiresRequestStream</code> a go. At the moment my code is as follows:
  </p>
  
  <pre><code>public class Task : IRequiresRequestStream
  {
      public string TaskName { get; set; }
      public string bodyData { get; set; }
  
      public override bool Equals(object obj)
      {
          Task task = obj as Task;
          if (task == null)
              return false;
          return TaskName.Equals(task.TaskName);
      }
  
      public override int GetHashCode()
      {
          return TaskName.GetHashCode();
      }
  
      public System.IO.Stream RequestStream
      {
          get
          {
              return new MemoryStream(System.Text.Encoding.UTF8.GetBytes(bodyData));
          }
          set
          {
              if (value.Length == 0)
              {
                  bodyData = string.Empty;
              }
              else
              {
                  byte[] buffer = new byte[value.Length];
                  int bytesRead = value.Read(buffer, 0, (int)value.Length);
                  bodyData = System.Text.Encoding.UTF8.GetString(buffer);
              }
          }
      }
  }
  </code></pre>
  
  <p>and service itself:
  </p>
  
  <pre><code>public class TaskService : RestServiceBase&lt;Task&gt;
  {
      public List&lt;Task&gt; tasks { get; set; }
  
      public override object OnGet(Task request)
      {
          if (string.IsNullOrEmpty(request.TaskName))
          {
              if (tasks == null || tasks.Count == 0)
                  return "&lt;tasks/&gt;";
              StringBuilder sb = new StringBuilder();
              sb.AppendLine("&lt;tasks&gt;");
              foreach (Task t in tasks)
              {
                  sb.AppendFormat("  &lt;task id={0}&gt;&lt;![CDATA[{2}]]&gt;&lt;task/&gt;{1}", t.TaskName, System.Environment.NewLine, t.bodyData);
              }
              sb.AppendLine("&lt;/tasks&gt;");
              return sb.ToString();                
          }
          else
          {
              if (tasks.Contains(request))
              {
                  var task = tasks.Where(t =&gt; t.TaskName == request.TaskName).SingleOrDefault();
                  return String.Format("&lt;task id={0}&gt;&lt;![CDATA[{2}]]&gt;&lt;task/&gt;{1}", task.TaskName, System.Environment.NewLine, task.bodyData);
              }
              else
                  return "&lt;task/&gt;";
          }
      }
  
      public override object OnPost(Task request)
      {
          if (tasks.Contains( request ))
          {
              throw new HttpError(System.Net.HttpStatusCode.NotModified, "additional information");
          }
  
          tasks.Add(new Task() { TaskName = request.TaskName, bodyData = request.bodyData });
          return null;
      }
  }
  </code></pre>
  
  <p>My routes:
  </p>
  
  <pre><code>Routes.Add&lt;Task&gt;("/tasks/{TaskName}").Add&lt;Task&gt;("/tasks");
  </code></pre>
  
  <p>It works but... as I couldn't find any similar example I would like to ask if this is the correct way of creating a service that is capable of processing POST requests that have additional informaion included in their message body. Am I doing anything wrong? Is there anything that I've missed?</p>
  
  <p>It was also mentioned on the SO thread link to which I have provided, that using DTO is the preferred way to pass data to ServiceStack based service. Assuming that client needs to send a lot of data, how could we achieve that? I don't want to pass data as JSON object in the URI. Am I making any false assumption here?</p>
  
  <hr>
  
  <ol>
  <li>Client is not going to be written in C# / .Net. Completely different technology is going to be used. This was one of the reasony why RESTful webservices.</li>
  <li>I know returning xml as string may not be the best idea. At the moment it is just a sample code. This will be changed later on.</li>
  <li>The most important part is if the solution provided for me is the proper way to create a webservice that can consume HTTP request that has xml data attached in its body. What I've shared with you works I am just not 100% sure that this is the best way to achieve my goal.</li>
  </ol>
  
  <hr>
  
  <h2>Edited on Thursday 8th of March, 2012:</h2>
  
  <p>After reading the answer and the comments I've changed my code a little bit. I was pretty sure that if I wanted to use serialization I had to use namespaces (when passing data in the HTTP message body to the service).</p>
  
  <p>I've used <code>http://localhost:53967/api/servicestack.task/xml/metadata?op=Task</code> to get more information about the service I've created. </p>
  
  <p>REST Paths:</p>
  
  <pre><code>All Verbs /tasks/{TaskName}
  All Verbs /tasks
  </code></pre>
  
  <p>HTTP + XML:
      POST /xml/asynconeway/Task HTTP/1.1 
      Host: localhost 
      Content-Type: application/xml
      Content-Length: length</p>
  
  <pre><code>&lt;Task xmlns:i="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://schemas.datacontract.org/2004/07/ServiceStackMVC"&gt;
    &lt;AuxData&gt;String&lt;/AuxData&gt;
    &lt;TaskName&gt;String&lt;/TaskName&gt;
  &lt;/Task&gt;
  </code></pre>
  
  <p>What I wanted to check was if it was possible to "mix" REST URI and pass the rest of the data as an xml.</p>
  
  <p>Using Fiddler, I've created following POST request:</p>
  
  <pre><code>POST http://localhost:53967/api/tasks/22
  </code></pre>
  
  <p>Request headers:</p>
  
  <pre><code>User-Agent: Fiddler
  Host: localhost:53967
  Content-Type: application/xml
  Content-Length: 165
  </code></pre>
  
  <p>Request Body:</p>
  
  <pre><code>&lt;Task xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ServiceStackMVC"&gt;
    &lt;AuxData&gt;something&lt;/AuxData&gt;
  &lt;/Task&gt;
  </code></pre>
  
  <p>My DTO right now is as follows:</p>
  
  <pre><code>public class Task
  {
      public string TaskName { get; set; }
      public string AuxData { get; set; }
  
      public override bool Equals(object obj)
      {
          Task task = obj as Task;
          if (task == null)
              return false;
          return TaskName.Equals(task.TaskName);
      }
  
      public override int GetHashCode()
      {
          return TaskName.GetHashCode();
      }
  }
  </code></pre>
  
  <p>And my service code is:</p>
  
  <pre><code>public class TaskService : RestServiceBase&lt;Task&gt;
  {
      public List&lt;Task&gt; tasks { get; set; }
  
      public override object OnGet(Task request)
      {
          return tasks;
      }
  
      public override object OnPost(Task request)
      {
          if (tasks.Contains( request ))
          {
              throw new HttpError(System.Net.HttpStatusCode.NotModified, "additional information");
          }
  
          tasks.Add(new Task() { TaskName = request.TaskName });
          return null;
      }
  }
  </code></pre>
  
  <p>So is this the proper way of passing XML data to the service? I think I am quite happy with xml namespaces included - that makes it even easier to develop services.</p>