简体   繁体   中英

Put/Post json not working with ODataController if Model has Int64

I have this Data Object with an Int64 column:

[TableAttribute(Name="dbo.vw_RelationLineOfBusiness")]
[DataServiceKey("ProviderRelationLobId")] 
public partial class RelationLineOfBusiness
{

    #region Column Mappings
    private System.Guid _Lineofbusiness;
    private System.String _ContractNumber;
    private System.Nullable<System.Int32> _ProviderType;
    private System.String _InsuredProviderType;
    private System.Guid _ProviderRelationLobId;
    private System.String _LineOfBusinessDesc;
    private System.String _CultureCode;
    private System.String _ContractDesc;
    private System.Nullable<System.Guid> _ProviderRelationKey;
    private System.String _ProviderRelationNbr;
    **private System.Int64 _AssignedNbr;**

When I post/Put object through my OData controller using HttpClient and NewtsonSoft:

partial class RelationLineOfBusinessController : ODataController {

public HttpResponseMessage PutRelationLineOfBusiness([FromODataUri] System.Guid key, Invidasys.VidaPro.Model.RelationLineOfBusiness entity)

the entity object is null and the error in my modelstate :

"Cannot convert a primitive value to the expected type 'Edm.Int64'. See the inner exception for more details."

I noticed when I do a get on my object using the below URL:

Invidasys.Rest.Service/VidaPro/RelationLineOfBusiness(guid'c6824edc-23b4-4f76-a777-108d482c0fee')

my json looks like the following - I noticed that the AssignedNbr is treated as a string.

{ "odata.metadata":"Invidasys.Rest.Service/VIDAPro/$metadata#RelationLineOfBusiness/@Element", "Lineofbusiness":"ba129c95-c5bb-4e40-993e-c28ca86fffe4","ContractNumber":null,"ProviderType":null, "InsuredProviderType":"PCP","ProviderRelationLobId":"c6824edc-23b4-4f76-a777-108d482c0fee", "LineOfBusinessDesc":"MEDICAID","CultureCode":"en-US","ContractDesc":null, "ProviderRelationKey":"a2d3b61f-3d76-46f4-9887-f2b0c8966914","ProviderRelationNbr":"4565454645", "AssignedNbr":"1000000045" ,"Ispar":true,"ProviderTypeDesc":null,"InsuredProviderTypeDesc":"Primary Care Physician", "StartDate":"2012-01-01T00:00:00","EndDate":"2014-01-01T00:00:00","Created":"2014-06-13T10:59:33.567", "CreatedBy":"Michael","Updated":"2014-06-13T10:59:33.567","UpdatedBy":"Michael" }

When I do a PUT with httpclient the JSON is showing up in my restful services as the following and the json for the AssignedNbr column is not in quotes which results in the restful services failing to build the JSON back to an object. I played with the JSON and put the AssignedNbr in quotes and the request goes through correctly.

{ "AssignedNbr":1000000045 ,"ContractDesc":null,"ContractNumber":null,"Created":"/Date(1402682373567-0700)/", "CreatedBy":"Michael","CultureCode":"en-US","EndDate":"/Date(1388559600000-0700)/","InsuredProviderType":"PCP", "InsuredProviderTypeDesc":"Primary Care Physician","Ispar":true,"LineOfBusinessDesc":"MEDICAID", "Lineofbusiness":"ba129c95-c5bb-4e40-993e-c28ca86fffe4","ProviderRelationKey":"a2d3b61f-3d76-46f4-9887-f2b0c8966914", "ProviderRelationLobId":"c6824edc-23b4-4f76-a777-108d482c0fee","ProviderRelationNbr":"4565454645","ProviderType":null, "ProviderTypeDesc":null,"StartDate":"/Date(1325401200000-0700)/","Updated":"/Date(1408374995760-0700)/","UpdatedBy":"ED"}

The reason we wanted to expose our business model as restful services was to hide any data validation and expose all our databases in format that is easy to develop against. I looked at the DataServiceContext to see if it would work and it does but it uses XML to communicate between the restful services and the client. Which would work but DataServiceContext does not give the level of messaging that HttpRequestMessage/HttpResponseMessage gives me for informing users on the errors/missing information with their post.

We are planning on supporting multiple devices from our restful services platform but that requires that I can use NewtonSoft Json as well as Microsoft's DataContractJsonSerializer if need be.

My question is for a restful service standpoint - is there a way I can configure/code the restful services to take in the AssignedNbr as in JSON as without the quotes.

Or from a JSON standpoint is their a way I can get the JSON built without getting into the serializing business nor do I want our clients to have deal with custom serializers if they want to write their own apps against our restful services.

Any suggestions?

Thanks.

I think you can migrate to Web API 2.2 for OData V4. Here's the information:

Announcing the Release of ASP.NET MVC 5.2, Web API 2.2 and Web Pages 3.2

OData V4 Spec says:

3.2 Controlling the Representation of Numbers

The IEEE754Compatible=true format parameter indicates that the service MUST serialize Edm.Int64 and Edm.Decimal numbers (including the odata.count, if requested) as strings. If not specified, or specified as IEEE754Compatible=false, all numbers MUST be serialized as JSON numbers.

This enables support for JavaScript numbers that are defined to be 64-bit binary format IEEE 754 values [ ECMAScript ] (see section 4.3.1.9) resulting in integers losing precision past 15 digits, and decimals losing precision due to the conversion from base 10 to base 2. OData JSON payloads that format Edm.Int64 and Edm.Decimal values as strings MUST specify this format parameter in the media type returned in the Content-Type header.

So, for payload as:

@"{ 
    ""Lineofbusiness"": ""ba129c95-c5bb-4e40-993e-c28ca86fffe4"",
    ""AssignedNbr"": ""1000000045""
  }";

you should set:

request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;IEEE754Compatible=true");

Otherwise, you shouldn't.

Sam Xu is exactly right and should be marked as the answer.

However, I wanted to add exactly what you need to do to add this to the pipeline.

First, you can set this global, per route etc. You can find that information here: http://www.asp.net/web-api/overview/advanced/http-message-handlers

Below you'll find an example that will work.

public static void Configuration(IAppBuilder builder)
    {
        HttpConfiguration config = new HttpConfiguration();       

        config.MessageHandlers.Add(new MethodOverrideHandler());
    }

public class MethodOverrideHandler : DelegatingHandler
{       
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;IEEE754Compatible=true");

        return base.SendAsync(request, cancellationToken);
    }
}

Alternatively, try changing the type you send to your web api to Number instead of string

Also, check the Type of the decimal that you are sending. If it's type 'string' you can change it to type number. For my service, making this change no longer throws the error.

//Gnuget Package Manager Install-Package numeral  

if (typeof newValue === 'string') 
{
newValue = numeral().unformat(newValue);
}

  odatajs.oData.request(
             {
                 requestUri: xxx,
                 method: "PATCH",
                 data: { PriceNull: newValue }
             }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM