请选择 进入手机版 | 继续访问电脑版

技术控

    今日:87| 主题:53432
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen

[复制链接]
抱着孤单睡 发表于 2016-10-4 01:58:06
236 1

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
ASP.NET SignalR is an open source library that adds real-time notifications to our application by establishing a two-way communication channel between server and client, in order to send asynchronous messages in both directions.
  HTML5 specifications about WebSocket have been introduced specifically to meet this need. Although natively supported by ASP.NET 4.5, as well as in the latest versions of popular browsers, it does require the presence of the IIS 8 web server. This poses a challenge especially when we are building a site intended for diverse audiences, since we cannot be absolutely sure that all our visitors will use browsers that are compliant with this technology.
    This article is published from the DNC Magazine for Developers and Architects .    Download this magazine from here   [PDF] or  Subscribe to this magazine for FREE  and download all previous and current editions
  SignalR connection strategy

  However, there are other techniques to establish a full-duplex communication channel and luckily ASP.NET SignalR can help us with that. During the initial stages of the communication and based on the characteristics of the server and the client, SignalR automatically makes a decision about the most suitable connection strategy to use, choosing between:
   · WebSocket : HTML5-related protocol that provides full duplex communication channels over a single TCP connection available in modern web browsers and web servers
   · Server-Sent Events : Strategy based on the EventSource HTML5 support that allows a server to stream messages to the connected clients
   · Forever Frame : Strategy based on the use of a hidden iframe element, where the chunked encoding HTTP feature is used to send stream of bytes
   · Long Polling : Basic technique that involves the opening of an HTTP connection and keeping it artificially alive to create the illusion of a persistent connection.
   By default, SignalR will try to use WebSocket whenever possible and if it's not available, it will gracefully fall back on the remaining ones until it picks the best option for the current environment. So with SignalR , we can establish real-time communication from server to clients: our application can push contents to connected clients instantly, rather than having the server wait for a client requesting new data.
  But what about pushing content from SQL Server to ASP.NET web app?

  Let’s assume we are developing a Web application to book flight tickets. Let us assume the tickets availability is stored in a database used by different booking terminals. These terminals have no idea about availability, and the only way for us to be aware of any change is to continuously poll the database for changes, and refresh the display. This approach has some disadvantages, such as a constant performance hit on the server even when there is no change in data.
   For such applications, we need the server to take the initiative and be capable of sending information to the client when a relevant event occurs, instead of waiting for the client to request it.   
   But what about the database? How can we keep our server code aware of database changes? An easy solution is writing code that periodically re-executes a query to maintain and update the server cache, and then use SignalR to send back a message to all connected clients whenever something has changed. In software terminology, this kind of continuous checking of other programs or devices to see what state they are in, is called polling.
   

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

  Figure 1: Server application polling database for changes and notifying client
  Of course, this is not the best solution. We need something that automatically notifies our server about any record change, and thereby reduces round trips to the database. Some possible options are:
  
       
  • SQL Server Service Broker.   
  • SqlNotificationRequest.   
  • SqlDependency.  
  Let’s take a look at them.
    SQL Service Broker and Queue  
  This is a feature of SQL Server where external or internal processes can send and receive asynchronous messages reliably by using extensions of T-SQL Data Manipulation Language (DML).
  SQL Server Service Broker is used to create conversations for exchanging messages. Messages are exchanged between two parties, the destination and the initiator, and allows to transmit data and trigger processing when receiving a message.
  This solution, of course, requires a good knowledge of SQL Sever needed for implementing the entire database infrastructure - that is a SQL Server Queue and a Service Broker. A server side object to listen for notifications is also needed.
  SqlNotificationRequest

  With SqlNotificationRequest, we are required to create our own Service Broker service and queue in SQL Server, as well as our own listener to process the sent notifications accordingly. We may choose to use this lower-level class for more granular control over the notification architecture. Following steps are involved:
  
       
  • Set up the Service Broker service and queue.   
  • Create an instance of the SqlNotificationRequest class and attach it to the SqlCommand.Notification property.   
  • Write a listener that retrieves and reacts to the received query notifications message.  
  This solution has the advantage to deal with a .NET class that receives notification about record changes, but still requires us to create a SQL Server Queue as well as a Service Broker.
  SqlDependency

  If we want to use query notifications without paying attention to the underlying Service Broker infrastructure, the SqlDependency .NET class in System.Data is our choice. The SqlDependency class represents a query notification dependency between an application and an instance of SQL Server. When we use query notifications, SQL Server provides the queue and the service object, as they are created automatically.
  While SqlNotificationRequest is a lower level API, SqlDependency is a high-level implementation to access query notifications. It allows us to detect changes on the database table. In most cases, this is the simplest and most effective way to leverage the SQL Server notifications capability by managed client applications (using the .NET Framework data provider for SQL Server). In short, SqlDependency provides capabilities to our application to monitor our database table for data changes without the hassles of continuously querying the database using timers or loops.
  However, the received notification doesn’t tell us which record is changed, so it is necessary to execute another database query to fetch the data. This is an example showing the event handler triggered by SqlDependency due to a record change:
  1. private void SqlDependencyOnChange(object sender, SqlNotificationEventArgs eventArgs)
  2. {
  3.     if (eventArgs.Info != SqlNotificationInfo.Invalid)
  4.     {
  5.         Console.WriteLine("Notification Info: " + eventArgs.Info);
  6.         Console.WriteLine("Notification source: " + eventArgs.Source);
  7.         Console.WriteLine("Notification type: " + eventArgs.Type);
  8.     }
  9. }
复制代码
As we can see, there is no information about the record that has been modified. With SqlDependency, infact the application issues a command that contains a query, and a request for notification. The application caches the results of the query or dynamic content generated from the query results. When the application receives the query notification, the application clears the cached content. The application then re-issues the query and the notification request, when the application needs the updated query results.
   Wouldn't it be better if this database notification returned us updated, inserted or deleted records, avoiding us to execute a new SELECT to refresh our server cache?
  SqlTableDependency for instant notifications from Database to Server

   SqlTableDependencyis an open source component that can create a series of database objects used to receive notifications on table record change. When any insert/update/delete operation is detected on a table, a change notification containing the record’s status is sent to SqlTableDependency, thereby eliminating the need of an additional SELECT to update application’s data.
   

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

  Figure 2: Notification from Database to SqlTableDependency after table record changes.
   The SqlTableDependency class represents a notification dependency between an application and a SQL Server table. To get notifications, this component provides an on the fly low-level implementation of an infrastructure composed of a table trigger, contracts, messages, queue, service broker and a clean-up stored procedure. SqlTableDependency class provides access to notifications without knowing anything about the underlying database infrastructure. When a record change happens, this infrastructure notifies SqlTableDependency, which in turn raises a .NET event to subscribers providing the updated record values. You can read more about SqlTableDependency at https://tabledependency.codeplex.com/wikipage?title=SqlTableDependency .
  Generic implementation

  This event that gets invoked implements the generic <T> pattern; a subscriber receives a C# object based on our needs. Let’s take a very simple example. Let’s take a database table as shown in Figure 3, and define a model that maps only to table columns we are interested in:
   

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

  Figure 3: Database table and relative C# model
  After this step we can establish our dependency, by simply creating a new instance of SqlTableDependency. Here we specify the C# model used to map the column’s table; and if needed, the table name as the second optional parameter.
  1. var conStr =
  2.    ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;

  3. var mapper = new ModelToTableMapper<SeatsAvailability>();
  4. mapper.AddMapping(c => c.Seats, "SeatsAvailability");

  5. using (var tableDependency = new SqlTableDependency<SeatsAvailability>(
  6.    conStr,
  7.    "FlightBookings"))
  8. {
  9.    tableDependency.OnChanged += TableDependency_Changed;
  10.    tableDependency.Start();

  11.    Console.WriteLine(@"Waiting for receiving notifications...");
  12.    Console.WriteLine(@"Press a key to stop");
  13.    Console.ReadKey();

  14.    tableDependency.Stop();
  15. }
复制代码
The ModelToTableMapper in this case is necessary because our C# model has a property whose name differs from the column’s name. The same holds true for the second parameter passed to SqlTableDependency constructor: C# model name differs from table name. If we had adopted identical names, this configuration wouldn't be necessary. Finally we define a handler that subscribes to record changes:
  1. private static void TableDependency_Changed(object sender, RecordChangedEventArgs<SeatsAvailability> e)
  2. {
  3.    var changedEntity = e.Entity;

  4.    Console.WriteLine(@"DML operation: " + e.ChangeType);
  5.    Console.WriteLine(@"From: " + changedEntity.From);
  6.    Console.WriteLine(@"To: " + changedEntity.To);
  7.    Console.WriteLine(@"Seats free: " + changedEntity.Seats);
  8. }
复制代码
For every inserted, deleted or updated record, SqlTableDependency instantiates an object with properties whose values are set based on the modifications carried on by a SQL operation. To achieve this, SqlTableDependency creates the following database objects:
   

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

  Fig.4: Database infrastructure generated from SqlTableDependency.
  The most important objects to note are:
  
       
  • Queue : used to store messages related to record changes   
  • Service broker : used to exchange info with the queue   
  • Table trigger : used to catch record changes on the monitored table, and prepare a message to put in the queue using the Service Broker.   
  • Conversation timer : This behaves as a “watch dog”. When the SqlTableDependency time-out expires, Service Broker puts a message to DialogTimer on the queue. Every message inserted in the queue triggers the activated stored procedure that detects the DialogTimer message, and executes the teardown of all SQL object generated previously in order to remove unused database objects.   
  • Activated stored procedure : used to clean up all SqlTableDependency objects in case the application closed down without disposing SqlTableDependency.  
  To use SqlTableDependency, we must have SQL Server Service Broker enabled on our database.
  A practical example using Knockout JS

  We are going to create a web application simulating a Flight Booking system. This web application serves different client terminals that book tickets for a flight. These terminals need to stay up to date constantly to avoid overbooking. The idea is to refresh all connected terminals every time a reservation is done, by submitting a message from the server containing real time availability.
  Using the described components, we can obtain a chain of notifications that starting from our database, goes to the server, and in turn goes to all terminal clients. All this without any sort of polling.
  Initial settings

  Create an ASP.NET MVC Web application and install the following packages:
  1. PM> Install-Package Microsoft.AspNet.SignalR
  2. PM> Install-Package Knockoutjs
  3. PM> Install-Package Knockout.Mapping
  4. PM> Install-Package SqlTableDependency  

  5. Then initialize SignalR:

  6. using Microsoft.Owin;
  7. using Owin;

  8. [assembly: OwinStartup(typeof(FlightBooking.Startup))]
  9. namespace FlightBooking
  10. {
  11.     public class Startup
  12.     {
  13.         public void Configuration(IAppBuilder app)
  14.         {
  15.             app.MapSignalR();
  16.         }
  17.     }
  18. }
复制代码
The following are the most important points to note during this process:
  
       
  • SignalR uses OWIN (Open Web Interface) for .NET as the standard interface between .NET web servers and web applications, enabling a level of indirection and abstraction that keeps our project from directly tying up to any specific hosting platform. This enables SignalR to be hosted from web applications.   
  • Every OWIN application must have a Startup class that follows specific conventions: a Configuration() method with the signature shown in the preceding code must be defined.   
  • The assembly-level attribute OwinStartup is used to declare that our Startup class will be used to bootstrap every OWIN-based asset contained in all the loaded assemblies.   
  • Inside the Configuration() method, we make a call to the MapSignalR() method in order to expose an endpoint called /signalr, which the clients will use to connect to the server.  
  Now we need a client. So, we customize the layout in order to include the required JavaScript libraries:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>SignalR, Knockout JS and SqlTableDependency</title>
  5. </head>
  6. <body>
复制代码
@RenderBody()
  http://~/Scripts/jquery-1.10.2.js  http://~/Scripts/jquery.signalR-2.2.0.js  http://~/signalr/hubs  http://~/Scripts/knockout-3.4.0.js  http://~/Scripts/knockout.mapping-latest.js  @RenderSection("scripts", required: false) </body> </html>
  The first relevant portions of code are the first two blocks, where we reference jquery and jquery.signalR as JavaScript libraries. jQuery is necessary because the SignalR JavaScript client is actually a jQuery plugin.
  Then we refer to a dynamic endpoint (/signalr/hubs) exposed by the server because of the MapSignalR call from the Startup class. It actually generates JavaScript code on the fly according to the available Hub. In practice, the JavaScript proxies for our Hub is built on the fly by the server-side portion of SignalR as soon as this endpoint is hit, and it is sent to the client as JavaScript source code.
  Hub implementation

   SignalR's main goal is to deliver a real-time message over HTTP. In order to do so, SignalR comes with two distinct APIs: one called Persistent connection , which we can consider as the low-level API; and one called Hub, which built on top of the former, represents a high-level API that allows client and server to call methods on each other directly. Hubs also allow us to pass strongly typed parameters to methods, enabling model binding.
  To recap our target, what we want to achieve is a notification chain that will forward this information to all connected clients, whenever any change is done to the FlightBookings table. So assuming an update DML operation on this table is executed, we want to broadcast messages from database, up to the clients.
  So we start defining our Hub class. We are going to use it to retrieve the first set of available flight seats, and then push seats availability change from the server. This class establishes a communication channel between the server and clients:
  1. [HubName("flightBookingTicker")]
  2. public class FlightBookingHub : Hub
  3. {
  4.    private readonly FlightBookingService _flightBookingService;

  5.    public FlightBookingHub() : this(FlightBookingService.Instance) { }

  6.    public FlightBookingHub(FlightBookingService flightBookingHub)
  7.    {
  8.       _flightBookingService = flightBookingHub;
  9.    }

  10.    // used to get the first result set concerning seats availability
  11.    public FlightsAvailability GetAll()
  12.    {
  13.       return _flightBookingService.GetAll();
  14.    }
  15. }
复制代码
Note: The class is marked with the HubName attribute, which allows us to give the Hub a friendly name to be used by the clients. If we don't use the HubName attribute, the Hub name will be the same as the class name.
  Hubs are instantiated through calls. Each time a client sends a message to the server, an object of this type will be created to process the request: it means that we cannot use instance members on the hub to maintain the state. After the request is processed, the object will be eliminated, so this information would be lost. That is why we need a singleton service class to constitute the channel between the database and web application; to be able to be the listener for record modifications. For this we are going to use SqlTableDependency.
  Let's create our server side "record change" listener. In its constructor, we instantiate our SqlTableDependency instance that will work as "record table change" listener, defining the connection string, and the table name to monitor:
  1. public class FlightBookingService : IDisposable
  2. {
  3.    // singleton instance
  4.    private readonly static Lazy _instance =
  5.       new Lazy(() =>
  6.          new FlightBookingService(
  7.            GlobalHost.ConnectionManager.GetHubContext().Clients));

  8.    private SqlTableDependency SqlTableDependency { get; }
  9.    private IHubConnectionContext Clients { get; }

  10.    private static connectionString =
  11.       ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;

  12.    public static FlightBookingService Instance => _instance.Value;

  13.    private FlightBookingService(IHubConnectionContext clients)
  14.    {
  15.       this.Clients = clients;

  16.       // because our C# model has a property not matching database table name,
  17.       // an explicit mapping is required just for this property
  18.       var mapper = new ModelToTableMapper();
  19.       mapper.AddMapping(x => x.Availability, "SeatsAvailability");

  20.       // because our C# model name differs from table name we must specify table name
  21.       this.SqlTableDependency = new SqlTableDependency(
  22.          connectionString,
  23.          "FlightBookings",
  24.          mapper);
  25.       
  26.       this.SqlTableDependency.OnChanged += this.TableDependency_OnChanged;
  27.       this.SqlTableDependency.Start();
  28.    }
复制代码
Unlike the Hub implementation, this service class is not disposed off when the communication with the client is ended. It has to monitor record changes, and then route this info to clients using an instance of our hub implementation. This is achieved by registering an event handler on SqlTableDependency:
  1. private void TableDependency_OnChanged(object sender,
  2.   RecordChangedEventArgs e)
  3. {
  4.   switch (e.ChangeType)
  5.   {
  6.      case ChangeType.Delete:                    
  7.         this.Clients.All.removeFlightAvailability(e.Entity);
  8.         break;

  9.      case ChangeType.Insert:
  10.         this.Clients.All.addFlightAvailability(e.Entity);
  11.         break;

  12.      case ChangeType.Update:
  13.         this.Clients.All.updateFlightAvailability(e.Entity);
  14.         break;
  15.   }
  16. }
  17. }
复制代码
  This event gives us an object populated with current table values. In case of update or insert operation, we receive the latest value; in case of delete , we receive the deleted record values. Within our event handler, we can notify a list of connected clients (IHubConnectionContext Clients property) about the change that happened on the database table. The JavaScript proxy will get this new availability, and using KnockoutJS, will update the UI.
  Our hub also exposes a method used to retrieve the seats availability. This method will be called from our client code only once - to populate the view containing the free seats:
  1. public FlightsAvailability GetAll()
  2. {
  3.   var flightsAvailability = new List();

  4.   using (var sqlConnection = new SqlConnection(connectionString))
  5.   {
  6.      sqlConnection.Open();
  7.      using (var sqlCommand = sqlConnection.CreateCommand())
  8.      {
  9.         sqlCommand.CommandText = "SELECT * FROM [FlightBookings]";

  10.         using (var sqlDataReader = sqlCommand.ExecuteReader())
  11.         {
  12.            while (sqlDataReader.Read())
  13.            {
  14.               var flightId = sqlDataReader.GetInt32(0);
  15.               var from = sqlDataReader.GetString(1);
  16.               var to = sqlDataReader.GetString(2);
  17.               var seats = sqlDataReader.GetInt32(2);

  18.               flightsAvailability.Add(new FlightAvailability {
  19.                  FlightId = flightId,
  20.                  From = from,
  21.                  To = to,
  22.                  Availability = seats
  23.               });
  24.            }
  25.         }
  26.      }
  27.   }

  28.   return new FlightsAvailability() {
  29.      FlightCompanyId = "field not used",
  30.      FlightAvailability = flightsAvailability
  31.   };
  32. }
复制代码
To complete our hub, we need to implement the IDisposable interface in order to destroy all database objects generated from SqlTableDependency.
  1. public void Dispose()
  2. {
  3.   // invoke Stop() to remove all DB objects generated from SqlTableDependency
  4.    this.SqlTableDependency.Stop();
  5. }
复制代码
Seats Availability View

  Now it is time to create a simple controller just to render our view:
  1. var conStr =
  2.    ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;

  3. var mapper = new ModelToTableMapper<SeatsAvailability>();
  4. mapper.AddMapping(c => c.Seats, "SeatsAvailability");

  5. using (var tableDependency = new SqlTableDependency<SeatsAvailability>(
  6.    conStr,
  7.    "FlightBookings"))
  8. {
  9.    tableDependency.OnChanged += TableDependency_Changed;
  10.    tableDependency.Start();

  11.    Console.WriteLine(@"Waiting for receiving notifications...");
  12.    Console.WriteLine(@"Press a key to stop");
  13.    Console.ReadKey();

  14.    tableDependency.Stop();
  15. }0
复制代码
  This view takes advantage of KnockoutJS to display free seats, as well as update them every time the availability changes on the database table. Knockout is a Model-View-ViewModel (MVVM) JavaScript library that helps us to create rich, responsive user interfaces with a clean underlying data model. Any time we have sections of UI that update dynamically (e.g., changes depending on the user’s actions or when an external data source changes), knockout will refresh our UI. This is achieved using the data-bind attribute added to DOM elements, that automatically update their values.
              Flight Id     From     To     Seats Availability                                            @section Scripts {  http://~/Scripts/flightBookingTicker.js  }
  Knockout ViewModel and SignalR client code

  What remains to do is to define our knockout ViewModel, used to bind HTML elements with our server data. In this example, we take advantage of the Knockout Mapping plug-in. This is an alternative to manually writing your own JavaScript code that constructs a ViewModel based on data we are fetching from the server. The mapping plug-in will convert JavaScript objects or JSON strings into Knockout observable properties that will be automatically added to our ViewModel. In the end, this step results in having four properties (flightId, from, to, freeSeats) created in our ViewModel.
  1. var conStr =
  2.    ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;

  3. var mapper = new ModelToTableMapper<SeatsAvailability>();
  4. mapper.AddMapping(c => c.Seats, "SeatsAvailability");

  5. using (var tableDependency = new SqlTableDependency<SeatsAvailability>(
  6.    conStr,
  7.    "FlightBookings"))
  8. {
  9.    tableDependency.OnChanged += TableDependency_Changed;
  10.    tableDependency.Start();

  11.    Console.WriteLine(@"Waiting for receiving notifications...");
  12.    Console.WriteLine(@"Press a key to stop");
  13.    Console.ReadKey();

  14.    tableDependency.Stop();
  15. }1
复制代码
The main ViewModel - FlightsBookingViewModel - has a constructor parameter used to initialize itself with initial seats availability. Also, it exposes three methods used to update itself, and consequently the UI:
  
       
  • removeFlightAvailability   
  • updateFlightAvailability   
  • addFlightAvailability  
  These methods will be called from the client-side hub proxy every time it is notified from our server side code using SignalR:
  1. var conStr =
  2.    ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;

  3. var mapper = new ModelToTableMapper<SeatsAvailability>();
  4. mapper.AddMapping(c => c.Seats, "SeatsAvailability");

  5. using (var tableDependency = new SqlTableDependency<SeatsAvailability>(
  6.    conStr,
  7.    "FlightBookings"))
  8. {
  9.    tableDependency.OnChanged += TableDependency_Changed;
  10.    tableDependency.Start();

  11.    Console.WriteLine(@"Waiting for receiving notifications...");
  12.    Console.WriteLine(@"Press a key to stop");
  13.    Console.ReadKey();

  14.    tableDependency.Stop();
  15. }2
复制代码
Our code is written inside a classic jQuery $(...); call, which actually ensures that it is called when the page is fully loaded. We first take a reference to our Hub, which is exposed by the $.connection.flightBookingTicker property generated by the dynamic endpoint.
  Then we add three callback methods on flightBookingTicker hub proxy: updateFlightAvailability, addFlightAvailability and removeFlightAvailability, whose name and signature are matching the method that the server Hub is trying to call back. These functions will update the knockout ViewModel with the received server message every time a record is changed.
  After that we call the start() method exposed by the $.connection.hub member, which performs the actual connection to our server. The start() call is asynchronous, and we have to make sure it has actually been completed before using any hub. That's easy because start() returns a promise object containing a done() method to which we can pass a callback function, where we put our hub-related code. Here we get the initial list of seats availability using server member (getAll) defined in Hub instance. Using this, we are able to call any method exposed by the Hub, creating the knockout ViewModel and execution the applyBindings call. When this function is executed, Knockout processes both the view and the ViewModel. All data bindings in the view are executed and dynamically replaced with the data contained in the ViewModel, that in our case, is FlightBookingViewModel.
  Wrapping Up

  So far, instead of executing a request from client to the web application, and then the web application to the database; we are doing the reverse: sending a request from database to web application, and in turn from web application to clients. Figure 5 shows an example of notification workflow when a table record changes:
   

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

Broadcast Real-Time Notifications using SignalR, KnockoutJS and SqlTableDependen ...

  Figure 5: Notification chain when a record changes in the monitored database table
  How to test

   You can download the source code at https://realtimenotifications.codeplex.com ; then create a database table with the following SQL script:
  1. var conStr =
  2.    ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;

  3. var mapper = new ModelToTableMapper<SeatsAvailability>();
  4. mapper.AddMapping(c => c.Seats, "SeatsAvailability");

  5. using (var tableDependency = new SqlTableDependency<SeatsAvailability>(
  6.    conStr,
  7.    "FlightBookings"))
  8. {
  9.    tableDependency.OnChanged += TableDependency_Changed;
  10.    tableDependency.Start();

  11.    Console.WriteLine(@"Waiting for receiving notifications...");
  12.    Console.WriteLine(@"Press a key to stop");
  13.    Console.ReadKey();

  14.    tableDependency.Stop();
  15. }3
复制代码
After setting the connection string, run the web application. Initially, if the database table has no data, an empty grid will be shown, otherwise its records will be displayed. Open SQL Server Manager and add, modify or delete a record in the table: as a record is committed we will get an immediate notification from the database to web server and, thanks to SignalR, from the web application to HTML page. Here, with the help of Knockout JS, the single row in the grid will be modified, based on what we have received from the database.
  
       
  •   Please Share this article if you think it was worth reading. Thanks!
      



上一篇:Understanding Python Class Instantiation
下一篇:New lower Azure pricing
冯正元 发表于 2016-10-4 12:01:36
2016-10-04是什么日子?
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )

© 2001-2017 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表