ASP.NET SignalR: Polling kiểu cũ, làm nó tốt hơn

Một trang web thường cần phải cập nhật một trang như những thay đổi dữ liệu bên dưới. Bạn có thể, tất nhiên, chỉ cần poll các máy chủ mỗi vài giây trên các trình duyệt thông qua JavaScript, nhưng để nhận được cập nhật trực tiếp từ một trang web,tốt hơn là để đẩy dữ liệu cho trình duyệt, sử dụng SignalR dựa trên máy chủ. Điều này sử dụng web socket để làm điều này hơn là dựa trên trình duyệt web polling mà được hỗ trợ trên các trình duyệt. Dino sẽ giải thích như thế nào.

Kể từ những ngày đầu của Ajax, các nhà phát triển web đấu tranh để làm cho các trang của họ có khả năng tiếp nhận và hiển thị thông tin cập nhật theo thời gian thực. Nó thực sự là một kinh nghiệm tốt đẹp cho người dùng khi họ mở một trang nhất định, đọc nội dung, và sau đó nhận được bản cập nhật cho các nội dung và nếu thay đổi xảy ra sẽ được phát hiện. Khó khăn của việc có các trang web sống là tất cả ở đây, trong các hiệu ứng kết hợp của hai biểu thức "thay đổi xảy ra" và "phát hiện".

Các nội dung mà các trang web hiển thị xuất phát từ sản lượng của một số lớp phụ trợ. Do đó nội dung trực tiếp là kết quả của một số máy chủ xử lý bên đó xảy ra không đồng bộ với việc vẽ và hiển thị trang web. Một ví dụ phổ biến là một trang trình bày kết quả của một số sự kiện trực tiếp, cho dù trò chơi bóng đá, giải đấu quần vợt,... nhưng cũng có một trang mà bắt đầu một quá trình xử lý dài và báo cáo về tiến trình đó.

Bởi bản chất của các trang web và các website, nó không phải là một nhiệm vụ dễ dàng để nhận được cập nhật trực tiếp trong trình duyệt. Trong khi không phải không thể ở tất cả và hàng trăm các trang web ra có thể chứng kiến nó-live các trang web yêu cầu một thiết kế và việc sử dụng các khung đặc biệt. Tại cốt lõi của nó, một trang sống cần có một cơ chế để gọi lại các môi trường máy chủ để biết về những thay đổi và một cơ chế để làm mới nội dung hiện tại. Kết hợp với nhau, Ajax (thông qua jQuery và Web Services) và các DOM mà trình duyệt thực hiện chắc chắn có thể giải quyết vấn đề. Nhưng đây chỉ là một giải pháp và không nhất thiết phải là hiệu quả nhất. Giải pháp này được dựa trên polling và, trong khi hiệu quả, có thể liên quan đến việc sử dụng quá mức các nguồn tài nguyên và tạo ra lưu lượng truy cập web quá nhiều.

Trong bài viết này, tôi sẽ bắt đầu từ đây và sau đó thảo luận về cấu trúc của các trang web trực tiếp và làm lại các giải pháp cổ điển để sử dụng ASP.NET SignalR.

Các mẫu Classic: Poll-và-Refresh

Kể từ sự ra đời của DOM động vào cuối năm 1990, nó đã không còn là một vấn đề để sửa đổi toàn bộ body của một trang web hiển thị, mặc dù nó vẫn còn khó khăn để đưa dữ liệu trực tiếp và thời gian thực xuống trang, cho đến nay Vấn đề đã được giải quyết với các dịch vụ XML Web đầu và điểm cuối JSON tiếp kết hợp với một thư viện JavaScript dễ sử dụng như jQuery. Vấn đề cuối cùng là sau đó: làm thế nào để buộc các trình duyệt để có được dữ liệu mới khi dữ liệu mới đã có sẵn?

Đối với kiến trúc của các giải pháp web đó không phải dễ dàng để có những bước của việc có các máy chủ đẩy lại dữ liệu cho khách hàng. Hầu hết các giải pháp đã được thực hiện với một bộ đếm thời gian bằng JavaScript mà gọi là một chức năng truy vấn ở mỗi khoảng thời gian.

var timer = window.setInterval (function () {
    // Kết nối với một điểm cuối HTTP, lấy dữ liệu
    // và cập nhật các DOM
    $ ("# liveDataContainer") load (url);.
}, 20000);

Như trong ví dụ, bạn có thể sử dụng một trong vô số các phương pháp của thư viện jQuery để kết nối với một URL, lấy một đoạn mã HTML và có thư viện để đính kèm nó ngay trong cơ thể của các quy định HTML yếu tố, ví dụ một phần tử DIV . Tham số đầu tiên của trình duyệt của setTimeout phương pháp có chức năng Javascript để gọi nhiều lần; tham số thứ hai chỉ ra độ dài của khoảng thời gian trong mili giây. Kết quả là, như các ví dụ trước, các nội dung của liveDataContainer phần tử HTML được cập nhật mỗi hai mươi giây với bất HTML được trả về bởi các URL được chỉ định.

Trong ASP.NET MVC, bạn có thể dễ dàng tạo ra như một điểm cuối HTML sử dụng một lần xem một phần. Dưới đây là một ví dụ:

[HttpGet]
public ActionResult Live ()
{
    var mô hình = GetViewModelInSomeWay ();
    return PartialView ("_ sống", mô hình);
}

Dự án được giả định có một _live.cshtml tập tin được xác định để vẽ lại một đoạn mã HTML-không phải là một đầy đủ trang-sáp nhập một mẫu định sẵn với dữ liệu trực tiếp qua các View chứa dữ liệu Model.

Lấy cảm hứng từ một trong những mô hình Ajax đầu tiên, phương pháp này làm việc tuyệt vời và không có lý do để tin rằng, nói về mặt chức năng, nó sẽ ít hiệu quả hơn này trong tương lai gần. Nó cũng cần lưu ý rằng phương pháp này thậm chí không đòi hỏi kiến thức sâu sắc về JSON, khung JavaScript hoặc những phức tạp của lập trình phía máy khách. Trong một cách, phương pháp này chỉ là một phiên bản hiện đại hơn và mượt mà của thẻ meta refresh cổ điển.

<meta http-equiv="refresh" content="20">

Được đặt trong phần đầu của trang, các thẻ meta refresh chỉ thị các trình duyệt để làm mới hoàn toàn trang mỗi số quy định của giây. Cách tiếp cận JavaScript là mượt mà vì nó chỉ làm mới các đoạn quy định của DOM.

JSON dựa trên Poll-và-Refresh

Các cách tiếp cận trước làm cho trang rất nhiều phản ứng nhanh hơn và dễ chịu khi làm việc mà vẫn giữ một loạt các áp lực về phía máy chủ. Điểm này đã được tranh luận khá nhiều thời gian gần đây. Sự cân bằng của việc có công việc được thực hiện trên máy khách và / hoặc máy chủ là gì? Lập trình máy chủ có lẽ là tốt nhất được biết đến, và trong vấn đề này, đáng tin cậy hơn. Có những khách hàng nhận được dữ liệu thô và định dạng trong qua JavaScript di chuyển rất nhiều công việc đi từ máy chủ. Trong số những thứ khác, đây cũng là một yếu tố màu xanh lá cây và có tiềm năng một cách để tiết kiệm điện. Tải JSON thay vì HTML thường nhanh hơn nhưng các nhà phát triển lực lượng này là để thiết kế các trang web một cách hoàn toàn khác nhau. Đối với hầu hết các phần bạn cần một công cụ phía khách hàng liên kết dữ liệu cho dù MustacheJS (xem http://www.simple-talk.com/dotnet/.net-framework/quick-and-dirty-web-data-binding ), KnockoutJS hoặc một số module của AngularJS.

Cuối cùng, nó là vấn đề sở thích cho dù bạn muốn có điểm cuối HTTP mà trở về HTML hoặc định dạng sẵn dữ liệu JSON để định dạng thông qua JavaScript. Một quyết định quan trọng hơn cho các trang web trực tiếp là sự lựa chọn của các cơ chế mà gây nên làm mới trang.

Long Polling và ASP.NET SignalR

Trong đoạn mã trên, tôi đã sử dụng một bộ đếm thời gian dummy mà xếp hàng một cuộc gọi đến HTTP endpoint cụ thể mỗi số quy định của mili giây. Điều này có thể tạo ra khá một chút về traffic. Bạn chắc chắn có thể tinh chỉnh số lượng lưu lượng diễn xuất vào độ dài của khoảng thời gian, nhưng điều đó đã được trung gian với tần số mà bạn cần để hiển thị dữ liệu mới, nếu có. Ví dụ, bạn đang cung cấp chương trình thể thao trực tiếp cung cấp số điểm hiện tại cho một môn thể thao như quần vợt, trong đó thay đổi điểm số trong một vài giây. Một giá trị tốt để thiết lập bộ đếm thời gian có thể là 30 hoặc 40 giây. Nó có thể là hơi ngắn hơn nếu bạn là live-ghi một số trận đấu được tiến hành, và nó có thể hơi lâu hơn nếu bạn đang theo dõi một trận đấu nào. Tuy nhiên, nó có nghĩa là bạn sẽ có một cuộc gọi được thực hiện cho các máy chủ mỗi 30 hoặc 40 giây từ bất kỳ của hàng trăm hoặc hàng ngàn hoặc nhiều hơn của khách hàng được kết nối.

ASP.NET SignalR là một khuôn khổ giúp để giảm thiểu các tác động trên các máy chủ của loại hình này hoạt động trong một cách đó là hoàn toàn minh bạch cho các nhà phát triển,SignalR sử dụng web socket để kết nối với máy chủ nếu trình duyệt hỗ trợ cho họ; nếu không thì nó chuyển sang long polling. Hiệu quả là như nhau nhưng các tác động trên máy chủ được giảm tới mức tối thiểu đó là có thể. Chúng ta hãy xem làm thế nào để cấu hình ASP.NET SignalR.

Cấu hình của SignalR

Các bước đầu tiên hướng tới sử dụng SignalR là cài đặt các gói từ NuGet. Bạn nhận được một vài file, một số tập tin JavaScript và một số nhị phân. Một trong những chương trình là các thư viện OWIN được sử dụng để bắt đầu và cấu hình SignalR. Trước hết, bạn phải có tập tin sau đây trong các dự án, được đặt tên startup.cs .

using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(YourProject.Startup))]
namespace YourProject
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

SignalR có một máy khách và một phần máy chủ. Các phần khách hàng bao gồm một vài hàm JavaScript-để bắt đầu lắng nghe thay đổi phía máy chủ và một để thông báo cho người nghe những thay đổi server-side. Phần phía khách hàng được phục vụ như là một plugin jQuery. Trong trang web này dự kiến sẽ hiển thị dữ liệu trực tiếp, bạn tham khảo các tập tin script SignalR.

<script type="text/javascript"
	src="@Url.Content("~/content/scripts/jquery.signalR-2.2.0.min.js")"></script>

Tiếp theo, bạn thêm khối kịch bản sau đây để xem HTML cùng.

<Script>
   $ (function () {
      // Lưu các tham chiếu đến các trung tâm SignalR
      var theHub = $ ​​.connection.yourAppHub;

      // Gọi hàm được gọi trở lại từ máy chủ
      // khi thay đổi được phát hiện
      ...

      // Bắt đầu SignalR client-side nghe
      . $ .connection.hub.start () done (function () {
         // Làm ở đây bất kỳ công việc khởi tạo, bạn có thể cần
         ...
      });
   });
</ script>

Đoạn mã có chứa một vài tài liệu tham khảo cần được giải thích thêm, đáng kể nhất là đối tượng trung tâm. Các $.connection là điểm mấu chốt trong các plugin SignalR jQuery và bày ra một kết nối để bắt đầu các cơ sở hạ tầng của máy khách lắng nghe từ những thay đổi từ máy chủ. Các $.connection.hub là các wrapper cho các cơ sở hạ tầng thông tin liên lạc có sử dụng long polling hoặc web socket miễn là phù hợp. Bằng cách gọi hàm bắt đầu, bạn bắt đầu quá trình lắng nghe. Bạn cũng có cơ hội để thực hiện một số nhiệm vụ khởi tạo, chẳng hạn như cập nhật các giao diện người dùng, nhưng đó là hoàn toàn tùy chọn.

SignalR Hubs

Rất nhiều chi tiết thú vị là $.connection.yourAppHub bạn cũng tìm thấy ở trước đoạn mã JavaScript. Đó là đề cập đến các thiết bị đầu cuối tương ứng phía máy khách cho các bộ xử lý SignalR server-side. Nói cách khác, một khi bạn bắt đầu kết nối mã khách hàng của bạn sẽ được gọi trở lại từ máy chủ bất cứ khi nào máy chủ phát hiện bất kỳ hành động liên quan được thông báo cho khách hàng. Bất cứ lúc nào các mã máy chủ thực hiện một nhiệm vụ mà thay đổi trạng thái của hệ thống, nó có thể muốn gọi lại cho khách hàng và chuyển thông tin cụ thể.

Việc gọi lại diễn ra thông qua một lớp Hub bạn xác định trên máy chủ. Dưới đây là một ví dụ:

public class YourAppHub : Hub
{
    public static void Refresh()
    {
       var hubContext = GlobalHost.ConnectionManager.GetHubContext();
       hubContext.Clients.All.refreshPage();
    }
}

Các lớp trung tâm phía máy chủ có thể có nhiều hàm như bạn muốn, thường là một cho mỗi kịch bản cập nhật bạn muốn được phản ánh trên các client. Để thông báo cho các khách hàng của bản cập nhật, mã máy chủ chỉ cần gọi một trong những hàm trên lớp hub, hoặc một trong các lớp hub bạn có thể có. Có một cái nhìn cẩn thận tại các dòng sau:

hubContext.Clients.All.refreshPage ();

Hàm refreshPage đến từ đâu? Đó là tên của phương thức JavaScript sẽ phản ứng với các thông báo máy chủ. Ngoài ra, tên của các trung tâm phía khách hàng phù hợp với tên của các máy chủ hub-yourAppHub.

var theHub = $ ​​.connection.yourAppHub;
theHub.client.refreshPage = function () {
     // Mã để làm mới trang dựa trên các thông tin sắp tới
     // từ máy chủ
      $.ajax({
        url: "/live/update",
        cache: false,
        dataType: "html",
        success: function (data) {
             $("#containerToUpdate").html(data);
        }
    });
 };

Có nhiều hơn một mảnh mà vẫn còn thiếu. Trường hợp là đoạn code mà làm cho nó có thể tìm thấy một đối tượng gọi yourAppHub về các plugin SignalR và ở đâu là đoạn code mà đảm bảo rằng các đối tượng JavaScript có giao diện giống như hub máy chủ? Đó là tất cả ở điểm cuối của kịch bản sau đây bạn cần phải có trên HTML cùng với các tài liệu tham khảo để các plugin SignalR jQuery.

<script type="text/javascript" src="~/signalr/hubs"></script>

Đó là một điểm cuối HTTP cố định; và nó sẽ tự động tạo ra mã JavaScript trong trang của bạn. Các mã sau thiết bị đầu cuối sẽ nhìn vào lớp máy chủ hub của bạn và tạo ra bất kỳ kết hợp mã JavaScript và để nó vào DOM của bạn.

Di chuyển dữ liệu xung quanh

Nếu cần thiết, các máy chủ có thể truyền dữ liệu xung quanh cho khách hàng. Bất cứ khi nào bất kỳ tác vụ máy chủ nào thực hiện một cái gì đó phải được thông báo cho khách hàng, tất cả họ làm là để gọi một hàm hub.

YourAppHub.Refresh ();

Không có gì ngăn cản bạn thêm dữ liệu vào các prototype của phương thức Refresh. Nếu bạn làm thế, các dữ liệu được serialized để JSON và bàn giao cho hub client JavaScript.

theHub.client.refreshPage = function (incomingData) {
    // Làm mới DOM trực tiếp sử dụng các dữ liệu đến
    ...
}

Nếu dữ liệu đến được làm bằng một vài giá trị cập nhật các DOM có thể khá dễ dàng. Nếu không, nói đó là một danh sách các đối tượng, sau đó nó có thể yêu cầu một mẫu HTML. Điều này lại liên quan đến việc sử dụng một khung khuôn mẫu như AngularJS, KnockoutJS hoặc thậm chí Mustache. Là một thay thế, bạn chỉ có thể nói với các máy khách mã JavaScript để yêu cầu một bản cập nhật HTML từ máy chủ. Đây là những gì các mã sau đây, đã trình bày ở trên, thực hiện:

$.ajax({ url: "/live/update", cache: false, dataType: "html", success: function (data) { $("#containerToUpdate").html(data); } });```Csharp

Giả sử một ứng dụng ASP.NET MVC, các phương thức Update trên bộ điều khiển webcam trả về một đoạn mới của HTML sẽ được chèn vào trong một container DIV với jQuery. Trong trường hợp này, quan điểm của HTML của bạn vẫn còn quan điểm cổ điển với HTML không cần có dữ liệu phía máy khách tham gia. Thay vào đó bạn chỉ nhìn thấy giá trị trong việc sử dụng dữ liệu phía máy khách sau đó ràng buộc SignalR chắc chắn là sự lựa chọn tốt nhất của bạn.

Tóm lược

Các mô hình cũ của polling một máy chủ chia sẻ tài nguyên để xem nếu bất cứ điều gì đã thay đổi kể từ lần cuối cùng là một thứ luôn luôn hoạt động. Nó có thể gây tranh cãi về tính hiệu quả của nó hoạt động, nhưng chắc chắn nó hoạt động. Ngay cả khi polling hoạt động cho bạn ngày hôm nay, bạn có thể muốn xem xét một sự thay thế mà chỉ có thể cung cấp cho bạn hiệu suất tốt hơn và làm nhẹ áp lực trên máy chủ. Đây là ASP.NET SignalR, một khung phía máy chủ với một plugin jQuery để ràng buộc làm mới trang của khách hàng với các lệnh từ máy chủ. Web socket được sử dụng để thực hiện các cơ chế thúc đẩy này và nếu web socket không được hỗ trợ bởi các trình duyệt sau đó polling sẽ được sử dụng trong một cách đó là hoàn toàn minh bạch cho các nhà phát triển.