C# 程式碼中呼叫 Javascript 程式碼段以提高應用程式的配置靈活性(使用 Javascript .NET 與 Jint)

Jacklondon Chen發表於2018-07-30

一般來說,我們需要在開發應用軟體的配置檔案中,新增一些引數,用於後續使用者根據實際情況,自行調整。

配置引數,可以放在配置檔案中、環境變數中、或資料庫表中(如果使用了資料庫的話)。通常,配置資料,以 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 ;

相關文章