ServiceStack保持长期连接并异步发送响应

时间:2015-08-20 08:53:11

标签: servicestack

我有一个客户端应用程序,通过建立与服务器的长实时HTTP连接来实时监控更改。

在ASP.NET WebAPI中,服务器可以使用PushStreamContent来保持连接很长时间,并在有更新后发送响应。

但在ServiceStack中,似乎没有类似的东西。

我查看了Different ways of returning an ImageStream的示例代码 IStreamWriter.WriteTo方法只调用一次,我不能使用async IO操作来避免阻塞服务器线程。

有没有办法异步向客户端发送渐进式响应?

这是WebAPI中执行作业的示例代码

public static async Task Monitor(Stream stream, HttpContent httpContent, TransportContext transportContext)
{

    ConcurrentQueue<SessionChangeEvent> queue = new ConcurrentQueue<SessionChangeEvent>();
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Action<SessionChangeEvent> callback = (evt) =>
    {
    queue.Enqueue(evt);
    tcs.TrySetResult(null);
    };
    OnSessionChanged += callback;
    try
    {
    using (StreamWriter sw = new StreamWriter(stream, new UTF8Encoding(false)))
    {
        await sw.WriteLineAsync(string.Empty);
        await sw.FlushAsync();
        await stream.FlushAsync();

        for (; ; )
        {

        Task task = tcs.Task;
        await Task.WhenAny(task, Task.Delay(15000));

        if (task.Status == TaskStatus.RanToCompletion)
        {
            tcs = new TaskCompletionSource<object>();

            SessionChangeEvent e;
            while (queue.TryDequeue(out e))
            {
            string json = JsonConvert.SerializeObject(e);
            await sw.WriteLineAsync(json);
            }

            task.Dispose();
        }
        else
        {
            // write an empty line to keep the connection alive
            await sw.WriteLineAsync(string.Empty);
        }
        await sw.FlushAsync();
        await stream.FlushAsync();
        }
    }
    }
    catch (CommunicationException ce)
    {
    }
    finally
    {
    OnSessionChanged -= callback;
    }
}

2 个答案:

答案 0 :(得分:1)

看看example。如果我理解你,这就是你要找的。

答案 1 :(得分:1)

写入长时间运行的连接正是Server Events的作用。您可以查看ServerEventsHandlerServerEventsHeartbeatHandler的实施情况,看看它是否已在ServiceStack中实施。

基本上它只使用自定义的ASP.NET IHttpAsyncHandler,它可以在ServiceStack's Request Pipeline的开头注册:

appHost.RawHttpHandlers.Add(req => req.PathInfo.EndsWith("/my-stream")
    ? new MyStreamHttpHandler()
    : null);

MyStreamHttpHandler是自定义HttpAsyncTaskHandler,例如:

public class MyStreamHttpHandler : HttpAsyncTaskHandler
{
    public override bool RunAsAsync() { return true; }

    public override Task ProcessRequestAsync(
        IRequest req, IResponse res, string operationName)
    {
        //Write any custom request filters and registered headers
        if (HostContext.ApplyCustomHandlerRequestFilters(req, res))
            return EmptyTask;

        res.ApplyGlobalResponseHeaders();



        //Write to response output stream here, either by:
        res.OuputStream.Write(...);

        //or if need access to write to underlying ASP.NET Response
        var aspRes = (HttpResponseBase)res.OriginalResponse;
        aspRes.OutputStream...



        //After you've finished end the request with
        res.EndHttpHandlerRequest(skipHeaders: true);
        return EmptyTask;
    }
}

开头的ApplyCustomHandlerRequestFilters()ApplyGlobalResponseHeaders()为其他插件提供了验证/终止请求或添加任何HTTP标头(例如CorsFeature)的机会。