Web API复杂参数属性均为null

时间:2014-06-09 22:14:58

标签: c# jquery ajax json asp.net-web-api

我有一个Web API服务调用,用于更新用户的首选项。不幸的是,当我从jQuery ajax调用中调用此POST方法时,请求参数对象的属性始终为null(或默认值),而不是传入的内容。如果我使用REST客户端调用相同的方法(我使用Postman),它工作得很漂亮。我无法弄清楚我做错了什么,但我希望有人之前见过这个。这很简单......

这是我的请求对象:

public class PreferenceRequest
{
    [Required]
    public int UserId;

    public bool usePopups;
    public bool useTheme;
    public int recentCount;
    public string[] detailsSections;
}

这是UserController类中的控制器方法:

    public HttpResponseMessage Post([FromBody]PreferenceRequest request)
    {
        if (request.systemsUserId > 0)
        {
            TheRepository.UpdateUserPreferences(request.UserId, request.usePopups, request.useTheme,
                                         request.recentCount, request.detailsSections);

            return Request.CreateResponse(HttpStatusCode.OK, "Preferences Updated");                
        }
        else
        {
            return Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "You must provide User ID");
        }
    }

这是我的ajax电话:

var request = {
    UserId: userId,
    usePopups: usePopups,
    useTheme: useTheme,
    recentCount: recentCount,
    detailsSections: details
};

$.ajax({
    type: "POST",
    data: request,
    url: "http://localhost:1111/service/User",
    success: function (data) {
        return callback(data);
    },
    error: function (error, statusText) {
        return callback(error);
    }
});

我尝试过设置dataType& contentType到几个不同的东西(' json',' application / json'等)但是请求对象的属性总是默认为null或null。所以,例如,如果我传入这个对象:

var request = {
  UserId: 58576,
  usePopups: false,
  useTheme: true,
  recentCount: 10,
  detailsSections: ['addresses', 'aliases', 'arrests', 'events', 'classifications', 'custody', 'identifiers', 'phone', 'remarks', 'watches']
}

我可以看到一个完全填充的请求对象,其中包含上面列出的有效值。但是在Web API控制器中,请求就在那里,但属性如下:

  UserId: 0,
  usePopups: false,
  useTheme: false,
  recentCount: 0,
  detailsSections: null

仅供参考 - 我没有在这个项目中使用任何ASP.Net MVC或ASP.NET页面,只使用Web API作为服务并使用jQuery $ .ajax进行所有调用。

知道我在这里做错了什么吗?谢谢!

更新:我只想说明我在其他控制器的同一个Web API项目中有很多方法可以执行此操作完全相同的事情,我正在调用完全相同,它们完美无缺!我花了一个上午比较各种调用,并且方法或标题似乎没有任何区别,但它只是不适用于这种特定的方法。

我也尝试过切换到Put方法,但我得到完全相同的结果 - 请求对象进来,但没有填充正确的值。令人沮丧的是,我在这个项目中有大约20个控制器类,并且帖子在所有这些中工作......

18 个答案:

答案 0 :(得分:52)

这似乎是Asp.Net WebAPI的常见问题 通常,null对象的原因是将json对象反序列化为C#对象。不幸的是,它很难调试 - 因此找到你的问题所在 我更喜欢将完整的json作为对象发送,然后手动反序列化。至少这样你会得到真正的错误而不是空值 如果更改方法签名以接受对象,则使用JsonConvert:

public HttpResponseMessage Post(Object model)
        {
            var jsonString = model.ToString();
            PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
        }

答案 1 :(得分:10)

也许它会有所帮助,我遇到了同样的问题。

一切都运作良好,突然之间,每个房产都被拖欠了。

经过一些快速测试后,我发现导致问题的是[Serializable]

public IHttpActionResult Post(MyComplexClass myTaskObject)
{
    //MyTaskObject is not null, but every member are (the constructor get called).
}

这是我班级的片段:

[Serializable]  <-- have to remove that [if it was added for any reason..]
public class MyComplexClass()
{
     public MyComplexClass ()
     {
        ..initiate my variables..
     }

     public string blabla {get;set;}
     public int intTest {get;set;
}

答案 2 :(得分:4)

我想问题是你的控制器期待[FromBody]的内容类型,尝试将你的控制器更改为

public HttpResponseMessage Post(PreferenceRequest request)

和ajax到

$.ajax({
    type: "POST",
    data: JSON.stringify(request);,
    dataType: 'json',
    contentType: "application/json",
    url: "http://localhost:1111/service/User",

顺便说一句,在javascript中创建模型可能不是最佳实践。

答案 3 :(得分:4)

使用@blorkfish发布的这项技术非常有效:

public HttpResponseMessage Post(Object model)
    {
        var jsonString = model.ToString();
        PreferenceRequest result = JsonConvert.DeserializeObject<PreferenceRequest>(jsonString);
    }

我有一个参数对象,它有几个原生类型和几个对象作为属性。对象具有标记为internal的构造函数,并且jsonString上的JsonConvert.DeserializedObject调用给出了错误:

  

无法找到用于ChildObjectB类型的构造函数。一类   应该有一个默认的构造函数,一个构造函数   参数或用JsonConstructor属性标记的构造函数。

我将构造函数更改为public,当我将Object模型参数替换为真实对象时,它现在填充参数对象。谢谢!

答案 4 :(得分:3)

因此,我知道有3个可能的问题,该值不绑定在何处:

  1. 没有无公共参数的 ctor
  2. 属性不是可公共设置的
  3. 存在绑定错误,导致ModelState.Valid == false -典型问题是:值类型不兼容(JSON对象为字符串,非GUID等)

所以我正在考虑是否应在API调用中应用一个过滤器,如果绑定导致错误,该过滤器将返回错误!

答案 5 :(得分:2)

我知道,这有点晚了,但我遇到了同样的问题。 @ blorkfish的回答也适用于我,但引导我找到了一个不同的解决方案。我的复杂对象的一部分缺少无参数构造函数。添加此构造函数后,Put和Post请求都按预期开始工作。

答案 6 :(得分:2)

派对有点晚了,但是我遇到了同样的问题,修复程序在你的ajax调用中声明了contentType:

    var settings = {
        HelpText: $('#help-text').val(),
        BranchId: $("#branch-select").val(),
        Department: $('input[name=departmentRadios]:checked').val()

    };

$.ajax({
        url: 'http://localhost:25131/api/test/updatesettings',
        type: 'POST',
        data: JSON.stringify(settings),
        contentType: "application/json;charset=utf-8",
        success: function (data) {
            alert('Success');
        },
        error: function (x, y, z) {
            alert(x + '\n' + y + '\n' + z);
        }
    });

您的API控制器可以像这样设置:

    [System.Web.Http.HttpPost]
    public IHttpActionResult UpdateSettings([FromBody()] UserSettings settings)
    {
//do stuff with your UserSettings object now
        return Ok("Successfully updated settings");
    }

答案 7 :(得分:2)

我也遇到了这个问题,经过debbug的大量研究,研究发现该问题不是由Content-Type或Type $ Ajax属性引起的,而是由JSON对象上的NULL值引起的,这是非常不礼貌的问题,因为POST既无法执行,但一旦修复了NULL值,则POST很好,并且将其本地转换为我的respuestaComparacion类,代码如下:

  

JSON

 respuestaComparacion: {
                            anioRegistro: NULL, --> cannot cast to BOOL
                            claveElector: NULL, --> cannot cast to BOOL
                            apellidoPaterno: true,
                            numeroEmisionCredencial: false,
                            nombre: true,
                            curp: NULL, --> cannot cast to BOOL
                            apellidoMaterno: true,
                            ocr: true
                        }
  

控制器

[Route("Similitud")]
[HttpPost]
[AllowAnonymous]

public IHttpActionResult SimilitudResult([FromBody] RespuestaComparacion req)
{
   var nombre = req.nombre;
}
  

班级

public class RespuestaComparacion
    {
        public bool anioRegistro { get; set; }
        public bool claveElector { get; set; }
        public bool apellidoPaterno { get; set; }
        public bool numeroEmisionCredencial { get; set; }
        public bool nombre { get; set; }
        public bool curp { get; set; }
        public bool apellidoMaterno { get; set; }
        public bool ocr { get; set; }
    }

希望获得帮助。

答案 8 :(得分:1)

我遇到了同样的问题。所需的修复是确保您的JSON到参数类的所有可序列化属性都得到;组;明确定义的方法。不要依赖C#自动属性语法!希望在以后的asp.net版本中修复此问题。

答案 9 :(得分:0)

  public class CompanyRequestFilterData
    {
             public string companyName { get; set; }
             public string addressPostTown { get; set; }
             public string businessType { get; set; }
             public string addressPostCode{ get; set; }
             public bool companyNameEndWith{ get; set; }
             public bool companyNameStartWith{ get; set; }
             public string companyNumber{ get; set; }
             public string companyStatus{ get; set; }
             public string companyType{ get; set; }
             public string countryOfOrigin{ get; set; }
             public DateTime? endDate{ get; set; }
             public DateTime? startDate { get; set; }
}

webapi控制器

    [HttpGet("[action]"),HttpPost("[action]")]
    public async Task<IEnumerable<CompanyStatusVm>> GetCompanyRequestedData(CompanyRequestFilterData filter)
    {}

jsvascript / typescript

export async function GetCompanyRequesteddata(config, payload, callback, errorcallback) {
await axios({
    method: 'post',
    url: hostV1 + 'companydata/GetCompanyRequestedData',
    data: JSON.stringify(payload),
    headers: {
        'secret-key': 'mysecretkey',
        'Content-Type': 'application/json'
    }
})
    .then(res => {
        if (callback !== null) {
            callback(res)
        }
    }).catch(err => {
        if (errorcallback !== null) {
            errorcallback(err);
        }
    })

}

这是工作中的一个c#核心3.1

我的案例是bool数据类型,而我已将字符串更改为bool [companyNameEndWith]和[companyNameStartWith],它确实起作用了。因此,请检查数据类型。

答案 10 :(得分:0)

HttpGet

public object Get([FromBody]object requestModel)
{
    var jsonstring = JsonConvert.SerializeObject(requestModel);
    RequestModel model = JsonConvert.DeserializeObject<RequestModel>(jsonstring);
}

答案 11 :(得分:0)

就我而言,添加时已解决问题

获取{}设置{}

到参数类定义:

public class PreferenceRequest
{
    public int UserId;
    public bool usePopups {get; set;}
    public bool useTheme {get; set;}
    public int recentCount {get; set;}
    public string[] detailsSections {get;set;}
}

代替:

   public class PreferenceRequest
    {
        [Required]
        public int UserId;
        public bool usePopups;
        public bool useTheme;
        public int recentCount;
        public string[] detailsSections;
    }

答案 12 :(得分:0)

我遇到了这个问题,将其解决了

  1. 使用属性[JsonProperty(“属性名称如json请求中的”) 在模型中使用nuget包newton
  2. 如果您序列化对象仅调用PostAsync

喜欢

istream& operator>>(istream& is, Temps& t){
    //assume format (max----min)
    return is >> t.max >> t.min;
}
  1. 如果不起作用,请从您的api中删除[from body]

答案 13 :(得分:0)

我的问题没有其他任何答案可以解决,因此值得考虑以下解决方案:

我有以下DTO和控制器方法:

public class ProjectDetailedOverviewDto
{
    public int PropertyPlanId { get; set; }

    public int ProjectId { get; set; }

    public string DetailedOverview { get; set; }
}

public JsonNetResult SaveDetailedOverview(ProjectDetailedOverviewDto detailedOverview) { ... }

因为我的DTO具有与参数同名的属性(detailedOverview),所以反序列化器感到困惑,并试图用字符串而不是整个复杂对象填充参数。 解决方案是将控制器方法参数的名称更改为'overview',以使反序列化器知道我没有尝试访问该属性。

答案 14 :(得分:0)

我今天也遇到了同样的问题。尝试所有这些方法之后,从Azure调试API并调试Xamarin Android应用程序,事实证明这是参考更新问题。请记住要确保您的API更新了Newtonsoft.JSON NUGET包(如果正在使用)。

答案 15 :(得分:0)

我遇到了同样的问题,我的解决方案是确保我的类属性的类型与json属性匹配,我的意思是

Json: "attribute": "true"

应该被视为字符串而不是布尔值,看起来如果你有这样的问题,故障属性下面的所有属性都将默认为null

答案 16 :(得分:0)

今天,我和你的问题一样。当我从POST发送ajax请求时,控制器会收到带有Null的空对象和默认属性值。 方法是:

[HttpPost]
public async Task<IActionResult> SaveDrawing([FromBody]DrawingModel drawing)
{


    try
    {

        await Task.Factory.StartNew(() =>
        {
            //Logic
        });
        return Ok();
    }
    catch(Exception e)
    {
        return BadRequest();
    }
}

我的Content-Type是正确的,其他一切也都是正确的。在尝试了很多东西后,我发现像这样发送对象:

$.ajax({
    url: '/DrawingBoard/SaveDrawing',
    type: 'POST',
    contentType: 'application/json',
    data: dataToPost
}).done((response) => { }); 

不会工作,但是这样发送却有效:

$.ajax({
    url: '/DrawingBoard/SaveDrawing',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify(dataToPost)
}).done((response) => { }); 

是的,丢失的JSON.stringify()导致整个问题,并且无需将=或其他任何内容作为前缀或后缀添加到JSON.stringify。 挖了一下之后。我发现请求有效负载的格式在两个请求之间完全不同 这是带有JSON.stringify

的请求有效负载

Request payload with JSON.stringify

这是没有JSON.stringify

的请求有效负载

Request payload without JSON.stringify

不要忘记,当事情变得神奇并且您使用Google Chrome来测试您的网络应用程序时。 Do Empty cache and hard reload不时{。}}

答案 17 :(得分:0)

由于这个问题昨天几乎整整一个工作日让我很烦恼,我想在同样的情况下添加可能有助于其他人的事情。

我使用Xamarin Studio创建我的角度和web api项目。在调试期间,对象有时会通过null,有时会作为填充对象。只有当我开始在Visual Studio中调试我的项目时,我的对象才会在每个帖子请求中填充。在Xamarin Studio中进行调试时,这似乎是一个问题。

如果您遇到与另一个IDE的此null参数问题,请尝试在Visual Studio中进行调试。