最近在項目中遇到這樣的需求:要將舊有系統的一部分業務邏輯集成到新的自動化流程工具中。這套正在開發的自動化工具使用的是C#語言,而舊有系統的業務邏輯則是使用AngularJS在前端構建而成。所以最初的考慮中有兩個解決方案,一是將原有JavaScript代碼改寫成C#代碼,以便集成;二是將所需代碼抽離后將它們放置在通過Node.js搭建的RESTful API里,再在C#代碼中以HttpClient調用之。
但是之后發現了Edge.js這一有趣的類庫,於是又多了一項選擇。
Edge.js的作用在於連通Node.js與.NET兩個世界。通過其開發者能夠在Node.js進程中調用.NET代碼或者在.NET進程中調用Node.js代碼。
根據需求,這里是要用到在C#代碼里調用Node.js,即JavaScript代碼。
想要了解如何使用該類庫,可以從官網上的例子入手:
class Program
{
static void Main(string[] args)
{
var func = Edge.Func(@"
return function (data, callback) {
callback(null, 'Node.js welcomes ' + data);
}
");
Console.WriteLine(func(".NET").Result);
Console.Read();
}
}
首先,需要通過Nuget引入它的類庫,Install-Package Edge.js
。
然后,使用EdgeJs中Edge類的Func靜態方法。該方法需要傳入Node.js中使用的代碼,並且必須返回一個JavaScript函數。該函數有一個用於外部傳入數據的參數,以及一個回調函數參數。此回調函數中的第一個參數為JavaScript中的異常信息,第二個是返回值。
Edge.Func方法返回的是Func<object,Task<object>>
委托對象,意味着在.NET可以以異步的方式處理返回內容。
接下來,看一下接近實際工程的例子。
以下的代碼是AngularJS中的常用寫法。現在的計划是要把其中sayHello函數的邏輯放到C#代碼中調用。
app.controller('myCtrl', function($scope) {
$scope.name = "World";
$scope.sayHello = function(data) {
$scope.greeting = 'Hello ' + $scope.name + ' ' + data + '!';
};
});
第一步要解決的是要考慮如何處理$scope。因為其本質上是一個對象,那么就將其定義為一個全局對象變量即可。
第二步是把核心代碼移入Edge的Func方法參數中。
var func = Edge.Func(@"
var $scope = {};
$scope.name = 'World';
$scope.sayHello = function(data) {
$scope.greeting = 'Hello ' + $scope.name + ' ' + data + '!';
};
");
第三步加入返回方法並對JavaScript代碼中可能出現的異常作捕獲處理。
var func = Edge.Func(@"
var $scope = {};
$scope.name = 'World';
$scope.sayHello = function(data) {
$scope.greeting = 'Hello ' + $scope.name + ' ' + data + '!';
};
return function (data, callback) {
var exception = null;
try {
$scope.sayHello(data);
} catch(err) {
exception = err;
}
callback(exception, $scope.greeting);
}
");
運行完整代碼能夠得到預期的結果。
class Program
{
static void Main(string[] args)
{
var func = Edge.Func(@"
var $scope = {};
$scope.name = 'World';
$scope.sayHello = function(data) {
$scope.greeting = 'Hello ' + $scope.name + ' ' + data + '!';
};
return function (data, callback) {
var exception = null;
try {
$scope.sayHello(data);
} catch(err) {
exception = err;
}
callback(exception, $scope.greeting);
}
");
Console.WriteLine(func(".NET").Result);
Console.Read();
}
}
不過上述.NET代碼還未能處理JavaScript中可能發現的異常情況,比如在sayHello函數中加上一句拋出異常語句,代碼在執行時則會發生預期中的錯誤。
$scope.sayHello = function(data) {
$scope.greeting = 'Hello ' + $scope.name + ' ' + data + '!';
throw 'there is an error!';
};
因此更好地做法是在.NET代碼里也加上相應的異常處理。
class Program
{
static void Main(string[] args)
{
try
{
var func = Edge.Func(@"
var $scope = {};
$scope.name = 'World';
$scope.sayHello = function(data) {
$scope.greeting = 'Hello ' + $scope.name + ' ' + data + '!';
throw 'there is an error!';
};
return function (data, callback) {
var exception = null;
try {
$scope.sayHello(data);
} catch(err) {
exception = err;
}
callback(exception, $scope.greeting);
}
");
Console.WriteLine(func(".NET").Result);
}
catch (Exception ex)
{
// 處理異常
}
Console.Read();
}
}
使用這種方法比直接翻譯JavaScript代碼的解決方案要更加節省工時,而且可以避免很多在翻譯語言過程中可能會產生的Bug。而與第二種建立Node.js Restful API的方式相比,又少了額外布署服務的工作。所以綜合考慮下來,是十分適合實際需求的一種方案。
唯一令人遺憾的是,Edge.js目前在.NET代碼調用Node.js代碼方面還不支持.NET Core。希望官網所述的coming soon能夠盡早到來。