【问题标题】:Observing standard output with reactive extensions使用响应式扩展观察标准输出
【发布时间】:2012-08-21 00:18:24
【问题描述】:

由于 StandardOutput 不是反应式的,我需要一种方法来观察它。 我知道 Process 类会在写入输出时公开一个用于接收通知的事件 所以我使用这个扩展方法来获取标准输出的 IObservable

public static class ProcessExtensions
{
    public static IObservable<string> StandardOutputObservable(this Process process)
    {
        process.EnableRaisingEvents = true;
        process.StartInfo.RedirectStandardOutput = true;

        var received = Observable.FromEventPattern<DataReceivedEventHandler,DataReceivedEventArgs>(
            handler => handler.Invoke,
            h => process.OutputDataReceived += h,
            h => process.OutputDataReceived -= h)
            .TakeUntil(Observable.FromEventPattern(
                h => process.Exited += h,
                h => process.Exited -= h))
            .Select(e => e.EventArgs.Data);

        process.BeginOutputReadLine();

        return received;

        /* Or if cancellation is important to you...
        return Observable.Create<string>(observer =>
            {
                var cancel = Disposable.Create(process.CancelOutputRead);

                return new CompositeDisposable(
                    cancel, 
                    received.Subscribe(observer));
            });
         */
    }
}

如发现here。 但是当我开始这个过程时

public sealed class ProgramHelper
{
    private readonly Process _program = new Process();
    public IObservable<string> ObservableOutput { get; private set; }

    public ProgramHelper(string programPath, string programArgs)
    {
        _program.StartInfo.FileName = programPath;
        _program.StartInfo.Arguments = programArgs;
    }

    public void StartProgram()
    {
        ConfigService.SaveConfig(
            new Config(
                new Uri(@"http://some.url.com")));

        _program.Start();

        ObservableOutput = _program.StandardOutputObservable();

    }
}

...

[TestFixture]
public class When_program_starts
{
    private ProgramHelper _program;

    [Test]
    public void It_should_not_complain()
    {
       //W
       Action act = () => _program.StartProgram();
       //T
       act.ShouldNotThrow<Exception>();
    }
}

我收到此错误:

“StandardOut 尚未重定向或进程尚未开始。”

感谢您的宝贵时间。

编辑: 将 ProgramHelper 编辑为

    public ProgramHelper(string programPath, string programArgs)
    {
        _program.StartInfo.FileName = programPath;
        _program.StartInfo.Arguments = programArgs;
        _program.EnableRaisingEvents = true;
        _program.StartInfo.UseShellExecute = false;
        _program.StartInfo.RedirectStandardOutput = true;
    }

但现在它抛出“访问被拒绝异常”。

我似乎没有权限以编程方式启动该进程;如果我从控制台启动 exe,它就可以正常工作。

【问题讨论】:

  • 你不应该有 StartInfo.UseShellExecute = false 前重定向吗?

标签: c# .net system.reactive


【解决方案1】:

在进程启动后,您正在改变Process.StartInfo 属性。

来自Process.StartInfo MSDN documentation

您可以更改 StartInfo 属性中指定的参数,直到您在进程中调用 Start 方法。启动进程后,更改 StartInfo 值不会影响或重新启动关联的进程。

【讨论】:

  • 嗨,dugas,谢谢!我编辑了我的代码,以便我的 ProgramHelper 构造函数是这个 public ProgramHelper(string programPath, string programArgs) { _program.StartInfo.FileName = programPath; _program.StartInfo.Arguments = 程序参数; _program.EnableRaisingEvents = true; _program.StartInfo.UseShellExecute = false; _program.StartInfo.RedirectStandardOutput = true; } 但现在它抛出一个 Access is denied 异常
  • 究竟是什么引发了异常?
  • _program.Start() 抛出异常。如果 UseShellExecute 为假且 RedirectStandarOutput 为真,我似乎无权以编程方式运行此代码。如果我从控制台启动 exe,它就可以正常工作。
  • 好的,我解决了这个问题;身份验证问题是由于文件名中的错误导致进程启动。 @dugas 给出的答案实际上解决了我的问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-31
  • 2011-03-25
相关资源
最近更新 更多