merger
merger

Reputation: 734

How do i make a self hosted wcf accept REST/JSON?

I have read here on SO in several posts that it is possible to create a selfhosted wcf REST service that accepts JSON as input. But i cant get it to work, im banging my head against the same rock over and over it seems :(

This is my very basic code that i cant get working. Im using .net 4.6.1 in VS 2017

[ServiceContract]
public interface IService1
{
//[WebInvoke(Method = "POST", UriTemplate = "Save")]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
bool Save(BatchOfRows request);
}

public bool Save(BatchOfRows request)
{
    return true;
}

Uri baseAddress = new Uri("http://localhost:8000/");

// Step 2: Create a ServiceHost instance.
var selfHost = new ServiceHost(typeof(Service1), baseAddress);
try
{
// Step 3: Add a service endpoint.
selfHost.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), "");

// Step 4: Enable metadata exchange.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpsGetEnabled = false;
selfHost.Description.Behaviors.Add(smb);

// Step 5: Start the service.
selfHost.Open();
Console.WriteLine("The service is ready.");

// Close the ServiceHost to stop the service.
Console.WriteLine("Press <Enter> to terminate the service.");
Console.WriteLine();
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce)
{
    Console.WriteLine("An exception occurred: {0}", ce.Message);
    selfHost.Abort();
}

I then connect with this code

        string url = @"http://127.0.0.1:8000";

        var client = new RestClient(url);

        var request = new RestRequest("Save", Method.POST);

        var b = new BatchOfRows();
        b.CaseTableRows.Add(new AMCaseTableRow { PROJID = "proj1", CASEID = "case1" });
        b.CaseTableRows.Add(new AMCaseTableRow { PROJID = "proj2", CASEID = "case2", DEVICEID = "device2" });

        var stream1 = new MemoryStream();
        var ser = new DataContractJsonSerializer(typeof(BatchOfRows));

        ser.WriteObject(stream1, b);

        stream1.Flush();
        stream1.Position = 0;

        StreamReader reader = new StreamReader(stream1);
        string payload = reader.ReadToEnd();

        request.AddParameter("Save",payload);

        var response = client.Post(request);
        var content = response.Content; 

In the respose i get this back.

"StatusCode: UnsupportedMediaType, Content-Type: , Content-Length: 0)"
  Content: ""
  ContentEncoding: ""
  ContentLength: 0
  ContentType: ""
  Cookies: Count = 0
  ErrorException: null
  ErrorMessage: null
  Headers: Count = 3
  IsSuccessful: false
  ProtocolVersion: {1.1}
  RawBytes: {byte[0]}
  Request: {RestSharp.RestRequest}
  ResponseStatus: Completed
  ResponseUri: {http://127.0.0.1:8000/Save}
  Server: "Microsoft-HTTPAPI/2.0"
  StatusCode: UnsupportedMediaType
  StatusDescription: "Cannot process the message because the content type 'application/x-www-form-urlencoded' was not the expected type 'application/soap+xml; charset=utf-8'."

I cant get it to work! I have tried with different client implementations with the same result. In every answer i check it sais to just use

[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]

And i should be good. But its not working and im getting abit frustrated as this is the simplest example i can think of.

So what am i doing wrong?

I have used the same type of implementation before, but for a SOAP project, and that is working just fine. I cant do that this time.

Upvotes: 0

Views: 425

Answers (1)

Abraham Qian
Abraham Qian

Reputation: 7522

Bro, we need to use WebHttpBinding to create Restful style WCF service. Here is an example.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-create-a-basic-wcf-web-http-service
Webservicehost is also need to host the service when we create the Restful style service. Alternatively, we could add WebHttpBehavior endpoint behavior to the host, like below.

static void Main(string[] args)
{
    Uri uri = new Uri("http://localhost:9999");
    WebHttpBinding binding = new WebHttpBinding();
    using (ServiceHost sh=new ServiceHost(typeof(MyService),uri))
    {
        ServiceEndpoint se=sh.AddServiceEndpoint(typeof(IService),binding,"");
        se.EndpointBehaviors.Add(new WebHttpBehavior());


        sh.Open();
        Console.WriteLine("Service is ready....");

        Console.ReadLine();
        sh.Close();
    }
}

Result.
enter image description here
Besides, For the BodyStyle=WebMessageBodyStyle.Wrapped attribute, Please pay attention to the data format when we have the Custom object parameter.

[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
bool Save(BatchOfRows request);

Assumed that the BatchOfRows has one ID property. Based on your definition, the Json Data should be.

{ “request”:{“ID”:1}}

For details.
Get the object is null using JSON in WCF Service
Feel free to let me know if there is anything I can help with.

Upvotes: 1

Related Questions