9

I've recently added WEB API to an existing VS desktop application and everything worked fine, until yesterday when I had to add a GET method that took three parameters, one of them a Date. Well, at first I thought that that was going to be a piece of cake, but much to my surprise I noticed that when I sent 2014/07/09 (9th July) on the server where the application was installed it was treated like 2014/09/07 (7th September) and for that reason all my comparisons never worked.

I have tried things like changing from a GET method to a POST method, changing my Regional and Language Options settings to the same on the server, passing the date as a String a created a Datetime object on the server using the parts of the string. Unfortunately none of them worked.

Then I remember that this desktop application have some methods on its WCF project (which I'm passing now to web API) that passed dates with no problem at all. Looking in the code for a while I found that they used something like this on every class of they WCF project that uses dates:

Imports System.Globalization
Imports System.Security.Permissions
Imports System.Threading

Public Class ServicioRemotoVentas
    Implements IServicioRemotoVentas        
    Public Sub New()
        MyBase.New()
        Thread.CurrentThread.CurrentCulture = New CultureInfo("es-PE", False)
    End Sub

Surely this Thread.CurrentThread.CurrentCulture = New CultureInfo("es-PE", False), must be there for something. Now I would like to know if you have used something like that in Web API before? if so how and where did you put such a configuration.

These are the settings on my pc :

enter image description here

enter image description here

And these are the server settings:

enter image description here enter image description here

I almost forgot to mention that I pass all the dates using this format yyyy/M/d with all the other parameters using json. Is it perhaps that when the string is deserialized in the Web API this is done using the system date format because I haven't specify the culture info to use?? or maybe it is a Json error when trying serialize/deserialize the dates??

As always, any advice or resources you could provide would be greatly appreciated.

eddy
  • 4,373
  • 16
  • 60
  • 94
  • Please, try to read this http://stackoverflow.com/a/13550990/1679310, it could give you some idea, how to set *web.config* ... maybe that could help. – Radim Köhler Jul 11 '14 at 06:47
  • @RadimKöhler Thanks, I will give it a go, but it looks like something more for asp.net MVC and my problem is with Web API – eddy Jul 11 '14 at 12:32
  • 1
    This setting, is the run-time setting, i.e. it does not matter if Asp.net, mvc, web api.. it is the way, how to say what is the default culture on a server (and runtime will care for us to set it on any thread) or if we even will use the user culture (not good way in web api where we do use JSON... culture independent format) – Radim Köhler Jul 11 '14 at 12:34
  • @RadimKöhler Thanks it works like a charm. Sorry for not trusting you right from the start. It's just that I had saw some pages that tried to change this in the WebApiConfig.cs or Global.asax that I thought you had misunderstood what I had described in my question. So thank you very much and once again SORRY – eddy Jul 11 '14 at 17:05

2 Answers2

13

As discussed in the comments, the ASP.NET runtime does have a solution for these scenarios: it is the web.cofig element <globalization> - (see MSDN <globalization> Element)

It's structure is defined as:

<configuration>
 <system.web>
  <globalization 
    enableClientBasedCulture="true|false"
    requestEncoding="any valid encoding string"
    responseEncoding="any valid encoding string"
    fileEncoding="any valid encoding string"

    responseHeaderEncoding = "any valid encoding string" 
    resourceProviderFactoryType = string
    enableBestFitResponseEncoding = "true|false"

    culture="any valid culture string"
    uiCulture="any valid culture string"/>

So, in case, that we want to force server/dev workstation to act in en-US culture we should use these explicit settings:

<globalization 
    enableClientBasedCulture="false" 
    uiCulture="en-US" 
    culture="en-US" />

This will use the proper (desired and set) culture for any http request.

Also interesting could be the default setting overview:

<globalization 
    requestEncoding="utf-8" 
    responseEncoding="utf-8" 
    fileEncoding="" 
    culture="" 
    uiCulture="" 
    enableClientBasedCulture="false" 
    responseHeaderEncoding="utf-8" 
    resourceProviderFactoryType="" 
    enableBestFitResponseEncoding="false" />

See also similar here:

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
2

It is mentioned in your question that the input is a string not a datetime object ("I almost forgot to mention that I pass all the dates using this format yyyy/M/d"). Your service interface isn't posted but I guess that the parameter type is DateTime and this is why the deserialization is incorrect.

Although the setting posted by Radim works it's not a fix but a hack/workaround.

There are two recommended ways to implement this:

  1. Use strings at both ends, i.e. the API parameter should also be string and the API specification should state what date format to use. Use DateTime.Parse(String, IFormatProvider) and specify the culture in contract (i.e. new CultureInfo("es-PE")) when the input string is converted to DateTime. https://msdn.microsoft.com/en-gb/kc8s65zs

  2. Use date objects at both ends. In this case the serializer will serialize the date object to a well known, culture independent format and the desrializer will deserialize the string to correct DateTime object.

    public void GetOrders(DatetTime fromDate)

I'd go with #2 because is generic and doesn't force the client to use a specific culture.

See also: The "right" JSON date format

Community
  • 1
  • 1
user3285954
  • 4,499
  • 2
  • 27
  • 19