C#通过Jint代理实现后端运行js代码

Jint原理实际是将js转成C#代码执行,比chrome V8内核执行会更快,支持大部分流行es语法
需注意实际运行js代码,一些变量或方法可能会污染.net环境(Jint原理是js转C#执行),所以需要在独立作用域内执行,每次执行完,卸载作用域,不会污染主域。
一共分2个文件:JintProxy,  MyHelpTool

1.JintProxy:

using Jint;
using Jint.Native;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace MyHelper
{
    /// <summary>
    /// Jint独立作用域代理, 防止污染全局.net对象
    /// </summary>
    public class JintProxy: MarshalByRefObject
    {
        private  Engine io_JintEngine = null;
        private  bool _ib_inited = false;
        private string _is_base_path = "";//基础目录(程序执行主目录, bin目录外)
        private Dictionary<string, object> _io_init = new Dictionary<string, object>();

        public JintProxy()
        {
            //获取当前作用域主目录(不包含\\bin)
            _is_base_path = AppDomain.CurrentDomain.BaseDirectory;
            _is_base_path = new Regex(@"(\\bin(\\)*)$", RegexOptions.IgnoreCase).Replace(_is_base_path, "");
            if (!_is_base_path.EndsWith("\\")) {
                _is_base_path = _is_base_path + "\\";
            }

        }

        //初始化一些属性,比如httpcontext(Http上下文), session(会话对象)的一些属性
        //尽量不要直接传递http, session,一面内存泄露
        public void init(Dictionary<string, object> ao_init) {
           
        }

        /// <summary>
        /// 初始化jint Engine, 避免多次重复加载js资源, 导致运行慢
        /// </summary>
        private void initJintEngine()
        {
            if (!_ib_inited)
            {
                if (io_JintEngine != null)
                {
                    io_JintEngine.Dispose();
                    io_JintEngine = null;
                }

                io_JintEngine = new Engine();

                //可以导入一些自定义.net类或已有的类, 已有类, 注意变量名最好起别名(避免影响到正常使用)
                //io_JintEngine.SetValue("MyClass", TypeReference.CreateTypeReference(io_JintEngine, typeof(MyClass)));


                var sb = new StringBuilder();
                //sb.Append(一些js初始化设定,或者js库也可以这样加载导入);
                
                //MyTestAdd方法
                sb.Append("function MyTestAdd(a, b){return a+b;}")

                //定义一些变量
                //sb.Append("var __is_init_xxx = " + xxxx + ";");
                //也可以这样定义
                //io_JintEngine.SetValue("__is_init_xxx", xxxx);
           
                //js初始化代码载入jint引擎中
                io_JintEngine.Execute(sb.ToString());
            }
        }

        /// <summary>
        /// 执行js函数
        /// </summary>
        /// <param name="jsFunName">js函数名</param>
        /// <param name="jsFunArguments">需传递给js函数的参数</param>
        /// <returns>js函数返回的结果</returns>
        public object RunJs(string jsFunName, params object[] jsFunArguments)
        {
            
            initJintEngine();//每次检查引擎是否初始化, 没有则会自动初始化
            object retObj = null;
            try
            {
                var jsResult = io_JintEngine.Invoke(jsFunName, jsFunArguments);
                //**很重要:如果结果是 JsValue 类型,先转换为 .NET 原生类型(不加这句可能会导致执行.net其它代码异常)
                if (jsResult is JsValue jintValue)
                {
                    retObj = ConvertJsValueToDotNet(jintValue);
                }
                else
                {
                    retObj = jsResult;
                }
            }
            catch (Exception)
            {
                throw;
            }


            return retObj;
        }
        /// <summary>
        /// 释放jint Engine资源
        /// </summary>
        public string disposeJintEngine()
        {
            try
            {
                if (io_JintEngine != null)
                {
                    io_JintEngine.Dispose();
                    io_JintEngine = null;
                    _ib_inited = false;
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            finally
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
            return "";
        }
        private object ConvertJsValueToDotNet(JsValue jsValue)
        {
            if (jsValue == null || jsValue.IsNull())
                return null;

            if (jsValue.IsBoolean())
                return jsValue.AsBoolean();

            if (jsValue.IsNumber())
                return jsValue.AsNumber();

            if (jsValue.IsString())
                return jsValue.AsString();

            if (jsValue.IsArray())
            {
                var list = new List<object>();
                foreach (var item in jsValue.AsArray())
                {
                    list.Add(ConvertJsValueToDotNet(item));
                }
                return list;
            }

            if (jsValue.IsObject())
            {
                var dict = new Dictionary<string, object>();
                foreach (var prop in jsValue.AsObject().GetOwnProperties())
                {
                    dict[prop.Key.ToString()] = ConvertJsValueToDotNet(prop.Value.Value);
                }
                return dict;
            }

            // 其他类型默认返回字符串表示
            return jsValue.ToString();
        }

    }
}

2.MyHelpTool

using System;
using System.IO;


namespace MyHelper
{
    public static class MyHelpTool
    {
        private static JintProxy io_JintProxy = null;
        private static AppDomain io_JintAppDomain = null;

        /// <summary>
        /// 释放jint Engine资源
        /// </summary>
        public static string disposeJintEngine()
        {
            var ls_return = "";

            ls_return = io_JintProxy != null ? io_JintProxy.disposeJintEngine() : "";
            io_JintProxy = null;
            if (io_JintAppDomain != null)
            {
                AppDomain.Unload(io_JintAppDomain);
                io_JintAppDomain = null;
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();
            return ls_return;
        }

        public static object RunJs(string jsFunName, params object[] jsArguments)
        {
            object retObj = null; 
            try
            {
                //创建Jint代理
                if (io_JintAppDomain == null)
                {
                    if (io_JintProxy != null)
                    {
                        io_JintProxy.disposeJintEngine();
                    }
                    //程序集配置,Jint使用的一些程序集版本可能与你当前使用不一样,需要重定向
                    //否则可能找不到程序集
                    //如果还有其它程序集版本找不到,参考MyJint.config其它程序集的设定
                    var setup = new AppDomainSetup
                    {
                        ConfigurationFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MyJint.config"),
                        ApplicationBase = AppDomain.CurrentDomain.BaseDirectory + "bin\\",
                        //代码禁止下载
                        DisallowCodeDownload = true, 
                        DisallowBindingRedirects = false
                    };
                   
                    io_JintAppDomain = AppDomain.CreateDomain("MyJintDomain_" + Guid.NewGuid().ToString(),
                        null,
                        setup
                    );
                    io_JintProxy = (JintProxy)io_JintAppDomain.CreateInstanceAndUnwrap(
                        typeof(JintProxy).Assembly.FullName,
                        typeof(JintProxy).FullName
                    );
                }

                retObj = io_JintProxy.RunJs(jsFunName, jsArguments);
            }
            catch (Exception)
            {
                throw;
            }
            
           
            return retObj;
        }
    
    }



  

}

MyJint.config:在主程序主目录中(bin目录外, 和web.config(asp.net mvc web)同一目录)
 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<runtime>
		<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
			<dependentAssembly>
				<assemblyIdentity name="System.Memory"
								  publicKeyToken="cc7b13ffcd2ddd51"
								  culture="neutral" />
				<!-- 重定向到实际存在的版本(例如4.0.3.0) -->
				<bindingRedirect oldVersion="0.0.0.0-4.0.1.2"
								 newVersion="4.0.3.0" />
			</dependentAssembly>
			<dependentAssembly>
				<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe"
								  publicKeyToken="b03f5f7f11d50a3a"
								  culture="neutral" />
				<bindingRedirect oldVersion="0.0.0.0-6.0.0.0"
								 newVersion="6.0.2.0" />
			</dependentAssembly>
			<dependentAssembly>
				<assemblyIdentity name="System.Buffers"
								  publicKeyToken="cc7b13ffcd2ddd51"
								  culture="neutral" />
				<bindingRedirect oldVersion="0.0.0.0-4.0.3.0"
								 newVersion="4.0.4.0" />
			</dependentAssembly>

			
		</assemblyBinding>
	</runtime>
</configuration>

3.实际应用:
 

  try
  {
       var li_test = MyHelpTool.RunJs('MyTestAdd', 1, 2);
        //li_test会被赋予值3
     
  }
  catch (Exception)
  {
     //这里可以做一些其它事
  }
  finally { 
     MyHelpTool.disposeJintEngine(); //一定要这样执行,不管程序如何异常还是正常,都会释放Jint代理
  }
         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LoveLearnling

您的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值