我正在尝试为System.Net.WebSocket编写一个扩展方法,它将使用Reactive Extensions(Rx.NET)将其转换为IObserver。您可以看到以下代码:
public static IObserver<T> ToObserver<T>(this WebSocket webSocket, IWebSocketMessageSerializer<T> webSocketMessageSerializer)
{
// Wrap the web socket in an interface that's a little easier to manage
var webSocketMessageStream = new WebSocketMessageStream(webSocket);
// Create the output stream to the client
return Observer.Create<T>(
onNext: async message => await webSocketMessageStream.WriteMessageAsync(webSocketMessageSerializer.SerializeMessage(message)),
onError: async error => await webSocketMessageStream.CloseAsync(WebSocketCloseStatus.InternalServerError, string.Format("{0}: {1}", error.GetType(), error.Message)),
onCompleted: async () => await webSocketMessageStream.CloseAsync(WebSocketCloseStatus.NormalClosure, "Server disconnected")
);
}
此代码有效,但我担心在onNext,onError和onCompleted lambdas中使用async / await。我知道这会返回一个 async void lambda,这是不赞成的(有时会导致我已经遇到的问题)。
我一直在阅读Rx.NET文档以及互联网上的博客文章,我似乎无法找到在IObserver中使用async / await方法的正确方法(如果有的话)。有没有正确的方法来做到这一点?如果没有,那么我该如何解决这个问题?
答案 0 :(得分:15)
订阅不采用if(rangeStart>rangeEnd){i--;}
方法。那么这里发生的是你正在使用<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script>
function conversion(n) {
if (document.getElementById('mtokm').checked) {
return (n/0.62137).toFixed(2);
}
else {
return (n*0.62137).toFixed(2);
}
}
function conversionTable(rangeStart, rangeEnd) {
if(atLeastOneRadio() && rangeStart != false && rangeEnd != false) {
divStr="<table border=1><tr><td>Miles</td><td>Kilometres</td></tr>";}
for(i=rangeStart;i<=rangeEnd;i++) {
if(i%2==0)
{
divStr+= "<tr bgcolor=\"yellow\"><td>" + i + "</td><td>" + conversion(i) + "</td></tr>";
}
else
{
divStr+= "<tr bgcolor=\"green\"><td>" + i + "</td><td>" + conversion(i) + "</td></tr>";
}
}
document.getElementById("divResult").innerHTML=divStr;
}
else
{
alert("Please make sure you have entered an integer in both text boxes");
}
}
function getnputValue(input) {
var nn = $("input[name=convert]:checked").val()
var myInt = document.getElementById(input).value;
if(myInt == parseInt(myInt))
return parseInt(myInt);
else
return false;
}
function check() {
var radios = document.getElementsByName("choice");
$("input[name=convert]:checked").val()
for (var i = 0, len = radios.length; i < len; i++) {
if (radios[i].checked) {
return true;
}
}
return false;
}
function atLeastOneRadio() {
return ($('input[type=radio]:checked').length > 0);
}
</script>
</head>
<body>
<p>
Start : <input type=textbox id=rangeTxt value=""/>
End : <input type=textbox id=rangeTxt2 value=""/>
<input type=radio name="convert" id="mtokm" value ="Miles to Kilometre"/> Miles to Kilometre
<input type=radio name="convert" id="kmtom" value ="Kilometre to Miles"/> Kilometre to Miles
<br>
<br>
<button onClick="conversionTable(getnputValue('rangeTxt'), getnputValue('rangeTxt2'))">Convert</button>
</p>
<div id="divResult">
</div>
</body>
</html>
中的“即发即忘”机制。问题是onNext消息将不再被序列化。
不应在Subscribe中调用async
方法,而应将其包装到管道中以允许Rx等待它。
在async void
和async
上使用“即发即弃”是可以的,因为这些是onError
调用的最后一件事。请注意,在onCompleted
和Observable
返回之后,可以在完成之前清除与Observable
相关联的资源。
我写了一个小扩展方法来完成所有这些:
onError
首先,我们将onCompleted
方法转换为 public static IDisposable SubscribeAsync<T>(this IObservable<T> source, Func<T, Task> onNext, Action<Exception> onError, Action onCompleted)
{
return source.Select(e => Observable.Defer(() => onNext(e).ToObservable())).Concat()
.Subscribe(
e => { }, // empty
onError,
onCompleted);
}
,桥接两个异步世界。这意味着async onNext
内的异步/等待将得到尊重。接下来,我们将方法包装到Observable
中,以便在创建时不会正确启动。相反,onNext
只有在前一个完成时才会调用下一个deferred observable。
聚苯乙烯。我希望下一版本的Rx.Net在订阅中支持Defer
。