我想开发一个HTML页面实时更新的项目。所以我开始在互联网上搜索,我发现只有这个有效的例子:http://venkatbaggu.com/signalr-database-update-notifications-asp-net-mvc-usiing-sql-dependency/
然后我试着让它适应我的项目。我先用一些代码解释一下。
这是我的数据库图表的一部分:
这里有一些代码:
[Table("Devices")]
public class Device
{
[Key]
public long DeviceId { get; set; }
[DisplayName("Modello")]
public long ModelId { get; set; }
[DisplayName("Fornitore")]
public long SupplierId { get; set; }
[DisplayName("Numero di serie")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un numero di serie")]
public string SerialNumber { get; set; }
[DisplayName("Codice fornitore")]
[StringLength(50)]
public string SupplierCode { get; set; }
[DisplayName("Data di acquisto")]
public DateTime DatePurchase { get; set; }
public virtual Model Model { get; set; }
public virtual Supplier Supplier { get; set; }
}
[Table("DeviceTypes")]
public class DeviceType
{
[Key]
public long DeviceTypeId { get; set; }
[DisplayName("Tipo dispositivo")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un tipo dispositivo")]
public string Name { get; set; }
}
[Table("HttpPop3")]
public class HttpPop3
{
[Key]
public long ID { get; set; }
public long DeviceId { get; set; }
[DisplayName("Mittente")]
[StringLength(50)]
[Required]
public string sms_num { get; set; }
[DisplayName("Data")]
[StringLength(50)]
[Required]
public string sms_date { get; set; }
[DisplayName("Testo")]
[StringLength(255)]
[Required]
public string sms_text { get; set; }
[DisplayName("Code")]
[StringLength(50)]
public string sms_code { get; set; }
public virtual Device Device { get; set; }
}
[Table("Models")]
public class Model
{
[Key]
public long ModelId { get; set; }
[DisplayName("Prodotto")]
public long ProductId { get; set; }
[DisplayName("Tipo dispositivo")]
public long DeviceTypeId { get; set; }
[DisplayName("Modello")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un modello")]
public string Name { get; set; }
public virtual Product Product { get; set; }
public virtual DeviceType DeviceType { get; set; }
}
[Table("Products")]
public class Product
{
[Key]
public long ProductId { get; set; }
[DisplayName("Produttore")]
public long VendorId { get; set; }
[DisplayName("Prodotto")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un prodotto")]
public string Name { get; set; }
public virtual Vendor Vendor { get; set; }
}
[Table("Suppliers")]
public class Supplier
{
[Key]
public long SupplierId { get; set; }
[DisplayName("Fornitore")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un fornitore")]
public string Name { get; set; }
[DisplayName("Indirizzo")]
[StringLength(50)]
public string Address { get; set; }
[DisplayName("Numero civico")]
[StringLength(10)]
public string Number { get; set; }
[DisplayName("Telefono")]
[StringLength(50)]
public string Phone { get; set; }
[DisplayName("Fax")]
[StringLength(50)]
public string Fax { get; set; }
[DisplayName("Email")]
[StringLength(50)]
public string Email { get; set; }
}
[Table("Vendors")]
public class Vendor
{
[Key]
public long VendorId { get; set; }
[DisplayName("Produttore")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un produttore")]
public string Name { get; set; }
}
public class iCareEntities : DbContext
{
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<DeviceType> DeviceTypes { get; set; }
public DbSet<Vendor> Vendors { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Model> Models { get; set; }
public DbSet<Device> Devices { get; set; }
public DbSet<HttpPop3> HttpPop3s { get; set; }
}
public class HttpPop3Repository
{
iCareEntities db = new iCareEntities();
string connString = ConfigurationManager.ConnectionStrings["iCareEntities"].ConnectionString;
public IEnumerable<HttpPop3> GetAllMessages()
{
//This method doesn't work
List<HttpPop3> messages = new List<HttpPop3>();
using (var connection = new SqlConnection(connString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(@"SELECT [Mittente], [Data], [Testo], [Code] FROM [iCare].[dbo].[HttpPop3View] ORDER BY [Data] DESC", connection))
{
command.Notification = null;
SqlDependency 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(new HttpPop3 { sms_num = (string)reader["Mittente"], sms_date = (string)reader["Data"], sms_text = (string)reader["Testo"], sms_code = (string)reader["Code"] });
}
}
}
return messages;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
MyHub.SendMessages();
}
}
}
[HubMethodName("sendMessages")]
public static void SendMessages()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
context.Clients.All.updateMessages();
}
HttpPop3
是一台SMS机器,在收到消息时进行POST。
我的目标是在HttpPop3
表中插入新消息时实时更新视图。这里是机器发出POST的代码隐藏:
public partial class _0090C2E7BD56 : System.Web.UI.Page
{
private iCareEntities db = new iCareEntities();
protected void Page_Load(object sender, EventArgs e)
{
if (Request["sms_num"] != null && Request["sms_date"] != null && Request["sms_text"] != null)
{
iCare.Models.HttpPop3 httppop3 = new iCare.Models.HttpPop3
{
// 0090C2E7BD56 is the serial number of the machine a 1 is its primary key in Devices table
DeviceId = 1,
sms_num = Request["sms_num"],
sms_date = Request["sms_date"],
sms_text = Request["sms_text"],
sms_code = Request["sms_code"]
};
db.HttpPop3s.Add(httppop3);
db.SaveChanges();
}
}
}
这样可行,当消息到达时,我的表格中有一个新行。
我使用观看次数生成HttpPop3Controller
之后:
public class HttpPop3Controller : Controller
{
private iCareEntities db = new iCareEntities();
// GET: /HttpPop3/
public ActionResult Index()
{
var httppop3s = db.HttpPop3s.Include(h => h.Device);
return View(httppop3s.ToList());
}
// GET: /HttpPop3/Details/5
public ActionResult Details(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
HttpPop3 httppop3 = db.HttpPop3s.Find(id);
if (httppop3 == null)
{
return HttpNotFound();
}
return View(httppop3);
}
// GET: /HttpPop3/Create
public ActionResult Create()
{
ViewBag.DeviceId = new SelectList(db.Devices, "DeviceId", "SerialNumber");
return View();
}
// POST: /HttpPop3/Create
// Per proteggere da attacchi di overposting, abilitare le proprietà a cui eseguire il binding.
// Per ulteriori dettagli, vedere http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="ID,DeviceId,sms_num,sms_date,sms_text,sms_code")] HttpPop3 httppop3)
{
if (ModelState.IsValid)
{
db.HttpPop3s.Add(httppop3);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.DeviceId = new SelectList(db.Devices, "DeviceId", "SerialNumber", httppop3.DeviceId);
return View(httppop3);
}
// GET: /HttpPop3/Edit/5
public ActionResult Edit(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
HttpPop3 httppop3 = db.HttpPop3s.Find(id);
if (httppop3 == null)
{
return HttpNotFound();
}
ViewBag.DeviceId = new SelectList(db.Devices, "DeviceId", "SerialNumber", httppop3.DeviceId);
return View(httppop3);
}
// POST: /HttpPop3/Edit/5
// Per proteggere da attacchi di overposting, abilitare le proprietà a cui eseguire il binding.
// Per ulteriori dettagli, vedere http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="ID,DeviceId,sms_num,sms_date,sms_text,sms_code")] HttpPop3 httppop3)
{
if (ModelState.IsValid)
{
db.Entry(httppop3).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.DeviceId = new SelectList(db.Devices, "DeviceId", "SerialNumber", httppop3.DeviceId);
return View(httppop3);
}
// GET: /HttpPop3/Delete/5
public ActionResult Delete(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
HttpPop3 httppop3 = db.HttpPop3s.Find(id);
if (httppop3 == null)
{
return HttpNotFound();
}
return View(httppop3);
}
// POST: /HttpPop3/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(long id)
{
HttpPop3 httppop3 = db.HttpPop3s.Find(id);
db.HttpPop3s.Remove(httppop3);
db.SaveChanges();
return RedirectToAction("Index");
}
public ActionResult GetMessages()
{
HttpPop3Repository httpPop3Repository = new HttpPop3Repository();
return PartialView("_HttpPop3List", httpPop3Repository.GetAllMessages());
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
我不知道为什么还有列[Devices]。[SerialNumber]但是对我来说没关系,它可以帮助我识别哪台机器收到了这条消息。
这里是我在示例中修改的Index.cshtml:
@model IEnumerable<iCare.Models.HttpPop3>
@{
ViewBag.Title = "Index";
}
<div class="row">
<div class="col-md-12">
<div id="httpPop3Table"></div>
</div>
</div>
@section Scripts{
<script src="/Scripts/jquery.signalR-2.1.1.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var notifications = $.connection.myHub;
//debugger;
// Create a function that the hub can call to broadcast messages.
notifications.client.updateMessages = function () {
GetAllMessages()
};
// Start the connection.
$.connection.hub.start().done(function () {
alert("connection started")
GetAllMessages();
}).fail(function (e) {
alert(e);
});
});
function GetAllMessages() {
var tbl = $('#httpPop3Table');
$.ajax({
url: '/HttpPop3/GetMessages',
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result) {
tbl.empty().append(result);
}).error(function () {
});
}
</script>
}
好的,现在问题了。这是我的HttpPop3Repository:
public class HttpPop3Repository
{
iCareEntities db = new iCareEntities();
string connString = ConfigurationManager.ConnectionStrings["iCareEntities"].ConnectionString;
public IEnumerable<HttpPop3> GetAllMessages()
{
//This method doesn't work
List<HttpPop3> messages = new List<HttpPop3>();
using (var connection = new SqlConnection(connString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(@"SELECT [Mittente], [Data], [Testo], [Code] FROM [iCare].[dbo].[HttpPop3View] ORDER BY [Data] DESC", connection))
{
command.Notification = null;
SqlDependency 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(new HttpPop3 { sms_num = (string)reader["Mittente"], sms_date = (string)reader["Data"], sms_text = (string)reader["Testo"], sms_code = (string)reader["Code"] });
}
}
}
return messages;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
MyHub.SendMessages();
}
}
}
如果HttpPop3类没有此属性,如何设置SerialNumber列?
谢谢
答案 0 :(得分:0)
您是否在global.asax
中启动了SQL依赖项请查看步骤3,此代码段丢失之前我更新了帖子
public class MvcApplication : System.Web.HttpApplication
{
string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
GlobalConfiguration.Configure(WebApiConfig.Register);
//Start SqlDependency with application initialization
SqlDependency.Start(connString);
}
protected void Application_End()
{
//Stop SQL dependency
SqlDependency.Stop(connString);
}
}
答案 1 :(得分:0)
尝试检查您可以从SqlDependency获取的其他信息。例如:
private static void Dependency_OnChanged(object sender, SqlNotificationEventArgs e)
{
bool updated = e.Info == SqlNotificationInfo.Update;
bool changed = e.Type == SqlNotificationType.Change;
bool isClient = e.Source == SqlNotificationSource.Data;
bool acceptable = updated && changed && isClient;
if (acceptable)
{
MyHub.SendMessages();
}
}
另一个想法我应该提到的是把
SqlDependency.Start(connString);
如果要创建具有迁移和代码的部署包,那么进入Global.asax中的Application_Start()并不是一个好主意。当您尝试部署它并希望迁移在第一次运行时为您创建新数据库时,这将会严重崩溃,因为您正在设置对不存在的数据库的依赖性......希望这有帮助...
答案 2 :(得分:0)
所以,另一个论坛的人建议我解决这个问题。我在Product类中添加了一个VendorName变量,其属性为[NotMapped]:
[Table("Products")]
public class Product
{
[Key]
[DisplayName("ID Prodotto")]
public long ProductID { get; set; }
[DisplayName("ID Produttore")]
public long VendorID { get; set; }
[DisplayName("Prodotto")]
[StringLength(50)]
[Required(AllowEmptyStrings = false, ErrorMessage = "E' richiesto un prodotto")]
public string Name { get; set; }
public virtual Vendor Vendor { get; set; }
[NotMapped]
[DisplayName("Produttore")]
public string VendorName { get; set; }
}
我的GetAllProducts方法变为:
public IEnumerable<Product> GetAllProducts()
{
List<Product> products = new List<Product>();
using (var connection = new SqlConnection(connString))
{
StringBuilder query = new StringBuilder();
query.Append("SELECT dbo.Products.ProductID, dbo.Vendors.Name AS VendorName, dbo.Products.Name AS ProductName ");
query.Append("FROM dbo.Products ");
query.Append("INNER JOIN dbo.Vendors ON dbo.Products.VendorID = dbo.Vendors.VendorID");
connection.Open();
using (SqlCommand command = new SqlCommand(query.ToString(), connection))
{
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
products.Add(new Product { ProductID = (long)reader["ProductID"], VendorName = (string)reader["VendorName"], Name = (string)reader["ProductName"] });
}
}
}
return products;
}
所以我有一个VendorName,在那里分配值,我没有得到错误'列不存在'。 要编写Sql查询,我使用SQL Server Management Studio视图设计器,它可以工作。
我已经有些问题了。 如果填充了所有列,则一切正常。如果有一些空值我无法从数据库获得任何东西。
我该如何解决?