2014-06-09 24 views
21

我有一個更新用戶首選項的Web API服務調用。不幸的是,當我從jQuery ajax調用中調用POST方法時,請求參數對象的屬性始終爲空(或默認值),而不是傳入的內容。如果我使用REST客戶機(我使用Postman)調用相同的確切方法, ,它的作品非常漂亮。我不知道我在做什麼錯,但我希望以前有人看到過。這是相當簡單的......Web API複雜參數屬性全爲空

這裏是我的請求對象:

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'等),但請求對象的屬性總是默認或爲空。因此,例如,如果我通過在該對象:

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個控制器類,並且這些文章可以在所有這些類中工作......

+3

你的ajax文章的內容類型是什麼,如果我沒有弄錯jquery默認是url-form-encoding,你想要的是application/json嗎? – Dalorzo

+0

這是json。正如我所提到的,我已經嘗試過指定content-type:'json',content-type:'application/json',並且我得到了相同的結果,或者兩者都不相同。 – Eddie

+0

檢查此可能的原因[WebApi發佈配置](http://stackoverflow.com/a/23925564/1959948) – Dalorzo

回答

40

這似乎是關於Asp.Net WebAPI的常見問題。
通常,null對象的原因是將json對象反序列化爲C#對象。不幸的是,調試非常困難 - 並因此找到問題所在。
我更喜歡只發送完整的json作爲對象,然後手動反序列化。至少這樣你會得到真正的錯誤而不是空值。
如果你改變你的方法簽名接受一個對象,然後使用JsonConvert:

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

我試過了,它在使用Postman的REST調用中繼續工作,但是在jQuery中,模型在Post方法中爲null,所以我在Json.net反序列化嘗試中遇到了異常。我將開始仔細檢查兩個調用中的頭文件,以查看我是否可以找出jQuery調用中的不同之處,或者爲什麼郵遞員調用可以工作... – Eddie

+0

使用此方法以及Dalorzo對客戶端的上面建議,我是能夠得到它的工作。謝謝! – Eddie

+5

Sheesh ...這看起來像是REST框架的基本特徵。 Web API如何無法做到這一點?無論如何感謝您的解決方法! – McGarnagle

3

我猜問題是,你的控制器期待的內容類型的[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可能不是最佳實踐。

+0

謝謝安舒爾 - 我實際上已經開始沒有[FromBody]屬性,但稍後添加它希望它能解決問題。不幸的是,無論是否得到相同的結果。我很好奇,如果你傳遞一個複雜的對象到一個Web API方法,你將如何創建在Ajax調用中使用的對象,如果不是在JavaScript中? – Eddie

+0

Eddie你需要使用一個好的MVVM(模型視圖模型)庫,我使用knockout.js http://knockoutjs.com/和映射覆雜對象到JavaScript我使用它的映射插件http:// knockoutjs。 COM /文檔/插件,mapping.html。通過使用這個我不需要擔心模型的同步 –

0

由於這個問題讓我幾乎在昨天整整一個工作日都感到困擾,所以我想添加一些可能在相同情況下幫助其他人的東西。

我使用Xamarin Studio來創建我的角度和web api項目。在調試過程中,對象有時會通過空值,並在其他時間作爲填充對象。只有當我開始在Visual Studio中調試我的項目時,我的對象在每個帖子請求中都被填充。這在Xamarin Studio中調試時似乎是個問題。

如果您正在運行到另一個IDE的空參數問題,請嘗試在Visual Studio中進行調試。

7

也許它會幫助,我有同樣的問題。

一切都很好,突然間,每個屬性都是默認的。

一些簡單的測試後,我發現,這是[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; 
} 
+0

這是我的。謝謝你的帖子! –

+0

你是天才! – unruledboy

2

我知道,這有點晚,但我碰到了同樣的問題。 @ blorkfish的答案也適用於我,但讓我轉向了另一種解決方案。我的複雜對象的一部分缺少無參數的構造函數。添加此構造函數後,Put和Post請求都按預期開始工作。

0

我遇到了同樣的問題。所需的修復是確保您的JSON參數類的所有序列化屬性都已獲得;組;方法明確定義。不要依賴C#自動屬性語法!希望這可以在更高版本的asp.net中得到解決。

+0

我使用'自動屬性',我沒有遇到過這樣的問題!你有這方面的實際經驗嗎,或者這只是一個'預感'? – Mahmoud

0

有點遲到了,但我有同樣的問題,並修復被宣佈的contentType在你的Ajax調用:

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"); 
    } 
3

使用這種技術發表@blorkfish偉大的工作:

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

我有一個參數Ø bject,它有幾個本地類型和幾個對象作爲屬性。這些對象具有標記爲內部的構造函數和JsonConvert。在jsonString DeserializedObject電話給了錯誤:

Unable to find a constructor to use for type ChildObjectB. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.

我改變了建設者對公衆和它現在填充參數對象時,我更換了與真實對象的對象模型參數。謝謝!

0

今天,我遇到了和你一樣的問題。當我從ajax發送POST請求時,控制器將收到空對象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來測試您的Web應用程序。 Do Empty cache and hard reload不時。