SignalR2 не работает в MVC5 с использованием SqlDependency

Я колеблюсь, публикуя этот вопрос, так как в сети есть несколько ответов на один и тот же вопрос. Но мне не повезло, мне ничего не помогает. Для моего веб-приложения мне нужна часть уведомления, и для этого я подумал об использовании SignalR 2 в том же.

Но это не работает. Ниже приведены полные части кода:

==>Hub Class

[HubName("MyHub")]
public class MyHub : Hub
{
    public static void Show()
    {
        IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
        context.Clients.All.displayStatus();
    }
}

==> Глобальный файл

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        SqlDependency.Start(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    protected void Application_End()
    {
        SqlDependency.Stop(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
    }
}

==>Репозиторий

public class DAL
{
    public List<DTO.Employee> GetEmployee()
    {
        List<DTO.Employee> l = new List<DTO.Employee>();
        try
        {
            using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
            {
                con.Open();
                using (var cmd = new SqlCommand("select * from employee", con))
                {
                    cmd.Notification = null;
                    SqlDependency dep = new SqlDependency(cmd);
                    dep.OnChange += new OnChangeEventHandler(Dep_OnChange);

                    using (var drd = cmd.ExecuteReader())
                    {
                        while (drd.Read())
                        {
                            l.Add(new DTO.Employee()
                            {
                                Id = Convert.ToInt64(drd["id"]),
                                Name = Convert.ToString(drd["name"])
                            });
                        }
                    }
                }
            }
        }
        catch { }
        return l;
    }

    private void Dep_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change)
        {
            MyHub.Show();
        }
    }
}

==> Стартовый класс Овина

[assembly: OwinStartupAttribute(typeof(SignalR2_App1.Startup))]

namespace SignalR2_App1 { public partial class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }

==> Посмотреть

<script src="~/Scripts/jquery-1.10.2.min.js"></script>    
<script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
<script src="~/signalr/hubs"></script>
<script type="text/javascript">
    $(function () {
        var job = $.connection.MyHub;
        job.client.displayStatus = function () {
            getData();
        }
        $.connection.hub.start();
        getData();
    })
    function getData() {
        $.ajax({
            url: "/data/getdata",
            contentType: "application/json charset=utf-8",
            dataType: "json",
            type: "Post",
            success: function (result) {
                $.each(result, function (e, obj) {
                    $("#tbldata_tbody").append("<tr><td>" + obj.Id + "</td><td>" + obj.Name + "</td></tr>")
                })
            },
            error: function () {
                alert("Error");
            }
        })
    }
</script>
<body>
<table id="tbldata">
    <thead>
        <tr>
            <td>Id</td>
            <td>Name</td>
        </tr>
    </thead>
    <tbody id="tbldata_tbody"></tbody>
</table>

==>Action

[HttpPost]
    public JsonResult GetData()
    {
        DAL.DAL O = new DAL.DAL();
        return Json(O.GetEmployee());
    }

Вы можете скачать весь код по ссылке ниже:
Ссылка на код


person Arjun    schedule 01.03.2018    source источник
comment
Я также проверил ссылку. На сервере Sql я выполнил этот запрос: ALTER DATABASE SignalRDemo SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE;   -  person Arjun    schedule 01.03.2018
comment
Также я отлаживаю свой код и обнаружил, что событие Dep_OnChange не запускается при каких-либо изменениях в таблице. Почему?   -  person Arjun    schedule 01.03.2018
comment
Решение: 1. Этот код отлично работал в Chrome, но не в Mozila Firefox. Так что проблем с кодом не было. 2. Позже было замечено, что параметр SqlNotificationEventArgs e в методе Dep_OnChange всегда приносил значение Subscribe. 3. Стало ясно, что со стороны сервера sql чего-то не хватает. 4. Наконец я обнаружил, что пропустил GRANT SUBSCRIBE QUERY NOTIFICATIONS To sa 5. Выполнение предыдущего запроса выдавало ошибку: Cannot find the user 'sa', because it does not exist or you do not have permission. 6. Затем мы изменили его на public вместо sa, и все было в порядке.   -  person Arjun    schedule 05.03.2018
comment
Наконец-то я нашел статью, которая помогла мне ссылка   -  person Arjun    schedule 05.03.2018


Ответы (1)


По вашему коду я думаю, что вы не понимаете всех деталей signalr. Вот несколько советов:

<сильный>1. Внутри вашего концентратора вам не нужен GlobalHost.ConnectionsManager

Внутри хаба у вас уже есть свойство Clients

<сильный>2. Не создавайте экземпляр своего хаба самостоятельно!

Внутри вас DAL вы не должны звонить

  MyHub.Show();

Вместо этого захватите HubContext:

GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients.All.displayStatus();

Лучший подход — используйте Strongly-Types-Hub:

По вашему коду я думаю, что вы не понимаете всех деталей signalr. Я предлагаю вам прочитать https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server

Например, на концентраторе вы должны определить только те методы, которые клиенты могут вызывать на сервере. Для правильного определения методов, которые сервер может вызывать у клиентов, вы можете использовать "Strongly-Types-Hubs". См.: https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server#stronglytypedhubs

Справочная информация о сроке службы объекта Hub:

https://docs.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-server:

Вы не создаете экземпляр класса Hub и не вызываете его методы из собственного кода на сервере; все, что делает для вас конвейер концентраторов SignalR. SignalR создает новый экземпляр класса концентратора каждый раз, когда ему необходимо обработать операцию концентратора, например, когда клиент подключается, отключается или вызывает метод на сервере.

Поскольку экземпляры класса Hub являются временными, их нельзя использовать для сохранения состояния от одного вызова метода к другому. Каждый раз, когда сервер получает вызов метода от клиента, новый экземпляр вашего класса Hub обрабатывает сообщение. Чтобы поддерживать состояние через несколько подключений и вызовов методов, используйте какой-либо другой метод, например базу данных или статическую переменную в классе концентратора, или другой класс, который не является производным от концентратора. Если вы сохраняете данные в памяти, используя такой метод, как статическая переменная в классе Hub, данные будут потеряны при перезапуске домена приложения.

Если вы хотите отправлять сообщения клиентам из собственного кода, который выполняется за пределами класса концентратора, вы не можете сделать это, создав экземпляр класса концентратора, но вы можете сделать это, получив ссылку на объект контекста SignalR для вашего класса концентратора. . Дополнительные сведения см. в разделе Как вызывать клиентские методы и управлять группами из-за пределов класса концентратора далее в этом разделе.

person Stephu    schedule 01.03.2018
comment
Спасибо, что поделились такими замечательными ссылками. Это, безусловно, поможет улучшить или получить полную информацию о SignalR. Кстати, предложенные вами изменения не сработали. Было несколько пар вещей, которые были обнаружены и, наконец, добились успеха. Скоро поделюсь ими в этой теме. - person Arjun; 05.03.2018
comment
@Arjun Понятно, что я написал не полное решение, потому что там много ошибок. Мои ответы только для того, чтобы направить вас на правильный путь. :-). Так что ответ мой неправильный, но я думаю, что он вам очень помог.... - person Stephu; 05.03.2018
comment
Да конечно, даже не только мне, но и всем, кто будет читать этот вопрос. Спасибо дружище. - person Arjun; 05.03.2018