一般來說,我們需要在開發應用軟體的配置檔案中,新增一些引數,用於後續使用者根據實際情況,自行調整。
配置引數,可以放在配置檔案中、環境變數中、或資料庫表中(如果使用了資料庫的話)。通常,配置資料,以 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.