C# 反应式扩展清理
如果您使用rx进行长链呼叫,例如:C# 反应式扩展清理,c#,linq,httpwebrequest,system.reactive,C#,Linq,Httpwebrequest,System.reactive,如果您使用rx进行长链呼叫,例如: var responses = collectionOfHttpRequests.ToObservable() .FromAsyncPattern(req.BeginGetResponse, req.EndGetResponse) .Select(res => res.GetResponseBodyString()) // Extension method to get the body of the request .Subscribe(); 然后在
var responses = collectionOfHttpRequests.ToObservable()
.FromAsyncPattern(req.BeginGetResponse, req.EndGetResponse)
.Select(res => res.GetResponseBodyString()) // Extension method to get the body of the request
.Subscribe();
然后在操作完成之前调用dispose,http请求是否会被取消、关闭并正确地处理,或者我是否必须从方法链中选择httprequests并单独处理它们
我有一个功能,一个可以同时发生多个http请求,我需要能够取消(而不是忽略)其中的一些/全部以节省网络流量。当序列完成、错误或订阅被处理时,Rx运营商链将自行清理。但是,每个操作员只清理他们希望清理的内容。例如,
FromEvent
将取消订阅该事件
在您的情况下,不支持取消,因此Rx不支持取消。但是,您可以使用Finally
调用
我不能承认Richard Szalay的解决方案是可以接受的。如果启动100个请求,第二个请求失败,出现服务器不可用错误(例如),其余98个请求将被中止。第二个问题是UI将如何对这种可观察的行为做出反应?太悲伤了 记住第4.3章,我希望通过observable.Using()操作符来表示WebRequest observable。但是WebRequest不是一次性的!所以我定义了DisposableWebRequest:
public class DisposableWebRequest : WebRequest, IDisposable
{
private static int _Counter = 0;
private readonly WebRequest _request;
private readonly int _index;
private volatile bool _disposed = false;
public DisposableWebRequest (string url)
{
this._request = WebRequest.Create(url);
this._index = ++DisposableWebRequest._Counter;
}
public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state)
{
return this._request.BeginGetResponse(callback, state);
}
public override WebResponse EndGetResponse(IAsyncResult asyncResult)
{
Trace.WriteLine(string.Format("EndGetResponse index {0} in thread {1}", this._index, Thread.CurrentThread.ManagedThreadId));
Trace.Flush();
if (!this._disposed)
{
return this._request.EndGetResponse(asyncResult);
}
else
{
return null;
}
}
public override WebResponse GetResponse()
{
return this._request.GetResponse();
}
public override void Abort()
{
this._request.Abort();
}
public void Dispose()
{
if(!this._disposed)
{
this._disposed = true;
Trace.WriteLine(string.Format("Disposed index {0} in thread {1}", this._index, Thread.CurrentThread.ManagedThreadId ));
Trace.Flush();
this.Abort();
}
}
}
然后我创建WPF窗口并在其上放置两个按钮(开始和停止)
因此,让我们创建适当的请求可观察集合。
首先,定义URL的可观察创建函数:
Func<IObservable<string>> createUrlObservable = () =>
Observable
.Return("http://yahoo.com")
.Repeat(100)
.OnStartup(() =>
{
this._failed = 0;
this._successed = 0;
});
您可能会对函数“HandleError()”感到疑惑。如果在EndGetResponse()调用中发生异常(我关闭了网络连接以复制异常),并且在request observable中未捕获到异常-它将使startMouseDown observable崩溃。HandleError以静默方式捕获异常,执行提供的操作,而不是为下一个观察者调用OnCompleted的OnError:
public static class ObservableExtensions
{
public static IObservable<TSource> HandleError<TSource>(this IObservable<TSource> source, Action<Exception> errorHandler)
{
return Observable.CreateWithDisposable<TSource>(observer =>
{
return source.Subscribe(observer.OnNext,
e =>
{
errorHandler(e);
//observer.OnError(e);
observer.OnCompleted();
},
observer.OnCompleted);
});
}
}
您的代码似乎不正确:在
IObservable
上没有可调用的扩展方法fromsyncPattern
。这种方法只是静态的。不是扩展。如果您花时间编写真正的代码,那么问题和解决方案都会变得显而易见。@Fryodor-虽然您对AsyncPattern中的是绝对正确的,但我不认为使用正确的方法签名可以让OP深入了解如何取消异步请求。
Func<string, IObservable<WebResponse>> createRequestObservable =
url =>
Observable.Using(
() => new DisposableWebRequest("http://yahoo.com"),
r =>
{
Trace.WriteLine("Queued " + url);
Trace.Flush();
return Observable
.FromAsyncPattern<WebResponse>(r.BeginGetResponse, r.EndGetResponse)();
});
var startMouseDown = Observable.FromEvent<RoutedEventArgs>(this.StartButton, "Click");
var stopMouseDown = Observable.FromEvent<RoutedEventArgs>(this.StopButton, "Click");
startMouseDown
.SelectMany(down =>
createUrlObservable()
.SelectMany(url => createRequestObservable(url)
.TakeUntil(stopMouseDown)
.Select(r => r.GetResponseStream())
.Do(s =>
{
using (var sr = new StreamReader(s))
{
Trace.WriteLine(sr.ReadLine());
Trace.Flush();
}
})
.Do(r => this._successed++)
.HandleError(e => this._failed++))
.ObserveOnDispatcher()
.Do(_ => this.RefresLabels(),
e => { },
() => this.RefresLabels())
)
.Subscribe();
public static class ObservableExtensions
{
public static IObservable<TSource> HandleError<TSource>(this IObservable<TSource> source, Action<Exception> errorHandler)
{
return Observable.CreateWithDisposable<TSource>(observer =>
{
return source.Subscribe(observer.OnNext,
e =>
{
errorHandler(e);
//observer.OnError(e);
observer.OnCompleted();
},
observer.OnCompleted);
});
}
}
private void RefresLabels()
{
this.SuccessedLabel.Content = string.Format("Successed {0}", this._successed);
this.FailedLabel.Content = string.Format("Failed {0}", this._failed);
}