Oh my dog
Oh my dog

Reputation: 33

WCF RESTful Console-hosted, return 400 Bad Request

Studying WCF RESTful, host in a Console,

my steps:

  1. create sample models
  2. create contract of service
  3. create service
  4. host this service in a console.
  5. run this host, looks ok.
  6. create a winform, use service address via json post to service host.
  7. i hope it would work, but return http 400.

I tried on WCF(not REST) Console-hosted, WebAPI, steps all ok.

finally, stackoverflow.com

please help

Models

[Serializable]
public abstract class Building
{
    public Manufacturer Manufacturer { get; set; }
}

[Serializable]
public class Manufacturer
{
    public string Name { get; set; }

    public string Telephone { get; set; }
}

[Serializable]
public class Furniture : Building
{
    public string Name { get; set; }
}

[Serializable]
public class Reception
{
    public int Floor { get; set; }

    public int Number { get; set; }
}

[Serializable]
public class Room : Building
{
    public string Number { get; set; }

    public List<Furniture> Furnitures { get; set; }
}

[Serializable]
public class Hotel : Building
{
    public Guid Guid { get; set; }

    public List<Reception> Receptions { get; set; }

    public List<Room> Rooms { get; set; }

    public string Name { get; set; }

    public string Address { get; set; }
} 

Contract

[ServiceContract]
public interface IHotel
{
    // Create objct Hotel
    [OperationContract]
    [WebInvoke(UriTemplate = "", Method = "POST", RequestFormat= WebMessageFormat.Json, ResponseFormat=WebMessageFormat.Json)]
    bool Create(Hotel hotel);
}

Service

public class HotelService : I Hotel
{
    public bool Build(Models.Hotel hotel)
    {
        if (hotel == null)
            return false;

        // codes here is object hotel(EF) creation, test OK
        return true;
    }
}

Host(Console)

WebServiceHost serviceHost = new WebServiceHost(typeof(Demo.Services.HotelService), new Uri("http://192.168.1.101/HotelService"));
ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(typeof(Demo.Contracts.IHotel), new WebHttpBinding(), "");
ServiceDebugBehavior sdb = serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.HttpHelpPageEnabled = false;

Console.WriteLine("Starting Service...");
// start service
serviceHost.Open();
Console.WriteLine("Started, press RETURN to exit.");
Console.ReadLine();
serviceHost.Close();

Client(Winform)

Caller

public bool BuildHotel(string json)
{
    WebRequest request = HttpWebRequest.Create("http://192.168.1.101/HotelService");

    request.ContentType = "application/json";

    byte[] data = Encoding.UTF8.GetBytes(json);
    request.ContentLength = data.Length;
    Stream requestStream = request.GetRequestStream();
    requestStream.Write(data, 0, data.Length);
    requestStream.Close();

    WebResponse response = request.GetResponse(); // 400 throwed here
    Stream responseStream = response.GetResponseStream();
    StreamReader responseStreamReader = new StreamReader(responseStream);
    string result = responseStreamReader.ReadToEnd();

    return true;
}

Json String for 'bool BuildHotel(string)' upon

{
    "Guid":"ea59c011-d656-4870-b29b-30a44e668560",
    "Receptions":[
        {"Floor":1,"Number":1},
        {"Floor":2,"Number":2}
    ],
    "Rooms":[
        {
            "Number":"c",
            "Furnitures":[
                {"Name":"1","Manufacturer":{"Name":"1","Telephone":"1"}},
                {"Name":"2","Manufacturer":{"Name":"2","Telephone":"2"}}
            ],
            "Manufacturer":{"Name":"c","Telephone":"c"}
        }
    ],
    "Name":"x",
    "Address":"x",
    "Manufacturer":{"Name":"x","Telephone":"x"}
}

Upvotes: 2

Views: 603

Answers (1)

Igor Tkachenko
Igor Tkachenko

Reputation: 1120

it expects such kind of JSON:

{"k_BackingField":{"k_BackingField":"4","k_BackingField":"4"},"k_BackingField":"x","k_BackingField":"ea59c011-d656-4870-b29b-30a44e668560","k_BackingField":"x","k_BackingField":[{"k_BackingField":1,"k_BackingField":1},{"k_BackingField":2,"k_BackingField":2}],"k_BackingField":[{"k_BackingField":{"k_BackingField":"3","k_BackingField":"3"},"k_BackingField":[{"k_BackingField":{"k_BackingField":"1","k_BackingField":"1"},"k_BackingField":"1"},{"k_BackingField":{"k_BackingField":"2","k_BackingField":"2"},"k_BackingField":"2"}],"k__BackingField":null}]}

To change it you can mark all your data contracts with DataContract and DataMember attribute:

    [DataContract]
    public abstract class Building
    {
        [DataMember]
        public Manufacturer Manufacturer { get; set; }
    }

In this case it will understand json as you have given us in the question and will process it successfully.

Upvotes: 0

Related Questions