我有问题从我的javascript / jQuery请求中接收json值到我的控制器。
MyClass如下所示:
function MyClass() {
this.MyString = null;
this.MyInt = null;
this.Subs = null;
}
我的请求如下所示:
var testData1 = new MyClass();
testData1.MyInt = 1234;
testData1.MyString = "abcDEF";
testData1.Subs = new Array();
var testData2 = new MyClass();
testData2.MyInt = 5678;
testData2.MyString = "GHIjkl";
testData1.Subs.push(testData2);
var jsonData = JSON.stringify(testData1);
var self = this;
$.ajax({
url: '/Home/Request',
type: 'POST',
dataType: 'json',
data: jsonData,
contentType: 'application/json; charset=utf-8',
success: function (x) {
self.ParseResult(x);
}
});
现在我有一个控制器:
public JsonResult Request(MyClass myObj)
{
var answer = ...
return Json(answer, JsonRequestBehavior.DenyGet);
}
使用以下课程:
public class MyClass
{
public string MyString { get; set; }
public int MyInt { get; set; }
public List<MyClass> Subs { get; set; }
}
jsonData中的所有名称与我的“MyClass”类中的名称完全相同。但myObj中没有值。
问题出在哪里。有什么办法可以让这个映射正常工作吗?
非常感谢您提前,
克里斯
更新:
谢谢你的反馈。我使用过JavascriptSerializer。但我有问题,myString为null:
public JsonResult Data(string myString)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<MyClass>(myString);
var answer = ...
return Json(answer, JsonRequestBehavior.DenyGet);
}
价值在哪里?我应该从请求数据中获取值吗?
@Dave Ward
你的第二个解决方案正在运作。但我对潜艇有问题。
var testData1 = new MyClass();
testData1.MyInt = 1234;
testData1.MyString = "abcDEF";
testData1.Subs = new Array();
for (var i = 0; i < 10; i++) {
var testData2 = new MyClass();
testData2.MyInt = i;
testData2.MyString = "abcDEF";
testData1.Subs.push(testData2);
}
我的控制器中有10个Subs,但都是空的。我该怎么办?
@Dave Ward,@ ALL
使用传统设置我的10个子机器人是空的,它们不在那里。子计数为0(非NULL)。 我试图将Subs Type从List更改为IEnumerable,但这没有帮助。 你知道我还能做些什么来让我的控制器充满潜艇吗?
好的,谢谢Dave Ward,我将使用JSON方法。
对于其他有相同问题的人来说,这个控制器代码可以来自帮助:
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(myString));
var serializer = new DataContractJsonSerializer(typeof(MyClass));
MyClass se = serializer.ReadObject(ms) as MyClass;
ms.Close();
答案 0 :(得分:3)
现在,您正在发送JSON字符串作为POST的整个主体。 MVC无法连接点并理解您希望它将整个字符串作为名为myString的参数提供。
为此,请更改您的客户端数据参数,如下所示:
$.ajax({
url: '/Home/Request',
type: 'POST',
dataType: 'json',
data: { myString: jsonData },
contentType: 'application/json; charset=utf-8',
success: function (x) {
// If ParseResult is some sort of JSON deserializing, don't do that.
// When the dataType is set to 'json', jQuery handles this for you
// automatically before the success handler is called.
self.ParseResult(x);
}
});
当你提供jQuery一个对象作为它的数据参数时,它会在发送之前自动对其进行URLEncodes,所以这样的东西将被POST到服务器:
myString={json:data, here:etc}
MVC会根据需要将其选为myString参数,然后您可以继续使用JavaScriptSerializer对其进行反序列化。
此外,除非您在客户端执行的操作比您显示的更复杂,否则JavaScript类是不必要的。像这样的东西会起作用:
var testData2 = {
MyInt: 5678,
MyString: "GHIjkl",
}
var testData1 = {
MyInt: 1234,
MyString: "abcDEF",
Subs: [ testData2 ]
}
所有这一切,为什么你使用JSON的请求?如果您在动作中接受自定义类型的参数,MVC的模型绑定器非常擅长从标准URLEncoded输入数据中保护该类型:
public JsonResult Data(MyClass request)
{
// request.MyInt, request.MyString, etc should exist here.
var answer = ...
// It's okay to accept URLEncoded input parameters, but still return JSON.
return Json(answer, JsonRequestBehavior.DenyGet);
}
然后,调用它不需要客户端JSON序列化:
var testData2 = {
MyInt: 5678,
MyString: "GHIjkl",
}
var testData1 = {
MyInt: 1234,
MyString: "abcDEF",
Subs: [ testData2 ]
}
$.ajax({
url: '/Home/Request',
type: 'POST',
traditional: true,
dataType: 'json',
data: testData1
success: function (x) {
self.ParseResult(x);
}
});
它更简单,并且更快,因为您在客户端删除了一层序列化并在服务器端删除了反序列化。
答案 1 :(得分:1)
根据我的经验,我必须将json作为字符串传递,然后反序列化它。我使用Newtonsoft来执行此操作。
public ActionResult DoAjax(string jsonRequest)
{
JsonSerializer serializer = new JsonSerializer();
StringReader sr = new StringReader(jsonRequest);
Newtonsoft.Json.JsonTextReader reader = new JsonTextReader(sr);
MyClass obj = (MyClass)serializer.Deserialize(reader, typeof(MyClass));
//...do other stuff
}
答案 2 :(得分:1)
对josh的类似攻击,你可以使用json actionfilter a la:
// requires newtonsoft.json.dll
public class JsonFilter : ActionFilterAttribute
{
public string Param { get; set; }
public Type JsonDataType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext
.Request.ContentType.Contains("application/json"))
{
string inputContent;
using (var sr = new StreamReader(filterContext.HttpContext
.Request.InputStream))
{
inputContent = sr.ReadToEnd();
}
var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
filterContext.ActionParameters[Param] = result;
}
else
try
{
// we should do a loop looking for json here ONLY if there's a callback
// i.e. we're calling jsonP
if (filterContext.HttpContext.Request.QueryString["callback"] != null)
{
string inputContent =
Enumerable.Where(filterContext.HttpContext
.Request.QueryString.Keys.Cast<string>()
.Select(qs => filterContext.HttpContext
.Request.QueryString[qs]), query => !string.IsNullOrEmpty(query))
.FirstOrDefault(query => query.IndexOf("{") == 0);
var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
filterContext.ActionParameters[Param] = result;
}
}
catch (Exception e)
{
// do nothing
filterContext.ActionParameters[Param] = null;
}
}
}
用法(在本例中为typeof(IList))但可以是任何类,即typeof(myClass):
[JsonFilter(Param = "jsonData", JsonDataType = typeof(IList<FundPropertyWeekSplit>))]
public virtual ActionResult AddFundPropertyWeekSplit(IList<FundPropertyWeekSplit> jsonData)
{
// code to deal with the newly created strongly typed object
}
我在商店里使用这个(相当多!!)...
答案 3 :(得分:0)
你可以看看Omar Al Zabir关于json,xml请求和响应处理的文章,他为解决这种常见情况提供了一个非常好的解决方案。
Create REST API using ASP.NET MVC that speaks both Json and plain Xml