一般來說,我們需要在開發應用軟件的配置文件中,添加一些參數,用於后續用戶根據實際情況,自行調整。
配置參數,可以放在配置文件中、環境變量中、或數據庫表中(如果使用了數據庫的話)。通常,配置數據,以 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.