将C# ASP.NET数组传递给Javascript数组

43

请问有人知道如何将C# ASP.NET的数组传递给JavaScript数组吗?如果能提供示例代码就更好了。

如果我之前表述不够清晰,非常抱歉。实际上,问题非常简单。假设在我的 aspx.cs 文件中我声明了:

int [] numbers = new int[5];

现在我想将numbers传递到客户端,并在JavaScript中使用数组中的数据。我该如何做?


你是在谈论将数据序列化为JSON吗? - Steven Sudit
我认为我们需要更多的细节。你想从代码后台传递到aspx,还是想使用AJAX将数据数组发送到javascript...或者完全不同的东西? - samandmoore
抱歉之前表述不够清晰。 - locoboy
9个回答

58

使用System.Web.Script.Serialization.JavaScriptSerializer类将其序列化,并赋值给javascript变量。

示例:

<% var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); %>
var jsVariable = <%= serializer.Serialize(array) %>;

抱歉有些含糊不清,请参见上文。 - locoboy
@zerkms,你能解释一下发生了什么吗?抱歉,我对此很菜。 - locoboy
@zerkms - 请考虑编辑此答案,使其完整,并突出显示它支持任意类型的事实。 - Alexei Levenkov

18
这是为了补充zerkms的答案。
要跨越语言障碍传递数据,您需要一种将数据序列化为字符串的方法。 JavaScript的一种序列化方法是JSON。在zerkms的示例中,代码将放置在aspx页面内。要在一个aspx页面上将他的示例和你的示例结合起来,你需要使用以下代码:
<%
    int[] numbers = new int[5];
    // Fill up numbers...

    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
%>

在 aspx 页面的稍后位置

<script type="text/javascript">
    var jsVariable = <%= serializer.Serialize(numbers) %>;
</script>

然而,这个答案假定您是在初始页面加载时生成JavaScript。根据您帖子中的评论,这可以通过AJAX完成。在这种情况下,您将使服务器响应序列化的结果,并使用您喜欢的框架在JavaScript中反序列化它。

注意: 也不要将此标记为答案,因为我想要语法高亮来使另一个答案更清晰。


你的意思是:var jsVariable = <%=serializer.Serialize(numbers)%> 吗? - locoboy
另外,你所说的从初始页面加载生成JS是什么意思? - locoboy
不可以,因为你处于生成 JavaScript 的上下文中。当你有 int[] numbers = new int[5] { 1, 3, 5, 7, 9 },序列化它会给你 "[1, 3, 5, 7, 9]"。所以生成的 JavaScript 变成了 "var jsVariable = [1, 3, 5, 7, 9];"。 - Anh-Kiet Ngo
更正一下,你是对的,serializer.Serialize(numbers) 后面需要加上分号。我误读了,以为你是指前面需要加上分号。我已经更正了代码。 - Anh-Kiet Ngo
由于某些原因,这不起作用。int[] 在后端(aspx.cs 文件)上,并且我还在 cs 文件中声明了序列化器。当我编写脚本标记时,会出现“int[] 在当前上下文中不存在”的错误。 - locoboy

17
您可以在Page_Load中使用ClientScript.RegisterStartupScript将JavaScript注入到页面中。
这是链接到MSDN参考文献的链接: http://msdn.microsoft.com/en-us/library/asz8zsxy.aspx 以下是Page_Load中的代码:
  List<string> tempString = new List<string>();
  tempString.Add("Hello");
  tempString.Add("World");

  StringBuilder sb = new StringBuilder();
  sb.Append("<script>");
  sb.Append("var testArray = new Array;");
  foreach(string str in tempString)
  {
    sb.Append("testArray.push('" + str + "');");
  }
  sb.Append("</script>");

  ClientScript.RegisterStartupScript(this.GetType(), "TestArrayScript", sb.ToString());

提示:使用StringBuilder构建脚本字符串,因为它可能会很长。

以下是检查注入数组“testArray”的Javascript代码,在你使用它之前需要先检查:

if (testArray)
{
  // do something with testArray
}

这里有两个问题:

  1. 一些人认为在C#中注入JavaScript会很烦人

  2. 我们必须在全局上下文中声明数组

如果你不能接受这些问题,另一个方法是让C#代码将数组保存到ViewState中,然后让JavaScript使用PageMethods(或Web服务)回调服务器来获取那个ViewState对象作为数组。但我认为对于这样的事情,这可能过度了。


2
@Gary:我的担忧在于临时序列化。如果该列表中的字符串包含单引号,我们就会遇到问题。这就是为什么使用JSON序列化器更安全的原因。 - Steven Sudit
1
@cfarm54:如果你看一下我们声明testArray数组的位置,它是Javascript中的全局变量。而且,"this"在这种情况下指的是页面。如果你把它放在用户控件中,它将返回用户控件类型;将代码注册到控件而不是页面。 - Gary
谢谢大家,这很有道理。实际问题是我在.cs文件中调用了一个返回双精度数组的Web服务。如果我将其推入JavaScript中(在那里我可以使用漂亮的Google散点图),那么如果我也使用JS来处理页面上的其他组件,这会干扰它们吗?我假设只有在声明另一个具有相同名称的JS数组时才会影响它... - locoboy
1
@cfarm54:它不应该影响其他脚本。这相当于在页面上有多个<script>部分或多个.js文件。如果您多次调用RegisterClientScript,请确保第二个参数(在本例中为“TestArrayScript”)与其他RegisterClientScript的唯一性。 如果我的回答有帮助,请点赞/标记答案!我正在努力获取足够的积分来发表评论 :) 谢谢! - Gary
1
@Gary:我的关注点在于正确性,而不是大小。由于OP正在使用双精度浮点数并进行转换,因此似乎没有任何注入的风险。 - Steven Sudit
显示剩余4条评论

11
在页面文件中:
<script type="text/javascript">
    var a = eval('[<% =string.Join(", ", numbers) %>]');
</script>

在后台代码中:

public int[] numbers = WhatEverGetTheArray();

我不确定我理解这个答案...你能带我走一遍吗? - locoboy
@cfarm54-在代码后台,您初始化了名为numbers的int[]。然后在javascript中,string.Join(“,”,numbers)使“numbers”数组成为像“1,2,3,4”这样的字符串。之后,我们使用eval('[1,2,3,4]')将类似数组的字符串转换为数组。 - Cheng Chen
变量"a"将是精确的js数组。您可以对其使用任何数组操作,例如a[0] a[1] a.length。 - Cheng Chen

9

对于对象数组:

var array= JSON.parse('@Newtonsoft.Json.JsonConvert.SerializeObject(numbers)'.replace(/&quot;/g, "\""));

对于整数数组:

 var array= JSON.parse('@Newtonsoft.Json.JsonConvert.SerializeObject(numbers)');

4

准备一个数组(在我的情况下是2D数组):

        // prepare a 2d array in c#
        ArrayList header = new ArrayList { "Task Name", "Hours"};
        ArrayList data1 = new ArrayList {"Work", 2};
        ArrayList data2 = new ArrayList { "Eat", 2 };
        ArrayList data3 = new ArrayList { "Sleep", 2 };
        ArrayList data = new ArrayList {header, data1, data2, data3};
        // convert it in json
        string dataStr = JsonConvert.SerializeObject(data, Formatting.None);
        // store it in viewdata/ viewbag
        ViewBag.Data = new HtmlString(dataStr);   

在视图中解析它。

<script>    
    var data = JSON.parse('@ViewBag.Data');
    console.log(data);
</script>

在您的情况下,您可以直接使用变量名而不是 ViewBag.Data。

4

我曾经遇到过类似的情况,而且我很容易地解决了它。这是我所做的。 假设你已经在aspx.cs页面中拥有了数组中的值。

1)在你的aspx页面中添加一个隐藏域,并使用隐藏域ID来存储数组值。

 HiddenField2.Value = string.Join(",", myarray);

2) 现在隐藏字段已经存储了值,只需用逗号分隔即可。在JavaScript中使用这个隐藏字段时,请按如下方式操作。简单地在JavaScript中创建一个数组,然后通过去除逗号将该值存储在该数组中。

var hiddenfield2 = new Array();
hiddenfield2=document.getElementById('<%=HiddenField2.ClientID%>').value.split(',');

这应该能解决你的问题。

谢谢,有了所有新的MVC和其他技术,我忘记了这个经典:P - Robert Benyi

0

简单

整数数组很容易传递。但是这个解决方案也适用于更复杂的数据。在您的模型中:

public int[] Numbers => new int[5];

在你的观点中:

numbers = @(new HtmlString(JsonSerializer.Serialize(Model.Numbers)))

可选项

传递字符串的技巧。您可能想要JSON编码器不对字符串中的某些符号进行转义。例如,我希望使用未经转义的西里尔字母。在您的视图中:

strings = @(
new HtmlString(
    JsonSerializer.Serialize(Model.Strings, new JsonSerializerOptions
    {
        Encoder = JavaScriptEncoder.Create(
            UnicodeRanges.BasicLatin,
            UnicodeRanges.Cyrillic)
    })))

0

这里是另一个替代方案。你可以使用ClientScriptManager Page.ClientScript.RegisterArrayDeclaration。以下是图表数据的示例。

var page = HttpContext.Current.CurrentHandler as Page;

_data = "[Date.UTC(2018, 9, 29, 0, 3), parseFloat(21.84)]
         ,[Date.UTC(2018, 9, 29, 0, 13), parseFloat(21.84)]
         ,[Date.UTC(2018, 9, 29, 0, 23), parseFloat(21.83)]
         ,[Date.UTC(2018, 9, 29, 0, 33), parseFloat(21.83)]";
page.ClientScript.RegisterArrayDeclaration("chartdata0", _data);

这段代码在客户端创建了一个数组。
var chartdata0 = new Array([Date.UTC(2018, 9, 29, 0, 3), parseFloat(21.84)]
             ,[Date.UTC(2018, 9, 29, 0, 13), parseFloat(21.84)]
             ,[Date.UTC(2018, 9, 29, 0, 23), parseFloat(21.83)]
             ,[Date.UTC(2018, 9, 29, 0, 33), parseFloat(21.83)]);

请查看以下文章。

https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.clientscriptmanager.registerarraydeclaration?view=netframework-4.8

这个解决方案在Chrome 64浏览器(包括“版本78.0.3904.70(官方构建)(64位)”)上使用更大的数组时存在问题。您可能会遇到“未捕获的RangeError:超过最大调用堆栈大小”。但是,在IE11,Microsoft Edge和FireFox中可以正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接