我有2个.NET解决方案。一个是asp.net mvc web应用程序,它是信号服务器。另一个是SignalR WPF客户端,它使用来自Web信号服务器的自定义类对象的集合。我使用IIS运行信号器MVC Web服务器。信号器WPF客户端应用程序在另一个VS实例中运行。
SignalR Web服务器有一个Hub方法(名为“MessageLogHub”,请参见下面的代码),如果有更改(例如手动将数据插入SQL,则使用SqlDependency)向所有信号器客户端广播自定义类对象的集合目标数据库表中的服务器数据库表)。自定义类对象的集合是SQL Server数据库服务器的所有记录。
从信号器WPF客户端应用程序端,我让客户端注册SignalR服务器方法如下:
Proxy.On<List<MessageLog>>("BroadcastMessage", OnBroadcastMessage);
名为“OnBroadcastMessage”的回调方法如下:
private void OnBroadcastMessage(List<MessageLog> logs)
{
// problem: this callback method is hits once there is a put from signalr server. but the "logs" parameter's value is never changed !!!
Dispatcher.Invoke(() =>
{
textblockTime.Text = DateTime.Now.ToLongTimeString() + " - logs.Count=" + logs.Count();
datagridLogs.ItemsSource = null;
datagridLogs.ItemsSource = logs;
});
}
因此,当数据库发生变化时,SignalR Web服务器将在所有连接的客户端上调用方法“ BroadcastMessage ”(请参阅下面的Signalr Hub服务器代码)和回调方法(在SignalR WPF客户端代码)“OnBroadcastMessage”将在客户端(WPF或Web应用程序客户端)上自动触发。 在VS中,我调试了名为“ OnBroadcastMessage ”的回调方法,当数据库发生变化触发SignalR服务器代码广播时,我看到它被点击所有连接的客户。
问题是 在“OnBroadcastMessage”的信号器Wpf客户端回调方法中(请参阅上面的“OnBroadcastMessage”回调方法代码),在该回调方法中命中调试断点时,“日志”参数的值不会更改。如果在数据库表中插入了一行,则应该更改“ logs ”参数的返回值,并将 new “logs”参数放入信号器客户端。请帮帮我。
我有一个信号器客户端的另一个信号器asp.net MVC web项目,它嵌入在SignalR MVC Web服务器解决方案中。它与信号服务器一起工作正常,我用signalR web客户端实时看到了这些变化。但是信号器WPF客户端应用程序无法正常工作。
以下是signalr WPF客户端应用程序的代码(文件后面的xaml代码):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using MessageWatchWpfClient.Models;
using Microsoft.AspNet.SignalR.Client;
namespace MessageWatchWpfClient
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string hostUrl = "http://localhost/MessageWatch/signalr";
public IHubProxy Proxy { get; set; }
public HubConnection Connection { get; set; }
public MainWindow()
{
InitializeComponent();
}
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
Connection = new HubConnection(hostUrl);
Proxy = Connection.CreateHubProxy("MessageLogHub");
// 1) Register so that Server automatically calls Client when database is changed
Proxy.On<List<MessageLog>>("BroadcastMessage", OnBroadcastMessage);
await Connection.Start();
// 2) Client calls Server on the Wpf application loading and the following is run one time only
await Proxy.Invoke<List<MessageLog>>("GetAllMessagesLog")
.ContinueWith((t) =>
{
Dispatcher.Invoke(() =>
{
textblockTime.Text = DateTime.Now.ToLongTimeString() + " - logs.Count=" + t.Result.Count();
datagridLogs.ItemsSource = t.Result;
});
}
);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void OnBroadcastMessage(List<MessageLog> logs)
{
// problem: this callback method is hits once there is a put from signalr server. but the "logs" parameter's value is never changed !!!
Dispatcher.Invoke(() =>
{
textblockTime.Text = DateTime.Now.ToLongTimeString() + " - logs.Count=" + logs.Count();
datagridLogs.ItemsSource = null;
datagridLogs.ItemsSource = logs;
});
}
}
}
以下代码适用于服务器端应用程序上的SignalR Hub类,该应用程序是Asp.net MVC Web并托管在IIS上:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using MessageWatch.Models;
using Microsoft.AspNet.SignalR;
using SD = SignalR.Dal;
using MessageWatch.Utils;
namespace MessageWatch.Hubs
{
public class MessageLogHub : Hub
{
NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
public IEnumerable<MessageLog> GetAllMessagesLog()
{
var messageList = new List<MessageLog>();
try
{
var conStr = ConfigurationManager.ConnectionStrings["SignalRDatabase"].ToString();
var connection = new SqlConnection(conStr);
const string query = "SELECT Message,EventID,LL.Name as LogLevelID,OC.Name as OperationCodeID,ML.ServerName,ML.ComponentName,ML.SubComponentName FROM [dbo].[MessageLog] ML inner join [dbo].[LogLevel] LL on ML.LogLevelID = LL.ID inner join [dbo].[OperationCode] OC on ML.OperationCodeID = OC.ID order by ML.ID desc";
SqlDependency.Start(conStr); // to avoid error "When using SqlDependency without providing an options value, SqlDependency.Start() must be called prior to execution of a command added to the SqlDependency instance."
var command = new SqlCommand(query, connection);
var dependency = new SqlDependency(command);
//If Something will change in database and it will call dependency_OnChange method.
dependency.OnChange += dependency_OnChange;
connection.Open();
var da = new SqlDataAdapter(command);
var dt = new DataTable();
da.Fill(dt);
for (var i = 0; i < dt.Rows.Count; i++)
{
var ml = new MessageLog
{
Name = dt.Rows[i]["Message"].ToString(),
EventID = Convert.ToInt32(dt.Rows[i]["EventID"].ToString()),
LogLevelName = dt.Rows[i]["LogLevelID"].ToString(),
OperationCodeName = dt.Rows[i]["OperationCodeID"].ToString(),
ServerName = dt.Rows[i]["ServerName"].ToString(),
ComponentName = dt.Rows[i]["ComponentName"].ToString(),
SubComponentName = dt.Rows[i]["SubComponentName"].ToString()
};
messageList.Add(ml);
}
}
catch (Exception ex)
{
_logger.Error(CultureInfo.CurrentCulture, "{0}", ex.Message);
}
return messageList;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
SendNotifications();
}
}
private void SendNotifications()
{
var messageList = GetAllMessagesLog();
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessageLogHub>();
context.Clients.All.broadcastMessage(messageList);//Will update all the clients with message log.
}
public void CreateData()
{
try
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MessageLogHub>();
var dbContext = new SD.SignalREntities();
var repository = new SD.GenericRepository(dbContext);
var ml = new DataRandomer().Create();
repository.Add(ml);
dbContext.SaveChanges();
context.Clients.All.createData();
}
catch (Exception ex)
{
_logger.Error(CultureInfo.CurrentCulture, "{0}", ex.Message);
}
}
}
}