从后台线程发送SignalR客户端消息

时间:2015-06-14 13:53:53

标签: c# multithreading asp.net-mvc-5 signalr hangfire

我正在尝试跟踪文章http://docs.hangfire.io/en/latest/background-processing/tracking-progress.html

指导的Hangfire后台工作进度

不幸的是,文章中给出的例子不起作用。我在本地下载并运行了示例Web应用程序(https://github.com/HangfireIO/Hangfire.Highlighter)。在作业完成后客户订阅时没关系。在这种情况下,消息直接从集线器发送,并已由客户端接收。否则从Hangfire作业调用消息调用,然后没有任何反应。没有例外,没有结果。什么可能导致这种行为?以防万一:hangfire工作不能异步工作......

示例中的代码:

Hangfire Job(请参阅突出显示方法)

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using HangFire.Highlighter.Hubs;
using HangFire.Highlighter.Models;
using Microsoft.AspNet.SignalR;

namespace HangFire.Highlighter.Jobs
{
    public class SnippetHighlighter : IDisposable
    {
        private readonly IHubContext _hubContext;
        private readonly HighlighterDbContext _dbContext;

        public SnippetHighlighter()
            : this(GlobalHost.ConnectionManager.GetHubContext<SnippetHub>(), new HighlighterDbContext())
        {
        }

        internal SnippetHighlighter(IHubContext hubContext, HighlighterDbContext dbContext)
        {
            if (hubContext == null) throw new ArgumentNullException("hubContext");
            if (dbContext == null) throw new ArgumentNullException("dbContext");

            _hubContext = hubContext;
            _dbContext = dbContext;
        }

        public void Highlight(int snippetId)
        {
            var snippet = _dbContext.CodeSnippets.Find(snippetId);
            if (snippet == null) return;

            snippet.HighlightedCode = HighlightSource(snippet.SourceCode);
            snippet.HighlightedAt = DateTime.UtcNow;

            _dbContext.SaveChanges();

            _hubContext.Clients.Group(SnippetHub.GetGroup(snippet.Id))
                .highlight(snippet.HighlightedCode);
        }

        public void Dispose()
        {
            _dbContext.Dispose();
        }

        private static async Task<string> HighlightSourceAsync(string source)
        {
            using (var client = new HttpClient())
            {
                var response = await client.PostAsync(
                    @"http://hilite.me/api",
                    new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "lexer", "c#" },
                    { "style", "vs" },
                    { "code", source }
                }));

                response.EnsureSuccessStatusCode();

                return await response.Content.ReadAsStringAsync();
            }
        }

        private static string HighlightSource(string source)
        {
            // Microsoft.Net.Http does not provide synchronous API,
            // so we are using wrapper to perform a sync call.
            return RunSync(() => HighlightSourceAsync(source));
        }

        private static TResult RunSync<TResult>(Func<Task<TResult>> func)
        {
            return Task.Run<Task<TResult>>(func).Unwrap().GetAwaiter().GetResult();
        }
    }
}

集线器

using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using HangFire.Highlighter.Models;
using Microsoft.AspNet.SignalR;

namespace HangFire.Highlighter.Hubs
{
    public class SnippetHub : Hub
    {
        public async Task Subscribe(int snippetId)
        {
            await Groups.Add(Context.ConnectionId, GetGroup(snippetId));

            // When a user subscribes a snippet that was already 
            // highlighted, we need to send it immediately, because
            // otherwise she will listen for it infinitely.
            using (var db = new HighlighterDbContext())
            {
                var snippet = await db.CodeSnippets
                    .Where(x => x.Id == snippetId && x.HighlightedCode != null)
                    .SingleOrDefaultAsync();

                if (snippet != null)
                {
                    Clients.Client(Context.ConnectionId)
                        .highlight(snippet.Id, snippet.HighlightedCode);
                }
            }
        }

        public static string GetGroup(int snippetId)
        {
            return "snippet:" + snippetId;
        }
    }
}

使用OWIN Startup类配置SingnalR。

0 个答案:

没有答案