使用信号器更新数据库更改时如何刷新视图

How to refresh view when using signal r to update on database change

我正在使用 mvc,我有一个仪表板,我使用了 charthelper 和 bootstrap 管理图表。现在我想更新数据库更改的数据。为此,我正在尝试使用信号 R。

之前

我使用存储库从数据库中获取数据。具有方法的服务文件夹也是如此。

现在。

我不确定具体该怎么做。 但到目前为止我所做的是创建了一个集线器 class, 返回

public static void Send()
   {
       IHubContext context = GlobalHost.ConnectionManager.GetHubContext<DashboardHub>();
       context.Clients.All.updateOnDashboard();
   }

正在观看

<script>
$(function () {
    // Declare a proxy to reference the hub.
    var chat = $.connection.dashboardHub;
    $.connection.hub.logging = true;

    chat.client.foo = function () { };

    //debugger;
    // Create a function that the hub can call to broadcast messages.
    chat.client.updateOnDashboard = function () {
        getAllDashboardUpdates()
    };
    $.connection.hub.start().done(function () {
        getAllDashboardUpdates();

        console.log('Now connected, connection ID=' + $.connection.hub.id);
    })
        .fail(function () { console.log('Could not connect'); });;

    //$.connection.hub.stop();
});

function getAllDashboardUpdates() {
    $.ajax({
        url: '/Dasdhboard/Index',
        contentType: 'application/html ; charset:utf-8',
        type: 'GET',
        dataType: 'html'
    }).success(function (result) {
        //$("#refTable").html(result);
    }).error(function () {
    });
}

控制器方法

public ActionResult Index(int? page)
    {
        IEnumerable<test> newlist = null;

        newlist = GetAlltest();
        var data = dashboardService.GetDashboardData(page, User);
        if (newlist != null)
        {
            return View(data);
        }
        return View(data);
    }

搜索依赖项

public IEnumerable<test> GetAlltest()
   {

       var messages = new List<test>();
       using (var connection = new SqlConnection(_connString))
       {
           connection.Open();
           using (var command = new SqlCommand(@"SELECT [id],[testid] FROM [dbo].[test]", connection))
           {
               command.Notification = null;
               SqlDependency.Start(_connString);
               var dependency = new SqlDependency(command);
               dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

               if (connection.State == ConnectionState.Closed)
                   connection.Open();

               var reader = command.ExecuteReader();

               while (reader.Read())
               {
                   messages.Add(item: new test { id = (int)reader["id"] });
               }
           }

       }
       return messages;
   }

   private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
   {
       if (e.Type == SqlNotificationType.Change)
       {
           DashboardHub.Send();
       }
   }

即使完成后,我的视图也没有刷新。我确定代码是多余的。有人可以告诉我更好的方法吗?或者我哪里出错了。

这只是一种方法。我也有2个图表。

如果我正确理解你的代码,你当前建立了一个 SingalR 连接,并且如果在客户端接收到 updateOnDashboard() 触发 AJAX 调用以从插入的服务器获取完整的 HTML 视图它在 DOM 使用 jQuery.

我会更改它,以便 updateOnDashboard() 也接收您的新值并在客户端呈现这些值,而不是再次调用服务器以获取 HTML 代码。我会更进一步,为这些值创建一个 Javascript 视图模型,并使用 Knockout 将仪表板元素数据绑定到视图模型。然后 updateOnDashboard() 只需将这些值(参数)推送到视图模型中,HTML 通过 Knockout 获取更新。

我在 this post... or V2 post

中写过一些关于这方面的博客

我在您的代码中没有看到检测这些数据更新的代码。您需要在服务器上检测更改并发出那些 updateOnDashboard() 调用。

另请注意,您的集线器方法 Send() 未在任何地方使用。集线器方法仅用于客户端到服务器的调用(传入的服务器调用)。您可能没有这些,所以您不需要集线器方法 - 我猜。

根据您的评论更新:

我使用 SinglaR "live" 将新添加的日志项广播到网络客户端。在服务器端,我有一个 singleton 测试新数据并使用 SignalR 将它们广播到网络客户端。这里的代码:

/// <summary>
/// Singleton that periodically checks the log database for new messages and broadcasts them to all
/// connected web-clients (SignalR).
/// </summary>
public class LiveMessageTicker : ILiveMessageTicker, IRegisteredObject
{
    private readonly TimeSpan updateInterval = TimeSpan.FromMilliseconds(2000);
    private readonly ILogEntriesRepository repository;
    private Guid lastLogEntryId = Guid.Empty;
    private readonly SemaphoreSlim checkSemaphore = new SemaphoreSlim(1, 2);
    private Timer checkTimer;
    private readonly IHubContext hub;

    /// <summary>
    /// Initializes a new instance of the <see cref="LiveMessageTicker"/> class.
    /// </summary>
    /// <param name="repository">The database repository to use.</param>
    /// <exception cref="System.ArgumentNullException"></exception>
    public LiveMessageTicker(ILogEntriesRepository repository)
    {
        if (repository == null) { throw new ArgumentNullException(nameof(repository)); }

        this.repository = repository;

        // Register this instance to in ASP to free it up on shutdown
        HostingEnvironment.RegisterObject(this);

        // Get the server-side SignalR hub
        hub = GlobalHost.ConnectionManager.GetHubContext<ServerMonitoringHub>(); 

        // Configure a Timer that calls CheckForNewMessages all 2 sec's
        checkTimer = new Timer(CheckForNewMessages, null, TimeSpan.Zero, updateInterval);
    }

    /// <summary>
    /// Stops this instance.
    /// </summary>
    /// <param name="immediate">if set to <c>true</c> immediatelly.</param>
    /// <seealso cref="IRegisteredObject"/>
    public void Stop(bool immediate)
    {
        checkTimer.Dispose();
        checkTimer = null;

        HostingEnvironment.UnregisterObject(this);
    }

    private void CheckForNewMessages(object state)
    {
        if (checkSemaphore.Wait(500))
        {
            try
            {
                // Get new log entries
                var newLogEntries = repository.GetNewLogEntries(lastLogEntryId).ToList();

                // If there arent any new log entries
                if (!newLogEntries.Any())
                {
                    return;
                }

                lastLogEntryId = newLogEntries.Last().Id;

                // Convert DB entities into DTO's for specific client needs
                var logEntries = newLogEntries.Select(l => new
                {
                    id = l.Id,
                    correlationId = l.CorelationIdentifier,
                    messageId = l.MessageId,
                    time = l.Time.ToLocalTime(),
                    level = (int)l.Level,
                    messageText = l.Message,
                    additionalData = l.AdditionalData.Select(a => new { name = a.Name, value = a.Value }).ToArray(),
                    tags = l.Tags.Select(t => t.Name).ToArray(),
                    channel = l.Channel.Name,
                    username = l.Username,
                    workstation = l.WorkstationName
                }).ToList();

                // Broadcast all new log entries over SignalR
                hub.Clients.All.addLogMessages(logEntries);
            }
            finally
            {
                checkSemaphore.Release();
            }
        }
    }
}

这一切都从 Global.asax.cs 开始,在那里我创建了一个上述 class 的实例(它通过 ASP.Net 注册自己,以便稍后使用 HostingEnvironment.RegisterObject(this) 正确停止).

请注意,我不会将呈现的 HTML-代码或视图推送给客户端。我将数据推送为 JSON。服务器不渲染它,但客户端渲染它。为了在客户端上呈现它,我使用 Javascript/Typescript view-model that collects the incomming messages in a Knockout ObservableArray. This observablearray is bound to in HTML using the Knockout foreach (see here)。因此,对于数据更新,我不使用 Razor 和 ASP.Net 来生成 HTML。这是最初发送的视图的全部内容,其中包含数据绑定并引用了我的 Javascript/Typescript。它与上面喜欢的博客中记录的非常相似-post.