封装DataflowEx

时间:2018-01-04 23:47:28

标签: c# tpl-dataflow

我想使用DataflowEx来封装此测试。我不确定我的设计是否正确,因为我已经尝试了很多我自己做但我没有像我的测试那样完成Dataflow并且不清楚我应该如何从外部发布服务器,IP组合。

    class HttpClientHandlerFactory : Dataflow<string, HttpClientHandler> {
        private readonly TransformBlock<string, WebProxy> _webproxyDataflow;
        private readonly TransformBlock<WebProxy, HttpClientHandler> _httpClientHandlerDataflow;

        public HttpClientHandlerFactory(IHttpClientHandlerFactoryData handlerFactoryData) : this(DataflowOptions.Default, handlerFactoryData) {
        }

        public HttpClientHandlerFactory(DataflowOptions dataflowOptions, IHttpClientHandlerFactoryData handlerFactoryData) : base(dataflowOptions){
            var dataflowBlockOptions = dataflowOptions.ToExecutionBlockOption();
            _webproxyDataflow = new TransformBlock<string, WebProxy>(async s => {
                new WebProxy(s);
            }, dataflowBlockOptions);
            _httpClientHandlerDataflow = new TransformBlock<WebProxy, HttpClientHandler>(proxy => new HttpClientHandler(){Proxy = proxy}, dataflowBlockOptions);
            var dataflowLinkOptions = new DataflowLinkOptions() { PropagateCompletion = true };
            _webproxyDataflow.LinkTo(_httpClientHandlerDataflow, dataflowLinkOptions, proxy => proxy != null);
            var nullTarget = DataflowBlock.NullTarget<WebProxy>();
            _webproxyDataflow.LinkTo(nullTarget, dataflowLinkOptions, proxy => proxy == null);
            RegisterChild(_webproxyDataflow);
            RegisterChild(_httpClientHandlerDataflow);
        }

        public override ITargetBlock<string> InputBlock => _webproxyDataflow;

        public override ISourceBlock<HttpClientHandler> OutputBlock => _httpClientHandlerDataflow;
    }

    class FactoryData: IHttpClientHandlerFactoryData {


    }
    [Fact]
    public async void MethodName(){
        var httpClientHandlers = new BufferBlock<HttpClientHandler>();
        var httpClientHandlerFactory = new HttpClientHandlerFactory(new FactoryData());
        httpClientHandlerFactory.LinkTo(httpClientHandlers.ToDataflow());
        var baseAddresses = new BufferBlock<Uri>();
        var transformBlock = new TransformBlock<Tuple<HttpClientHandler, Uri>,HttpClient>(
                data => {
                    WriteLine($"{data.Item2.ToString()}-{Environment.CurrentManagedThreadId}-{((WebProxy) data.Item1.Proxy).Address}");
                    return new HttpClient(data.Item1){BaseAddress = data.Item2};
                });
        var joinBlock = new JoinBlock<HttpClientHandler,Uri>();
        httpClientHandlers.LinkTo(joinBlock.Target1);
        baseAddresses.LinkTo(joinBlock.Target2);
        joinBlock.LinkTo(transformBlock,new DataflowLinkOptions(){PropagateCompletion = true});

        baseAddresses.Post(new Uri("http://www.serverA.com"));
        baseAddresses.Post(new Uri("http://www.ServerB.com"));
        httpClientHandlerFactory.Post("127.0.0.1");
        httpClientHandlerFactory.Post("127.0.0.2");
        joinBlock.Complete();
        await transformBlock.Completion;

    }

更新

仔细阅读JSteward关于缺少NullTarget块的评论,我意识到我的原始块方法不正确。所以这是正确的版本。

    [Fact]
    public async Task MethodName() {
        var dataflowLinkOptions = new DataflowLinkOptions() { PropagateCompletion = true };
        var httpClientHandlerFactory = new HttpClientHandlerFactory(new HttpClientHandlerFactoryData());
        var baseAddresses = new BufferBlock<Uri>();
        var transformBlock = new TransformBlock<Tuple<HttpClientHandler, Uri>, HttpClient>(
                data => {
                    WriteLine($"{data.Item2.ToString()}-{Environment.CurrentManagedThreadId}-{((WebProxy)data.Item1.Proxy).Address}");
                    var httpClient = new HttpClient(data.Item1) { BaseAddress = data.Item2 };
                    return httpClient;
                });
        var joinBlock = new JoinBlock<HttpClientHandler, Uri>();
        httpClientHandlerFactory.OutputBlock.LinkTo(joinBlock.Target1,dataflowLinkOptions);
        baseAddresses.LinkTo(joinBlock.Target2,dataflowLinkOptions);
        joinBlock.LinkTo(transformBlock, dataflowLinkOptions);


        baseAddresses.Post(new Uri("http://www.serverA.com"));
        baseAddresses.Post(new Uri("http://www.ServerB.com"));
        httpClientHandlerFactory.Post("127.0.0.1");
        httpClientHandlerFactory.Post("127.0.0.2");

        httpClientHandlerFactory.Complete();
        baseAddresses.Complete();
        transformBlock.LinkTo(DataflowBlock.NullTarget<HttpClient>(), dataflowLinkOptions);

        await transformBlock.Completion;

    }

完成此输出。

  

02:51:41.3365 | http://www.servera.com/-11-http://127.0.0.1/     02:51:41.3365 | http://www.serverb.com/-11-http://127.0.0.2/

现在要迁移到DataflowEx,我声明了下一个类

    class HttpClientFactory:Dataflow<string,HttpClient>{
        private readonly HttpClientHandlerFactory _httpClientHandlerFactory;
        private readonly TransformBlock<Tuple<HttpClientHandler, Uri>, HttpClient> _transformBlock;
        private JoinBlock<HttpClientHandler, Uri> _joinBlock;
        private BufferBlock<Uri> _baseAddresses;

        public HttpClientFactory(IHttpClientFactoryData httpClientHandlerFactoryData) : this(DataflowOptions.Default, httpClientHandlerFactoryData) {
        }

        public HttpClientFactory(DataflowOptions dataflowOptions, IHttpClientFactoryData handlerFactoryData) : base(dataflowOptions) {
            var dataflowLinkOptions = new DataflowLinkOptions() { PropagateCompletion = true };
            _httpClientHandlerFactory = new HttpClientHandlerFactory(new HttpClientHandlerFactoryData());

            _baseAddresses = new BufferBlock<Uri>();
            _transformBlock = new TransformBlock<Tuple<HttpClientHandler, Uri>, HttpClient>(
                data => {
                    handlerFactoryData.Logger.WriteLine($"{data.Item2.ToString()}-{Environment.CurrentManagedThreadId}-{((WebProxy)data.Item1.Proxy).Address}");
                    return new HttpClient(data.Item1) { BaseAddress = data.Item2 };
                });
            _joinBlock = new JoinBlock<HttpClientHandler, Uri>();

            _httpClientHandlerFactory.OutputBlock.LinkTo(_joinBlock.Target1,dataflowLinkOptions);
            _baseAddresses.LinkTo(_joinBlock.Target2,dataflowLinkOptions);
            _joinBlock.LinkTo(_transformBlock, dataflowLinkOptions);
            RegisterChild(_transformBlock);
            RegisterChild(_httpClientHandlerFactory);
            RegisterChild(_baseAddresses);
            foreach (var baseAddress in handlerFactoryData.BaseAddresses){
                _baseAddresses.Post(baseAddress);
            }
        }

        public override ITargetBlock<string> InputBlock => _httpClientHandlerFactory.InputBlock;

        public override ISourceBlock<HttpClient> OutputBlock => _transformBlock;
    }

并编写了一个测试,表明它与预期的输出

完成了
    [Fact]
    public async Task MethodName2(){
        var clientFactoryData = new HttpClientFactoryData(new[]{new Uri("http://www.serverA.com")}){Logger = this};
        var httpClientFactory = new HttpClientFactory(DataflowOptions.Verbose,clientFactoryData);
        httpClientFactory.InputBlock.Post("127.0.0.1");
        httpClientFactory.LinkLeftToNull();
        httpClientFactory.Complete();

        await httpClientFactory.OutputBlock.Completion;
    }
  

02:55:44.8536 | [HttpClientFactory1]此时有0个待办事项(在:0,出:0)。     02:55:45.0039 | [HttpClientFactory1] - &gt; [HttpClientHandlerFactory1]已完成     02:55:45.0039 | http://www.servera.com/-11-http://127.0.0.1/

然而,在上面的测试中,我使用了原始的Complete方法,并在OutputBlock上等待,而不是在DataFlow上。使用内置Dataflow方法的下一个测试无法完成。

    [Fact]
    public async Task MethodName2(){
        var clientFactoryData = new HttpClientFactoryData(new[]{new Uri("http://www.serverA.com")}){Logger = this};
        var httpClientFactory = new HttpClientFactory(DataflowOptions.Verbose,clientFactoryData);
        httpClientFactory.InputBlock.Post("127.0.0.1");
        httpClientFactory.LinkLeftToNull();


        await httpClientFactory.SignalAndWaitForCompletionAsync();
    }

1 个答案:

答案 0 :(得分:1)

覆盖Complete方法以完成额外的BufferBlock使测试通过。

audioFileReader