4

I'm trying to find a way to call a WCF method using JSON and pass a TimeSpan as parameter but I always receive a "Bad request" response from the service.

Here is a snippet code service interface:

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

Service call:

  String method = "GetTimeSpan";
  String result = null;

  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + method);
  request.KeepAlive = false;
  request.Method = WebRequestMethods.Http.Post;
  request.ContentType = "application/json";

  JsonSerializer serializer = new JsonSerializer();

  TimeSpan ts = new TimeSpan(23, 59, 59);
  String jsonString = JsonConvert.SerializeObject(ts);


  String data = jsonString;      //jsonString = "23:59:59"
  //I have already tryed with {"value": "23:59:59"} and the result is the same, bad request.
  request.ContentLength = data.Length;

  StreamWriter writer = new StreamWriter(request.GetRequestStream());
  writer.Write(data);
  writer.Close();

  WebResponse response = request.GetResponse();
  StreamReader reader = new StreamReader(response.GetResponseStream());
  result = reader.ReadToEnd();
  response.Close();

This is just an example. When calling a service without TimeSpan everything works fine. I need to put it work in order do keep compatibility with other clients that are consuming the service in the typical way.

Response:

The remote server returned an error: (400) Bad Request.

Am I passing the wrong TimeSpan json representation? Or is there a way to define how to deserialize the TimeSpan when the service handles the request?

Thanks in advance

Bonomi
  • 2,541
  • 5
  • 39
  • 51
  • TimeSpan can't be serialized. Probable duplicate of http://stackoverflow.com/questions/3232701/using-json-to-serialize-deserialize-timespan – Dennis Traub Aug 24 '11 at 16:49
  • @dennis - that question was about WCF on .NET 3.5 (using VS2008 so a fairly good presumption). Maybe this has changed since .NET 4.0? Maybe OP could clarify .NET version? – Kev Aug 28 '11 at 14:49

3 Answers3

3

The format for TimeSpan used by WCF is not the same one used by the Newtonsoft JSON serializer (JSON.NET) . You can serialize one TimeSpan instance using the DataContractJsonSerializer (DCJS), and that will be the format required by a WCF REST service.

The code below will print out the formats of some TimeSpan values as serialized by both JSON.NET and DCJS:

public class StackOverflow_7178839
{
    public static void Test()
    {
        foreach (var ts in new TimeSpan[] { new TimeSpan(23, 59, 59), new TimeSpan(3, 4, 5, 6), new TimeSpan(-4, 3, 4, 5, 333) })
        {
            Console.WriteLine("For TimeSpan value: {0}", ts);
            Console.WriteLine("  {0}", Newtonsoft.Json.JsonConvert.SerializeObject(ts));
            DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(TimeSpan));
            MemoryStream ms = new MemoryStream();
            dcjs.WriteObject(ms, ts);
            Console.WriteLine("  {0}", Encoding.UTF8.GetString(ms.ToArray()));
        }
    }
}
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
1

You can form the json as mentioned below and pass

{"value":"PT19H"} => Passing 19 Hrs as timespan value

{"value":"PT19H15"} => Passing 19 Hrs, 15 Secs as timespan value

{"value":"23H59M59S"} => Passing 23 Hrs, 59 Mins and 59 Secs as timespan value

Bala
  • 11
  • 1
0

For anyone who still have a problem with WCF serializer, I have found the solution like this : use your own formatter but make sure clearing all formatter.

private void RegisterRoute() {
            var config = new WebApiConfiguration() { EnableHelpPage = true, EnableTestClient = true };
            config.Formatters.Clear();
            config.Formatters.Add(new JsonNetMediaTypeFormatter());
            config.MaxReceivedMessageSize = 2097151;
            config.MaxBufferSize = 2097151;
            RouteTable.Routes.SetDefaultHttpConfiguration(config);
            RouteTable.Routes.MapServiceRoute("sys", config);
}
рüффп
  • 5,172
  • 34
  • 67
  • 113