3

在我的控制器中,我有一个返回 JSON 数据的操作:

[HttpGet]
public ActionResult AjaxJson(){
    var ret = new List<dynamic>();

    ret.Add(new{
        Make = "Honda",
        Year = 2011,
    });

    ret.Add(new{
        Make = "BMW",
        Fun = true
    });    

    return Json(new { json = ret }, JsonRequestBehavior.AllowGet);
}

我有点担心dynamic关键字的使用,因为列表中的项目实际上是匿名类型。但是没有办法创建匿名类型的列表。

我的第二个问题(不那么重要)是,如果我将 JSON 数据作为数组返回。在客户端上,要到达Honda,我必须以这种方式引用它:data.json[0].Make

但我希望能够这样做:data.json.MyWeekdayCar.Make

我知道如果我将 JSON 数据作为对象返回(稍后列出的控制器操作),我可以使用 引用Hondadata.json.MyWeekdayCar.Make但我将失去使用data.json.length. 有没有办法两全其美 - 能够使用data.json.MyWeekdayCar.Make和计算客户端的对象数量?

控制器将 JSON 数据作为对象返回:

[HttpGet]
public ActionResult AjaxJson(){
    var ret = new{
        MyWeekdayCar = new{
            Make = "Honda",
            Year = 2011
        },
        MyWeekendCar = new{
            Make = "BMW",
            Fun = true
        },
        length = 2 // this makes client side data.json.length work, but it doesn't feel normal.
    };

    return Json(new { json = ret }, JsonRequestBehavior.AllowGet);
}

编辑

将动态列表与匿名对象一起使用是否有副作用或意外问题?

4

3 回答 3

0

因此,要回答您的第一个问题,以您正在做的方式使用动态并没有什么特别的问题。

如果不跳过一些障碍,您将无法准确实现您想要的,但是您可以使用以下几个选项:

选项 1:您可以编写如下所示的服务器端代码:

var honda = new { Make = "Honda", Year = "2011" };
var bmw = new { Make = "Bmw", Fun = true };
var array = new dynamic[] { honda, bmw };

var ret = new
{
    Cars = array,
    Length = array.Length,
    MyWeekDayCar = honda, 
    MyWeekendCar = bmw
};

然后你可以在你的javascript中使用它(不是你想要的,但关闭):

data.json.MyWeekendCar.Make, 
data.json.Cars.Length
data.json.Cars[0].Make

这种方法的缺点是您必须在服务器端非常具体,因此可能有点不灵活。但它确实涉及最少的工作。

选项 2:保持服务器端代码不变,但没有长度属性:

var ret = new {
    MyWeekdayCar = new{
        Make = "Honda",
        Year = 2011
    },
    MyWeekendCar = new{
        Make = "BMW",
        Fun = true
    }
};

然后在 javascript 中创建类作为数据的包装器,允许您以您想要的方式使用它,例如:

CarsClass.prototype = Array.prototype;   // Inherit from array type for length and other functions
function CarsClass(json) {   
    var that = this;   // very important... but you'll need to research this yourself ;)

    for (var key in json)   // loop around all the properties in the object
    {
        if (json.hasOwnProperty(key))
        {
            that[key] = json[key];   // copy each property to our new object
            that.push(json[key]);    // add each property to our internal array
        }
    }    
}

var cars = new CarsClass(  // This is just dummy data, you would use your json
{ 
    MyWeekdayCar : { Make: 'Honda', Year: '2011' },
    MyWeekendCar : { Make: 'BMW', Fun: true },
    AnotherCar: { Make: 'Skoda', FuelEfficient: true} // flexible!
});

alert(cars.MyWeekendCar.Make); // 'BMW'
alert(cars.length); // 3
alert(cars[0].Make); // 'Honda'
alert(cars[2].FuelEfficient); // True

你可以在这个 jsfiddle 中看到这个工作:http: //jsfiddle.net/m49h5/

正如您在这种方法中看到的那样,您可以在服务器端添加更多汽车,它们会被 javascript 类拾取。当然,如果您在客户端添加\删除汽车,这种方法需要更聪明。如果您确实需要这个,请告诉我,我可以提供进一步的建议

希望这可以帮助!

于 2012-12-06T09:56:55.243 回答
0

如果您想要两全其美,并且您的 json 格式不会定期更新,请查看 JSON C# 类生成器:http: //jsonclassgenerator.codeplex.com/

每次更新 json 格式时,您都可以重新生成类以供前端开发人员使用。

在前端,他们可以使用 json.net 库将您的 json 反序列化为生成的类,如下所示:

Car a = JsonConvert.DeserializeObject<Car> (json);

如果这不符合您的要求,我知道的下一个最佳解决方案是按照您的建议使用动态对象。

于 2012-12-05T21:32:14.633 回答
0

有没有办法两全其美 - 能够使用data.json.MyWeekdayCar.Make和计算客户端的对象数量?

不适用于匿名类型。您正在创建具有两个属性的匿名类型的单个对象:MyWeekdayCar它们 MyWeekendCar两种不同的匿名类型。

所以你没有对象的集合,你有一个具有两个属性的对象,它们都是不同的类型。您必须length在创建对象时添加一个属性。

可以尝试创建一个Dictionary而不是普通数组:

var ret = new Dictionary<string,dynamic>();

ret.Add("MyWekedayCar",new{
    Make = "Honda",
    Year = 2011,
});

ret.Add("MyWeekendCar",new{
    Make = "BMW",
    Fun = true
});  

然后我认为你可以访问它:

data.json.["MyWeekdayCar"].Make
data.json.length

虽然老实说,我对 JSON/JavaScript 和字典知之甚少,不知道这是否有效。如果不是,我会将其从我的答案中删除。

于 2012-12-05T21:37:20.167 回答