ASP.NET Core MVC中Microsoft.ClearScript.V8的LINQ使用及报错解决
在ASP.NET Core MVC中使用ClearScript V8获取JS返回结果并使用LINQ
问题场景
在ASP.NET Core MVC项目中使用Microsoft.ClearScript.V8执行JS脚本,调用NewLinq()返回过滤后的数组时,触发以下错误:
UnderlyingSystemType = '((Microsoft.ClearScript.ScriptItem)data).UnderlyingSystemType' threw an exception of type 'System.NotImplementedException'
原控制器代码:
public async Task<IActionResult> Index() { using (var engine1 = new V8ScriptEngine()) { engine1.AddHostType(typeof(JavaScriptExtensions)); engine1.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading; string scriptPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "js", "NewScript.js"); string scriptContent = System.IO.File.ReadAllText(scriptPath); engine1.Execute(scriptContent); dynamic data = engine1.Evaluate("NewLinq();"); return View(); } }
JS脚本NewScript.js代码:
function NewLinq() { const rawData = [ { "id": 1, "name": "John", "age": 25 }, { "id": 2, "name": "Jane", "age": 30 } ]; var result = rawData.filter(person => person.age > 25); return result; }
错误原因
ClearScript返回的dynamic对象是V8引擎的脚本对象包装,并非原生CLR集合类型,直接访问其内部属性或尝试用LINQ操作会触发未实现的异常。
解决方案
需要将V8返回的脚本对象显式转换为CLR可识别的集合类型,推荐两种实现方式:
方式1:强类型转换(推荐,便于LINQ操作)
- 定义对应JS对象的实体类:
public class Person { public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
- 修改控制器代码,转换为强类型集合:
public async Task<IActionResult> Index() { using (var engine1 = new V8ScriptEngine()) { engine1.AddHostType(typeof(JavaScriptExtensions)); engine1.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading; string scriptPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "js", "NewScript.js"); string scriptContent = System.IO.File.ReadAllText(scriptPath); engine1.Execute(scriptContent); // 将V8脚本数组转换为CLR可枚举类型 var scriptResult = engine1.Evaluate("NewLinq();") as IEnumerable<dynamic>; // 转换为强类型集合 var personList = scriptResult.Select(item => new Person { Id = (int)item.id, Name = (string)item.name, Age = (int)item.age }).ToList(); // 正常使用LINQ操作 var filteredPersons = personList.Where(p => p.Age >= 30).ToList(); return View(filteredPersons); } }
方式2:使用ScriptObject直接处理
如果不需要强类型,也可以通过ScriptObject访问属性并转换:
public async Task<IActionResult> Index() { using (var engine1 = new V8ScriptEngine()) { engine1.AddHostType(typeof(JavaScriptExtensions)); engine1.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading; string scriptPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "js", "NewScript.js"); string scriptContent = System.IO.File.ReadAllText(scriptPath); engine1.Execute(scriptContent); var scriptArray = engine1.Evaluate("NewLinq();") as ScriptObject; var dataList = new List<dynamic>(); foreach (var item in scriptArray) { var person = new { Id = (int)((ScriptObject)item)["id"], Name = (string)((ScriptObject)item)["name"], Age = (int)((ScriptObject)item)["age"] }; dataList.Add(person); } // LINQ操作示例 var result = dataList.Where(p => p.Age > 25).ToList(); return View(result); } }
内容的提问来源于stack exchange,提问作者user21912510
相关产品推荐
相关产品推荐

