2015-03-30 14 views
7

Arkaplan

Şu anda Process.Start() aracılığıyla Node çalıştıran bir C# programında çalışıyorum. Bu alt süreçten stdout ve stderr'i alıyorum ve kendi nedenlerime göre yönlendiriyorum. Bunun yerine, Node.exe'nin yerine Edge.js çağrısı ile değiştirmeyi arıyorum. Bunu yapabilmek için Edge içinde çalışan Javascript'ten gelen stdout ve stderr'leri güvenilir bir şekilde yakalayabilmem ve iletileri C# uygulamasına geri döndürebilmem gerekir. Kenar işlemi sona ererse ben dava kimseye tamlığı için bu yaklaşımı anlatacağım 1 C# ile Edge.js'yi çağırırken, stdout ve stderr'i nasıl takarsınız?

Yaklaşım basitçe bir msgs diziyi bildirmek ve bu başa oldukça kolaydır, onu :)

önerir process.stdout.write ve process.stderr.write öğelerinin üzerine yazarak, bu dizideki iletileri toplayan yeni işlevlerle birlikte, en sonunda, msgs dizisini döndürmeniz yeterlidir. Örnek: Kenar kodu sonlandırması durumunda

var msgs = []; 
process.stdout.write = function (string) { 
    msgs.push({ stream: 'o', message : string }); 
}; 
process.stderr.write = function (string) { 
    msgs.push({ stream: 'e', message: string }); 
}; 

// Return to caller. 
var result = { messages: msgs; ...other stuff... }; 
callback(null, result); 

Açıkçası bu sadece çalışır ve msj kötü durumda büyük ulaşması. Ancak, iyi performans göstermesi muhtemeldir çünkü tüm mesajları geri almak için yalnızca bir sıralı çağrı gereklidir.

Yaklaşım 2

Bunu açıklaması biraz daha zordur. İletileri biriktirmek yerine, C# 'dan gönderdiğimiz bir delege kullanarak stdout ve stderr'i "bağlarız". C#, biz biz Edge içine geçecek bir nesne oluşturmak ve bu nesnenin bir özellik stdoutHook çağırdı:

dynamic payload = new ExpandoObject(); 
payload.stdoutHook = GetStdoutHook(); 

public Func<object, Task<object>> GetStdoutHook() 
{ 
    Func<object, Task<object>> hook = (message) => 
    { 
     TheLogger.LogMessage((message as string).Trim()); 
     return Task.FromResult<object>(null); 
    }; 

    return hook; 
} 

Gerçekten uzak bir Eylem ile alabilir, ancak Kenar Func<object, Task<object>> gerektirdiği görülmektedir, o kazandı aksi halde işlevi proxy. Ardından, JavaScript, biz bu işlevi algılayabilir ve böyle kullanın:

var func = Edge.Func(@" 
    return function(payload, callback) { 
     if (typeof (payload.stdoutHook) === 'function') { 
      process.stdout.write = payload.stdoutHook; 
     } 

     // do lots of stuff while stdout and stderr are hooked... 
     var what = require('whatever'); 
     what.futz(); 

     // terminate. 
     callback(null, result); 
}"); 

dynamic result = func(payload).Result; 

Sorular

S1. Bu tekniklerin her ikisi de işe yarıyor gibi görünüyor, ama bunu yapmanın daha iyi bir yolu var mı, belki de özlediğim Edge'e yerleşik bir şey var mı? Her iki çözüm de istilacıdır - Edge'de yapılması gereken asıl işi sarmak için bir miktar kod gerektirmektedir. Bu dünyanın sonu değil, invaziv olmayan bir yöntem olsaydı daha iyi olurdu.

Q2. Ben bir görev dönmek zorunda yaklaşımda 2'de, burada

return Task.FromResult<object>(null); 

o zaten tamamlandı "boş görevi" dönen olması yanlış gibi geliyor. Ama bunu yazmanın başka bir yolu var mı?

Q3. Stdout ve stderr'ı çırparken Javascript kodunda daha titiz davranmalı mıyım? Bu kod Açıkçası burada neler olduğunu emin değilim, orada çift edge.js içinde dikkat ama process.stdout.write :-) benim ham üzerine yazmaya daha biraz daha karmaşıktır

// Fix #176 for GUI applications on Windows 
try { 
    var stdout = process.stdout; 
} 
catch (e) { 
    // This is a Windows GUI application without stdout and stderr defined. 
    // Define process.stdout and process.stderr so that all output is discarded. 
    (function() { 
     var stream = require('stream'); 
     var NullStream = function (o) { 
      stream.Writable.call(this); 
      this._write = function (c, e, cb) { cb && cb(); }; 
     } 
     require('util').inherits(NullStream, stream.Writable); 
     var nullStream = new NullStream(); 
     process.__defineGetter__('stdout', function() { return nullStream; }); 
     process.__defineGetter__('stderr', function() { return nullStream; }); 
    })(); 
} 

cevap

2

S1: Düğüm, CLD'den Düğüm'ü çağırırken, Node.js kodunun stdout veya stderr dosyasını otomatik olarak yakalayabilen Edge'de yerleşik bir şey yoktur. Bir noktada, CLR/V8 sınırında marshaling akışlarını kolaylaştıracak bir Edge uzantısı yazmayı düşündüm. Kapağın altında, Yaklaşım 2'ye çok benzer olurdu.Kenarın üstünde bağımsız bir modül olarak yapılabilir.

S2: Bu durumda tamamlanmış bir görevin yapılması çok uygundur. Fonksiyonunuz Node.js çıkışını yakaladı, işledi ve aslında bu anlamda "tamamlandı". Null ile tamamlanan bir görevin yapılması, bir Eylem'den dönmenin gerçekten ahlaki bir karşılığıdır.

S3: İşaret ettiğiniz kod yalnızca Konsol uygulamaları değil, Windows GUI uygulamalarıyla ilgilidir. Bir Konsol uygulaması yazıyorsanız, sadece write'u geçersiz kılmak, Edge.js.'a ilettiğiniz Node.js kodu düzeyinde yeterli olmalıdır. Düğümdeki write imzasının isteğe bağlı bir encoding parameter to be passed in olmasına izin verdiğini unutmayın. Hem Yaklaşım 1 hem de 2'de bunu görmezden geliyorsunuz. Özellikle Yaklaşım 2'de JavaScript proxy'sini C# geri çağrısına, process.stdout.write'a atamadan önce parametreleri normalleştiren bir JavaScript işlevine sarmayı öneririm. Aksi takdirde, Edge.js kodu, parametresinin write çağrısına iletildiğini, Edge.js çağrı kuralını izleyen bir geri arama işlevi olduğunu varsayabilir.

+0

Teşekkürler Tomasz, bu yüzden temelde, benim için en iyi bahis kodlama olduğuna dikkati çeken Yaklaşım 2. Bunu yapmanın daha kolay bir yolu olsaydı, belki de bir çift opsiyonel akış veya delegeyi alabilen Edge.Func() 'ın aşırı yüklenmesi daha iyi olurdu. –

İlgili konular