zoukankan      html  css  js  c++  java
  • C# 代码中调用 Javascript 代码段以提高应用程序的配置灵活性(使用 Javascript .NET 与 Jint)

    一般来说,我们需要在开发应用软件的配置文件中,添加一些参数,用于后续用户根据实际情况,自行调整。

    配置参数,可以放在配置文件中、环境变量中、或数据库表中(如果使用了数据库的话)。通常,配置数据,以 key/value 的形式。

    有时候,这种  key/value 的形式,不足以满足用户需求。比如,系统中有个定时删除临时文件的 job ,我们希望在客户工厂的生产交接班期间及员工吃饭时间,比如客户工厂生产交接班时间为 5:30 - 6:00 , 23:00-23:30, 中途吃饭时间为 11:00, 4:00。

    也许,可以用正则表达式,来实现以上的功能。但实际情况一调查,我们发现,客户用户懂正则表达式的基本没有,我们自己公司软件开发人员懂正则表达式的也很少。如果做成正则表达式方式,后续代码交接之后,能不能维护/修改,也很难说。

    这样,我们找到了"以 Javascript 的代码段,进行判断,作为配置参数值",这样可以完美地解决我们的问题。Javascript 基本语法简单,客户用户也可自行更改。

    对于可在 C# 代码中使用的 Javascript 引擎,我们找到了两个:  Javascript .NET 与 Jint。前者依赖于 Goolge V8 引擎,运行时需要 Microsoft C Runtime Libraries, 后者则是纯 C# 代码组件。

    为同时测试这两种,我们先进行代码抽象: 

    Javascript 代码,可能无 package/namespace ,可能无 function ,只是一段代码。但无论如何,调用前赋值、调用程序、调用后获取需要的数值,这个基本逻辑,是不会变的。

    a. 基础类定义如下:

     1 using System.Collections.Generic;
     2 
     3 namespace xxxx
     4 {
     5     public interface IJavascriptEngine
     6     {
     7         /// <summary>
     8         /// 执行一段 Javascript 代码,传入一些参数,得到一些数值
     9         /// </summary>
    10         /// <param name="strJavascriptCode"></param>
    11         /// <param name="inputParameters"></param>
    12         /// <param name="outputNameValues">传入时,只填key, 保留 value为空;返回时,填写value</param>
    13         void Execute(string strJavascriptCode, Dictionary<string, object> inputParameters, Dictionary<string, object> outputNameValues);
    14     }
    15 }

    b. Javascript .NET 实现以上接口的代码如下:

     1 using System.Collections.Generic;
     2 
     3 namespace dispatch_service.srv
     4 {
     5     public class JsNetJavascriptEngineSrv : IJavascriptEngine
     6     {
     7         public virtual void Execute(string strJavascriptCode, Dictionary<string, object> inputParameters, Dictionary<string, object> outputNameValues)
     8         {
     9             using (Noesis.Javascript.JavascriptContext context = new Noesis.Javascript.JavascriptContext())
    10             {
    11                 //step 1, 初始化各个变量值
    12                 foreach (KeyValuePair<string, object> pair in inputParameters)
    13                 {
    14                     context.SetParameter(pair.Key, pair.Value);
    15                 }
    16 
    17                 //step 2, 执行 Javascript 代码,可能是多个函数,或无函数的代码段
    18                 context.Run(strJavascriptCode);
    19 
    20                 //step 3, 读取所需的变量值,暂存到 nonNullKeyValues 变量中。
    21                 Dictionary<string, object> nonNullKeyValues = new Dictionary<string, object>();
    22                 foreach (KeyValuePair<string, object> pair in outputNameValues)
    23                 {
    24                     object value = context.GetParameter(pair.Key);
    25                     if (value != null)
    26                     {
    27                         nonNullKeyValues[pair.Key] = value;
    28                     }
    29                 }
    30 
    31                 //step 4,将暂存的变量值,通过 outputNameValues 返回。
    32                 foreach (KeyValuePair<string, object> pair in nonNullKeyValues)
    33                 {
    34                     outputNameValues[pair.Key] = pair.Value;
    35                 }
    36             }
    37         }
    38     }
    39     
    40 }

    c. Jint 实现此接口的代码如下:

     1 using System.Collections.Generic;
     2 using Jint;
     3 
     4 namespace xxxx
     5 {
     6     public class JintJavascriptEngineSrv : IJavascriptEngine
     7     {
     8         public virtual void Execute(string strJavascriptCode, Dictionary<string, object> inputParameters, Dictionary<string, object> outputNameValues)
     9         {
    10             Engine en = new Engine();
    11            
    12             //step 1, 初始化各个变量值
    13             foreach (KeyValuePair<string, object> pair in inputParameters)
    14             {
    15                 en.SetValue(pair.Key, pair.Value);
    16             }
    17                
    18             //step 2, 执行 Javascript 代码,可能是多个函数,或无函数的代码段
    19             en.Execute(strJavascriptCode);
    20 
    21             //step 3, 读取所需的变量值,暂存到 nonNullKeyValues 变量中。
    22             Dictionary<string, object> nonNullKeyValues = new Dictionary<string, object>();
    23             foreach (KeyValuePair<string, object> pair in outputNameValues)
    24             {
    25                 Jint.Native.JsValue value = en.GetValue(pair.Key);
    26                 if (value != null)
    27                 {
    28                     nonNullKeyValues[pair.Key] = value.ToObject();
    29                 }
    30             }
    31 
    32             //step 4,将暂存的变量值,通过 outputNameValues 返回。
    33             foreach (KeyValuePair<string, object> pair in nonNullKeyValues)
    34             {
    35                 outputNameValues[pair.Key] = pair.Value;
    36             }
    37 
    38         }
    39     }
    40 }

    d. 最后,调用代码里,可以自由切换以上两种 Javascript 引擎:

     1                 Dictionary<string, object> inputParameters = new Dictionary<string, object>();
     2                 //给 inputParameters 填充数值,此处无需填充。
     3 
     4                 Dictionary<string, object> outputNameValues = new Dictionary<string, object>();
     5                 //给 outputNameValues 填充 key 值,此处需得到 canRunNow 变量数值。
     6                 outputNameValues["canRunNow"] = null;
     7 
     8                 //IJavascriptEngine eng = new JsNetJavascriptEngineSrv();
     9                 IJavascriptEngine eng = new JintJavascriptEngineSrv();
    10 
    11                 eng.Execute(jsStr, inputParameters, outputNameValues);
    12                 object objValue = outputNameValues["canRunNow"];
    13                 System.Nullable<bool> bValue =(System.Nullable<bool>) objValue;
    14                 if (bValue != null && bValue.Value)
    15                 {
    16                     needRunNow = true;
    17                 }

    e. 附上 Javascript 代码段:

    var nowTime=new Date(); var canRunNow = false; var nowHour = nowTime.getHours();  var nowMin = nowTime.getMinutes();  if ( nowHour == 22 && nowMin == 0 ) {canRunNow = true;}

    或:

    var nowTime=new Date(); var canRunNow = false; var nowMin = nowTime.getMinutes(); var nowSec = nowTime.getSeconds(); if ( nowSec % 3 == 0 ) {canRunNow = true;}

    这样配置就很灵活了。

    当然,这里的 Javascript 代码段 , 作为配置参数 (key/value 中的 value),我们把它的多个代码写成一行。其实,不写成一行,也是可行的。

    -----------------------------------------------------------------------------------------------------------------------

    转发请注明出处。当心我晚上变大灰狼来摸你肚子哟。我是 jacklondon , at , cnblogs.com. 

    开源项目 velocityweb 维护人。上海折桂软件有限公司负责人。当前在开发及推广折桂打印平台系统、折桂上传平台系统。 http://zheguisoft.com ; http://www.cnblogs.com/jacklondon ;
  • 相关阅读:
    C#解决界面不响应
    C#调用SendMessage 用法
    C#开机自动启动程序代码
    C# WinForm使用乐器数字接口
    以下C#程序的输出结果是( )。
    C# 关键字extern用法
    C#循环测试题
    C#播放wav文件
    Matches正则使用提取内容
    C#测试题若干,都是基础阿
  • 原文地址:https://www.cnblogs.com/jacklondon/p/call_javascript_in_csharp_code_using_javascript_dot_net_and_jint.html
Copyright © 2011-2022 走看看