我想從我的 C# 專案中運行 .py 檔案,并得到結果。python 腳本正在發出 API 請求,并回傳一個 auth_key 令牌,我想在我的 C# 代碼中使用它。唯一的問題是,由于某種原因,C# 代碼不會等待行程完成,因此并非每個帳戶都有 auth_key。這是我的 C# 代碼。
private static void GenerateTokens()
{
var url = ConfigurationManager.AppSetting[GeSettingsNode() ":ip"];
for (int i = 0; i < accounts.Count; i )
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = ConfigurationManager.AppSetting["PythonPath"];
start.Arguments = string.Format($"python_operation_processor.py {accounts[i].client_key_id} {accounts[i].key_sercret_part} {url}");
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
Process process = Process.Start(start);
using (StreamReader reader = process.StandardOutput)
{
accounts[i].auth_key = reader.ReadToEnd().Trim();
}
}
}
這是我發出 API 請求的 Python 腳本 ( python_operation_processor.py )。
if __name__ == '__main__':
client_key_id = sys.argv[1]
client_secret = sys.argv[2]
API_URL = sys.argv[3]
nonce = str(uuid.uuid4())
d = datetime.datetime.now() - datetime.timedelta(hours=3)
timestamp = d.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] 'Z'
signature = b64encode(hmac.new(b64decode(client_secret), msg=bytes(client_key_id nonce timestamp, 'utf-8'),
digestmod=hashlib.sha256).digest()).decode('utf-8')
r = requests.post(API_URL '/v1/authenticate',
json={'client_key_id': client_key_id, 'timestamp': timestamp, 'nonce': nonce,
'signature': signature})
if r.status_code != 200:
raise Exception('Failed to authenticate: ' r.text)
auth_token = r.json()['token']
print(auth_token)
你有什么想法,我如何等待每個行程的執行,并為每個帳戶獲取令牌?
uj5u.com熱心網友回復:
我最近創建了類似的東西并最終得到了這個,因為雖然等待程序很容易,但要正確填充輸出流卻很棘手。
提供的方法還允許您將輸出顯示到應用程式中的文本塊或類似內容中。
如果像這樣使用它,令牌將被寫入 StringBuilder,并用作回傳值。
private async Task<string> RunCommand(string fileName, string args)
{
var timeoutSignal = new CancellationTokenSource(TimeSpan.FromMinutes(3));
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = fileName;
start.Arguments = string.Format("{0}", args);
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.UseShellExecute = false;
start.CreateNoWindow = true;
var sb = new StringBuilder();
using (Process process = new Process())
{
process.StartInfo = start;
process.OutputDataReceived = (sender, eventArgs) =>
{
sb.AppendLine(eventArgs.Data); //allow other stuff as well
};
process.ErrorDataReceived = OnProcessOnErrorDataReceived;
if (process.Start())
{
process.EnableRaisingEvents = true;
process.BeginOutputReadLine();
process.BeginErrorReadLine();
await process.WaitForExitAsync(timeoutSignal.Token);
//allow std out to be flushed
await Task.Delay(100);
}
}
return sb.ToString();
}
要將其呈現到 UI 應用程式中的文本塊,您需要:
- 實作一個表明新行已被讀取的事件,這意味著轉發該
process.OutputDataReceived事件。 - 如果您考慮實時提要,請確保在 python 中重繪 stdio 緩沖區,將 flush 設定為 true:
print(""hello world"", flush=True)
如果您使用的是較舊的 .net 版本;您可以WaitForExitAsync按照此處所述實作:https://stackoverflow.com/a/17936541/2416958作為擴展方法:
public static class ProcessHelpers
{
public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
{
ManualResetEvent processWaitObject = new ManualResetEvent(false);
processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredProcessWaitHandle = null;
registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
processWaitObject,
delegate(object state, bool timedOut)
{
if (!timedOut)
{
registeredProcessWaitHandle.Unregister(null);
}
processWaitObject.Dispose();
tcs.SetResult(!timedOut);
},
null /* state */,
timeout,
true /* executeOnlyOnce */);
return tcs.Task;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/455080.html
