1

I'm having a problem with a self-host WCF REST service.

When I try to issue a GET via browser or Fiddler, I get a 400 Bad Request. Tracing is reporting an inner exception of XmlException "The body of the message cannot be read because it is empty."

I don't have any configuration in app.config (do I need any?). I have tried changing WebServiceHost to ServiceHost, and WSDL is returned, but the operations still return 400.

What am I missing here?

// Add Reference to System.ServiceModel and System.ServiceModel.Web
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;

namespace WCFRESTTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var baseAddress = new Uri("http://localhost:8000/");
            var host = new WebServiceHost(typeof(RestService), baseAddress);

            try
            {
                host.AddServiceEndpoint(typeof(IRestService), new WSHttpBinding(), "RestService");

                var smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                host.Description.Behaviors.Add(smb);

                host.Open();
                Console.WriteLine("Service Running.  Press any key to stop.");
                Console.ReadKey();
            }
            catch(CommunicationException ce)
            {
                host.Abort();
                throw;
            }
        }
    }

    [ServiceContract]
    public interface IRestService
    {
        [OperationContract]
        [WebGet(UriTemplate = "Test")]
        bool Test();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class RestService : IRestService
    {
        public bool Test()
        {
            Debug.WriteLine("Test Called.");
            return true;
        }
    }
}
Jay
  • 383
  • 2
  • 16
  • What's the definition of `IRestService`? What's the URL you're sending in Fiddler? – carlosfigueira Mar 29 '13 at 15:01
  • IRestService is in the listed code, and I've tried every conceivable combination of URL's. http://localhost:8000/RestService/Test http://localhost:8000/Test http://localhost:8000/?WSDL etc – Jay Mar 29 '13 at 15:14

1 Answers1

4

When you use the WebServiceHost, you typically don't need to add a service endpoint - it will add one with all behaviors required to make it a "Web HTTP" (a.k.a. REST) endpoint (i.e., an endpoint which doesn't use SOAP and you can easily consume with a tool such as Fiddler, which seems to be what you want). Also, Web HTTP endpoints aren't exposed in the WSDL, so you don't need to add the ServiceMetadataBehavior either.

Now for why it doesn't work - sending a GET request to http://localhost:8000/Test should work - and in the code below it does. Try running this code, and sending the request you were sending before with Fiddler, to see the difference. That should point out what the issue you have.

public class StackOverflow_15705744
{
    [ServiceContract]
    public interface IRestService
    {
        [OperationContract]
        [WebGet(UriTemplate = "Test")]
        bool Test();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class RestService : IRestService
    {
        public bool Test()
        {
            Debug.WriteLine("Test Called.");
            return true;
        }
    }

    public static void Test()
    {
        var baseAddress = new Uri("http://localhost:8000/");
        var host = new WebServiceHost(typeof(RestService), baseAddress);

        // host.AddServiceEndpoint(typeof(IRestService), new WSHttpBinding(), "RestService");

        // var smb = new ServiceMetadataBehavior();
        // smb.HttpGetEnabled = true;
        // host.Description.Behaviors.Add(smb);

        host.Open();

        WebClient c = new WebClient();
        Console.WriteLine(c.DownloadString(baseAddress.ToString().TrimEnd('/') + "/Test"));

        Console.WriteLine("Service Running.  Press any key to stop.");
        Console.ReadKey();
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • I swore I tried this, but apparently not. So what is WebServiceHost doing differently? And what is the recommended way to add the "RestService" back into the path, via the base address? – Jay Mar 29 '13 at 15:35
  • 1
    By default `WebServiceHost` will add the endpoint on the base address. So if you want your operation to respond at `http://localhost:8000/RestService/Test`, then you can add the `RestService` in the base address. – carlosfigueira Mar 29 '13 at 16:22