萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> ASP.NET 程式設計

ASP.NET (JScript.NET) 中 eval 無法定義變數問題解析與解決方案

前言

在 ASP.NET (JScript.NET) 頁面中使用 eval() 動態定義變數,在舊版 JScript (Classic ASP) 可行,但在 JScript.NET 「快速模式」下會失敗。本文解析根本原因、快速模式限制,並提供三種解決方案:物件屬性動態擴充、expando 物件、關閉快速模式 (不建議)。

一、現象重現

<%@ Page Language="JScript" %>
<script runat="server">
    eval("var f1=1, f2=2, f3=3;");
    Response.Write(f1 + "<br/>"); // 編譯錯誤:'f1' 未定義
</script>

錯誤訊息:JS1008: 'f1' is not declared 或 eval 方法不能在封閉範圍內定義標識符。

二、根本原因:JScript.NET 快速模式限制

ASP.NET 預設以 快速模式 編譯 JScript.NET,限制包括:

  • 所有變數必須靜態宣告 (無隱含全域變數)。
  • eval() 在「受限安全上下文」執行,且 無法在封閉範圍建立新識別符 (變數/函數)。
  • eval 內定義的變數僅在該次呼叫存活,呼叫結束即銷毀。
  • 內建物件 (String、Array 等) 禁止 expando 屬性 (動態新增屬性)。

參考:MSDN: 升級先前的 JScript 版本中建立的應用程式

三、解決方案 1:使用物件動態屬性 (推薦)

<%@ Page Language="JScript" %>
<script runat="server">
    // 建立一個空物件作為容器
    var T = new Object();

    // 動態新增屬性 (相當於變數)
    T.F1 = 1;
    T.F2 = 2;
    T.F3 = 3;

    // 存取
    Response.Write("F1 = " + T.F1 + "<br/>");
    Response.Write("F2 = " + T.F2 + "<br/>");
    Response.Write("F3 = " + T.F3 + "<br/>");

    // 迴圈動態產生大量欄位
    for (var i = 0; i < 12; i++) {
        var key = "F" + i.toString().padStart(3, '0'); // F000, F001...
        T[key] = i + 1000;
    }
    for (var i = 0; i < 12; i++) {
        var key = "F" + i.toString().padStart(3, '0');
        Response.Write(T[key] + "<br/>");
    }
</script>

優點:符合快速模式規則、IntelliSense 友善、可序列化為 JSON、無安全性風險。

四、解決方案 2:ExpandoObject (需 .NET 4.0+ / 引用 System.Core)

<%@ Page Language="JScript" %>
<%@ Import Namespace="System.Dynamic" %>
<script runat="server">
    dynamic bag = new System.Dynamic.ExpandoObject();
    bag.F1 = 1;
    bag.F2 = 2;
    bag.DynamicMethod = new Func<string>(() => "Hello");
    Response.Write(bag.F1 + " " + bag.DynamicMethod());
</script>

五、解決方案 3:關閉快速模式 (僅限命令列編譯,ASP.NET 不支援)

// 命令列編譯器
jsc.exe /fast- MyScript.js
// 或在 web.config (僅理論上,ASP.NET 執行階段強制快速模式)
<system.web>
  <compilation debug="true">
    <compilers>
      <compiler language="JScript" extension=".js" type="Microsoft.JScript.JScriptCodeProvider, Microsoft.JScript, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" compilerOptions="/fast-" />
    </compilers>
  </compilation>
</system.web>

警告:ASP.NET 執行階段為穩定性強制啟用快速模式,compilerOptions="/fast-" 在 ASP.NET 中不生效,且會導致效能下降、執行緒安全問題。

六、從資料庫欄位動態建立變數的最佳實踐

<%@ Page Language="JScript" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<script runat="server">
    // 模擬從 DB 取得欄位名稱
    string[] fields = { "UserId", "UserName", "Email", "CreateDate" };

    // 使用 Dictionary 做強型別容器
    var record = new System.Collections.Generic.Dictionary<string, object>();

    // 填充資料 (實際從 DataReader 讀取)
    record["UserId"] = 1001;
    record["UserName"] = "Admin";
    record["Email"] = "admin@example.com";
    record["CreateDate"] = DateTime.Now;

    // 輸出
    foreach (var kv in record)
        Response.Write($"{kv.Key} = {kv.Value}<br/>");
</script>

七、總結建議

  1. 棄用 eval:JScript.NET 快速模式下 eval 受限且效能差,且有安全風險 (XSS/注入)。
  2. 改用物件/字典/ExpandoObject:動態屬性、強型別、可序列化、除錯友善。
  3. 新專案請改用 C# / VB.NET:JScript.NET 已停止更新,工具鏈、社群支援極少。
  4. 遷移既有專案:逐頁將 <%@ Language=JScript %> 改為 C#,將 eval 邏輯重構為物件操作。
copyright © 萬盛學電腦網 all rights reserved