LoginSignup
2
5

More than 1 year has passed since last update.

C#とNode.jsを連携する その2

Last updated at Posted at 2021-10-20

C#とNode.jsを連携する

コンソールアプリを利用する

EdgeJSはC#のソースを文字列にしそれをコンパイルしています。ソースだろうがファイルだろうがDllだろうがC#を一旦文字列化し、再度ビルドします。
Nugetを読んでたり、外部DLLを参照していたり、Puhblishで書き出したものをすべて読み込んだりすると、Dllが足りなかったり、バージョン違いのedgeJSを上書きしてしまったりで、いろいろうまく動作しないことが多いです。
プログラムが複雑になると開発が難しくなる懸念があります。
そこでC#のコンソールアプリを別個に作り、外部プロセスでコンソールアプリを実行し引数でjsonを投げ、結果をJsonで標準出力しNodeJs側で取得するというのが開発効率がよいと考えました。

サンプルファイル

一式をGitに上げました

Node.jsから実行されるC#

process.env.EDGE_USE_CORECLR = 1;
process.env.EDGE_DEBUG=1;
process.env.EDGE_NATIVE='edge-js/build/Release/edge_coreclr.node';

const edge = require('edge-js');

var add = edge.func({
    source: path.join(__dirname, '../ConsoleApp1/clsTest.cs') ,
    references: ['System.IO', 'System.Diagnostics.Process']
});

add('Node.js', function (error, result) {
    if (error) throw error;
    console.log("result   " + result);
});

Node.jsから実行されたC#からC#コンソールアプリを呼ぶ

コンソールアプリを呼びだするだけのシンプルなものです。引数でJsonを渡す

public class Startup
{
    public async Task<object> Invoke(object input)
    {

        System.Diagnostics.Process p = new System.Diagnostics.Process();
        // 子プロセスの実行ファイル名
        p.StartInfo.FileName = "ConsoleApp1/bin/Debug/net5.0/ConsoleApp1";
        // 子プロセスのオプション(もしあれば)
        p.StartInfo.Arguments = "-n";
        // コンソール・ウィンドウを開かない
        p.StartInfo.CreateNoWindow = true;
        // シェル機能を使用しない
        p.StartInfo.UseShellExecute = false;
        // 標準出力をリダイレクト
        p.StartInfo.RedirectStandardOutput = true;
        // 標準入力をリダイレクト
        p.StartInfo.RedirectStandardInput = true;
        p.Start(); // 子プロセスの実行開始
        // 子プロセスの出力の読み込み
        string output2 = await p.StandardOutput.ReadToEndAsync();            
        p.WaitForExit();
        // p.WaitForExitAsync(); // 子プロセスが終了するのを待つ こっちだとエラーが出た
        p.Dispose(); // 子プロセスの破棄       
        return output2;
    }       
}

C#コンソールアプリ内でいろいろやれる

Nugetを読んだり、外部ライブラリを使ったり、いつもどおりのC#プログラミングをやる

    class Program
    {        
        private static Timer MyTimer;
        static void Main(string[] args)
        {
            RestClient client = new RestClient();
            RestRequest request = new RestRequest();            

            // RestAPIから情報取得のためにアクセスする、e-StatのURLです(json用) 
            client.BaseUrl = new Uri("http://api.e-stat.go.jp/rest/3.0/app/json/getStatsData");

            // HTTPのコマンドを指定します、情報の取得なので GET を指定します
            request.Method = Method.GET;

            // リクエストを送信します
            var response = client.Execute(request);

            //Thread.Sleep(1000);  
            Console.WriteLine("--------111-----------------" + response.Content );
            // Thread.Sleep(1000);
            Console.WriteLine("--------222-----------------" + request.ToString());
            // Thread.Sleep(2000);            
            Console.WriteLine("--------333-----------------");
        }
    }

実行結果

コンソールアプリで実行したものをすべて取得してからnode.jsに返ってきました。標準出力でJsonを表示し取得する
Screenshot from 2021-10-20 17-16-55.png

C#のEdgeJS中身を考察

EdgeJSのC#EdgeCompiler.csを見ることでReadMeに書かれていないやり方で実装方法が発見できます。

EdgeCompiler.csを読むとNodeJsからパラメーターで送るとC#側でSystem.Runtimeなど処理を自動で読み込んでいる処理がわかる。
System.Runtimeなどはコンパイル文のC#側でUsingを書く必要がないです。それ以外のアセンブリはreferencesで設定して読み込みます。

Screenshot from 2021-10-20 14-28-14.png

EdgeJS C#側で読み込めるDllファイルの制限

読み込めるDllファイルは制限があります。バージョンの新しいもの(NetStandard2.0以降?)は読み込めないことが多いようです。
読み込めるDllファイルを確認するにはEdgeCompiler.csのcompileAssembliesの値をデバッグするとわかります。
Screenshot from 2021-10-20 16-57-02.png

感想

C#の再ビルドはいろいろ不具合が予想されるのでシンプルにし、外部コンソールアプリから実行してやるのが一番だと思いました。

追記

node.jsにはが外部プロセスを実行するプログラムがあったのでこれを使ったほうがよい気がしてきました。

C#とNode.jsを連携する 最終章に続く

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5