Get nullable variable DateTime serialized in WCF service responses

0

I have a WCF service with a nullable DateTime variable in a DataContract as shown below. Because of business rules this DataMember can not have the EmitDefaultValue set to true and the type must be DateTime?

[DataContract (Name = "DADOS")]
classe public Dados
{
    [DataMember (EmitDefaultValue = false, Name = "NASCIMENTO")]
    public DateTime? DtNascimento = null;
}

My DataContract is specified as below, see that I have to have two versions of the WebInvoke maintain interoperability between different systems (responses in JSON and XML format):

    [ServiceContract]
    public interface IRestService
    {
        [OperationContract (Name = "ConsultaDadosXml")]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "ConsultaDados/xml?token={token}")]
        Dados ConsultaDadosXml (token string);

        [OperationContract (Name = "ConsultaDadosJson")]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "ConsultaDados/json?token={token}")]
        Dados ConsultaDadosJson (token string);
    }

The problem is that when DtNavigation comes correctly filled with a good valid database value, everything works fine, when it comes with a null value of the database, the XML / JSON response comes without the BIRTH tag, okay, this is happening because EmitDefaultValue = false . I can set, via procedures my database to send me an empty value, but when I do this the serialized object comes with a MinDate value in the responses.

xml version:

     <DADOS>
         <NASCIMENTO> 1900-01-01T00: 00: 00 </ NASCIMENTO>
     </ DADOS>

Json version:

{
    "NASCIMENTO": "/ Date (-2208981600000-0200) /",
}

What I really need is an empty tag being shown in the responses when this value is null, because there are other systems connected in the web service trying to interpret these values, so the best solution would be to keep these variables empty as follows:

Xml:

<DADOS>
<NASCIMENTO> </ NASCIMENTO>
</ DADOS>

Json:

{
    "NASCIMENTO": "",
}

Can anyone help me with any suggestions?

    
asked by anonymous 07.05.2015 / 18:56

1 answer

0

The first idea to solve this problem would be to use an extra property, type string , decorated with [DataMember] as in the code below:

[DataContract(Name = "DADOS", Namespace = "")]
public class Dados
{
    public DateTime? DtNascimento = null;
    [DataMember(EmitDefaultValue = false, Name = "NASCIMENTO")]
    private string WireDtNascimento
    {
        set { /* nao usado */ }
        get
        {
            return this.DtNascimento == null ?
                "" :
                DtNascimento.Value.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
        }
    }
}
The problem is that since you need to use the same type in two different serialization forms, and the format of DateTime in XML (which I used in the example above) is different from the format in JSON ( \/Date(...)\/) .

There are two solutions to this problem: you can look in the call stack to see if the serializer you are using is JSON, and use that information to decide how to convert the value. It works, but it's a very big hack (you're basing your logic according to a detail of WCF implementation) that I would not advise ...

[DataContract(Name = "DADOS", Namespace = "")]
public class Dados
{
    public DateTime? DtNascimento = null;
    [DataMember(EmitDefaultValue = false, Name = "NASCIMENTO")]
    private string WireDtNascimento
    {
        set { /* nao usado */ }
        get
        {
            if (this.DtNascimento == null)
            {
                return "";
            }
            else
            {
                var usandoJson = new StackTrace().GetFrames().Any(st => st.GetMethod().DeclaringType == typeof(DataContractJsonSerializer));
                if (usandoJson)
                {
                    var millis = (long)this.DtNascimento.Value.ToUniversalTime().Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
                    var offset = this.DtNascimento.Value.Kind == DateTimeKind.Utc ? "" : this.DtNascimento.Value.ToString("%K").Replace(":", "");
                    return "/Date(" + millis + offset + ")/";
                }
                else
                {
                    return this.DtNascimento.Value.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
                }
            }
        }
    }
}

Another alternative - since you are using two methods, you can use DataContract for each response format. There will be a bit more code duplication, but you gain readability.

[DataContract(Name = "DADOS", Namespace = "")]
public class DadosJson
{
    public DateTime? DtNascimento = null;
    [DataMember(EmitDefaultValue = false, Name = "NASCIMENTO")]
    private string WireDtNascimento
    {
        set { /* nao usado */ }
        get
        {
            if (this.DtNascimento == null)
            {
                return "";
            }
            else
            {
                var millis = (long)this.DtNascimento.Value.ToUniversalTime()
                    .Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
                    .TotalMilliseconds;
                var offset = this.DtNascimento.Value.Kind == DateTimeKind.Utc ?
                    "" :
                    this.DtNascimento.Value.ToString("%K").Replace(":", "");
                return "/Date(" + millis + offset + ")/";
            }
        }
    }
}
[DataContract(Name = "DADOS", Namespace = "")]
public class DadosXml
{
    public DateTime? DtNascimento = null;
    [DataMember(EmitDefaultValue = false, Name = "NASCIMENTO")]
    private string WireDtNascimento
    {
        set { /* nao usado */ }
        get
        {
            return this.DtNascimento == null ?
                "" :
                this.DtNascimento.Value.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
        }
    }
}
[ServiceContract]
public interface IRestService
{
    [OperationContract(Name = "ConsultaDadosXml")]
    [WebGet(ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "ConsultaDados/xml?token={token}")]
    DadosXml ConsultaDadosXml(string token);

    [OperationContract(Name = "ConsultaDadosJson")]
    [WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "ConsultaDados/json?token={token}")]
    DadosJson ConsultaDadosJson(string token);
}
public class Service : IRestService
{
    public DadosXml ConsultaDadosXml(string token)
    {
        var result = new DadosXml();
        if (!"NULL".Equals(token, StringComparison.OrdinalIgnoreCase))
        {
            result.DtNascimento = DateTime.Now;
        }

        return result;
    }

    public DadosJson ConsultaDadosJson(string token)
    {
        return new DadosJson
        {
            DtNascimento =  ConsultaDadosXml(token).DtNascimento
        };
    }
}
    
07.05.2015 / 20:04