1

I have a simple WebApi 2.1 project and am receiving a model state error when I post and leave the value for a non-required nullable field (double type) blank. I want to leave the xml element but allow it to be blank. I had assumed making the field nullable would handle this but instead, if I post with salary left blank, I receive the error (listed below). If I put a number in... such as <salary>32000</salary> everything works as expected.

How can I allow a blank value for a nullable double and still pass model validation?

The error I receive:

System.Web.Http.ModelBinding.ModelError: "There is an error in XML document (1, 111)."

My Model:

public class Employee
{
    [Required]
    public string LastName { get; set; }

    public string MiddleName { get; set; }

    [Required]
    public string FirstName { get; set; }

    public double? Salary { get; set; }
}

My Controller Post Method:

public HttpResponseMessage Post([FromBody]Employee employee)
{
    if (ModelState.IsValid)
    {
        string firstName = employee.FirstName;
        string lastName = employee.LastName;

        if (employee.Salary != null)
        {
            double? salary = employee.Salary;
        }

        return Request.CreateResponse(HttpStatusCode.OK);
    }
    else
    {
        return Request.CreateErrorResponse(HttpStatusCode.NoContent, ModelState);
    }
}

Here is my actual Post (with headers listed):

Content-Type: application/xml
Accept-Language: en-us
Accept: application/xml

<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <LastName>Charlie</LastName>
    <MiddleName>Bravo</MiddleName>
    <FirstName>Alpha</FirstName>
    <Salary></Salary>
</Employee>
user2315985
  • 2,848
  • 5
  • 17
  • 18
  • [This blog](http://andypottsblog.blogspot.co.uk/2014/03/posting-xml-to-webapi.html) *could* be of help - particularly the part where it mentions a config update `"config.Formatters.XmlFormatter.UseXmlSerializer = true;"` –  May 21 '14 at 15:43
  • I do have config.Formatters.XmlFormatter.UseXmlSerializer = true; in my WebApiConfig. It serializes and deserializes fine unless that value is blank. – user2315985 May 21 '14 at 15:50
  • This seems related: http://stackoverflow.com/questions/1914133/can-xmlserializer-deserialize-into-a-nullableint –  May 21 '14 at 15:57
  • 1
    @user2315985 I came across the same situation on a project, as a quick fix i just changed the property type to string and dealt with it later. Its dirty but quick. I spend hours on this :( – heymega May 21 '14 at 16:19
  • As you suggested I am leaning towards changing the property to string but that just doesn't seem like the right thing to do... there should be a way to handle this in webapi. – user2315985 May 25 '14 at 02:45

2 Answers2

2

If you have to handle an empty Salary node (as opposed to a missing one), I'd change the model to the following:

public class Employee
{
    [Required]
    public string LastName { get; set; }

    public string MiddleName { get; set; }

    [Required]
    public string FirstName { get; set; }

    public string Salary { get; set; }
    public double? SalaryAmount 
    { get
       {
          if (string.IsNullOrEmpty(Salary)) return null;
          return double.parse(Salary);
       }
     ]
}

Disclaimer: I don't have VS handy so I wasn't able to validate my code.

You then have to use SalaryAmount when you are consuming the Employe instance. The reason for this is an empty XML element evaluates to string.Empty; a missing XML element evaluates to null. Double.Parse does not like empty strings which is what is causing your problem.

One other thing I'd recommend is to not use floating point when dealing with money; it introduces rounding and other problems. I'd change double to a decimal.

Jeff Siver
  • 7,434
  • 30
  • 32
1

I suggest please don't include salary node in XML if it is blank. Try it and it should work then.

Try this : user xsi:nil="true"

 Content-Type: application/xml
 Accept-Language: en-us
 Accept: application/xml

<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     <LastName>Charlie</LastName>
     <MiddleName>Bravo</MiddleName>
     <FirstName>Alpha</FirstName>
     <Salary xsi:nil="true"></Salary>
</Employee>
dotnetstep
  • 17,065
  • 5
  • 54
  • 72
  • The client has an existing process (they cannot change) that generates the XML with all elements (including salary) and I therefore i must accept their xml... sometimes with a blank and sometimes with a salary included. – user2315985 May 21 '14 at 15:42
  • Can you please let me know that if you not include Salary node it works ? – dotnetstep May 23 '14 at 01:49
  • It does work if is left out but not if is left but blank. – user2315985 May 25 '14 at 02:43