How to: Create a Service That Accepts Arbitrary Data using the WCF REST Programming Model

Sometimes developers must have full control of how data is returned from a service operation. This is the case when a service operation must return data in a format not supported byWCF. This topic discusses using the WCF REST Programming Model to create a service that receives arbitrary data.

To implement the service contract

  1. Define the service contract. The operation that receives the arbitrary data must have a parameter of type Stream. In addition, this parameter must be the only parameter passed in the body of the request. The operation described in this example also takes a filename parameter. This parameter is passed within the URL of the request. You can specify that a parameter is passed within the URL by specifying a UriTemplate in the WebInvokeAttribute. In this case the URI used to call this method ends in "UploadFile/Some-Filename". The "{filename}" portion of the URI template specifies that the filename parameter for the operation is passed within the URI used to call the operation.

     [ServiceContract]  
    public interface IReceiveData  
    {  
        [WebInvoke(UriTemplate = "UploadFile/{fileName}")]  
        void UploadFile(string fileName, Stream fileContents);  
    }  
    
  2. Implement the service contract. The contract has only one method, UploadFile that receives a file of arbitrary data in a stream. The operation reads the stream counting the number of bytes read and then displays the filename and the number of bytes read.

    public class RawDataService : IReceiveData  
    {  
        public void UploadFile(string fileName, Stream fileContents)  
        {  
            byte[] buffer = new byte[10000];  
            int bytesRead, totalBytesRead = 0;  
            do  
            {  
                bytesRead = fileContents.Read(buffer, 0, buffer.Length);  
                totalBytesRead += bytesRead;  
            } while (bytesRead > 0);  
            Console.WriteLine("Service: Received file {0} with {1} bytes", fileName, totalBytesRead);  
        }  
    }  
    

To host the service

  1. Create a console application to host the service.

    class Program  
    {  
       static void Main(string[] args)  
       {  
       }  
    }  
    
  2. Create a variable to hold the base address for the service within the Main method.

    string baseAddress = "http://" + Environment.MachineName + ":8000/Service";  
    
  3. Create a ServiceHost instance for the service that specifies the service class and the base address.

    ServiceHost host = new ServiceHost(typeof(RawDataService), new Uri(baseAddress));  
    
  4. Add an endpoint that specifies the contract, WebHttpBinding, and WebHttpBehavior.

    host.AddServiceEndpoint(typeof(IReceiveData), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());  
    
  5. Open the service host. The service is now ready to receive requests.

    host.Open();  
    Console.WriteLine("Host opened");  
    

To call the service programmatically

  1. Create a HttpWebRequest with the URI used to call the service. In this code, the base address is combined with "/UploadFile/Text". The "UploadFile" portion of the URI specifies the operation to call. The "Test.txt" portion of the URI specifies the filename parameter to pass to the UploadFile operation. Both of these items map to the UriTemplate applied to the operation contract.

    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress + "/UploadFile/Test.txt");  
    
  2. Set the Method property of the HttpWebRequest to POST and the ContentType property to "text/plain". This tells the service that the code is sending data and that data is in plain text.

    req.Method = "POST";  
    req.ContentType = "text/plain";  
    
  3. Call GetRequestStream to get the request stream, create the data to send, write that data to the request stream, and close the stream.

    Stream reqStream = req.GetRequestStream();  
    byte[] fileToSend = new byte[12345];  
    for (int i = 0; i < fileToSend.Length; i++)  
       {  
           fileToSend[i] = (byte)('a' + (i % 26));  
       }  
    reqStream.Write(fileToSend, 0, fileToSend.Length);  
    reqStream.Close();  
    
  4. Get the response from the service by calling GetResponse and display the response data to the console.

    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();  
    Console.WriteLine("Client: Receive Response HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);  
    
  5. Close the service host.

    host.Close();  
    

Example

The following is a complete listing of the code for this example.

using System;  
using System.Collections.Generic;  
using System.Text;  
using System.ServiceModel;  
using System.ServiceModel.Web;  
using System.ServiceModel.Description;  
using System.IO;  
using System.Net;  
  
namespace ReceiveRawData  
{  
    [ServiceContract]  
    public interface IReceiveData  
    {  
        [WebInvoke(UriTemplate = "UploadFile/{fileName}")]  
        void UploadFile(string fileName, Stream fileContents);  
    }  
    public class RawDataService : IReceiveData  
    {  
        public void UploadFile(string fileName, Stream fileContents)  
        {  
            byte[] buffer = new byte[10000];  
            int bytesRead, totalBytesRead = 0;  
            do  
            {  
                bytesRead = fileContents.Read(buffer, 0, buffer.Length);  
                totalBytesRead += bytesRead;  
            } while (bytesRead > 0);  
            Console.WriteLine("Service: Received file {0} with {1} bytes", fileName, totalBytesRead);  
        }  
    }  
  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";  
            ServiceHost host = new ServiceHost(typeof(RawDataService), new Uri(baseAddress));  
            host.AddServiceEndpoint(typeof(IReceiveData), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());  
            host.Open();  
            Console.WriteLine("Host opened");  
  
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(baseAddress + "/UploadFile/Test.txt");  
            req.Method = "POST";  
            req.ContentType = "text/plain";  
            Stream reqStream = req.GetRequestStream();  
            byte[] fileToSend = new byte[12345];  
            for (int i = 0; i < fileToSend.Length; i++)  
            {  
                fileToSend[i] = (byte)('a' + (i % 26));  
            }  
            reqStream.Write(fileToSend, 0, fileToSend.Length);  
            reqStream.Close();  
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();  
            Console.WriteLine("Client: Receive Response HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);  
            host.Close();  
  
        }  
    }  
}  

Compiling the Code

  • When compiling the code reference System.ServiceModel.dll and System.ServiceModel.Web.dll

See also