Cách tạo luồng Twitter thời gian thực với SignalR


Dương Thái Bảo
3 năm trước
Hữu ích 4 Chia sẻ Viết bình luận 0
Đã xem 4491

SignalR đã trở thành một công nghệ đột phá mà tất cả các nhà phát triển ASP.NET muốn đưa vào các ứng dụng web của họ.

Nó chắc chắn làm mờ các dòng giữa ứng dụng web và ứng dụng máy tính để bàn và khiến người dùng của bạn ngồi dậy và chú ý đến một trang web động hiển thị chuyển động thay vì văn bản và hình ảnh trên một trang tĩnh.

Tôi luôn thấy SignalR là một bổ sung đáng hoan nghênh cho vành đai công cụ của mình để xây dựng các ứng dụng thời gian thực. Tôi cũng muốn bao gồm rất nhiều bản demo SignalR để hiển thị những gì có thể được thực hiện với công nghệ như chỉnh sửa WebGrid hoặc nút Like thời gian thực

Vì vậy, hôm nay, tôi muốn tham gia xây dựng một luồng twitter không đồng bộ, thời gian thực, chạy trên trang web của bạn. Luồng cụ thể này có nghĩa là để lấy các tweet thời gian thực của bạn trên dòng thời gian của bạn và hiển thị chúng khi chúng đến.

Thiết lập

Ban đầu, tôi đã đi với tùy chọn ứng dụng MVC tiêu chuẩn (Tệp -> Dự án mới -> Ứng dụng web ASP.NET -> Mẫu ASP.NET 4.5.2 -> MVC)

Sau khi hoàn thành update-package, tôi đã cài đặt các gói sau:

  • Tín hiệuR ( install-package Microsoft.AspNet.SignalR)
  • TweetInvi ( install-package TweetinviAPI)

Sau khi các gói đó được cài đặt, chúng tôi đã sẵn sàng đặt nền tảng cho luồng twitter của mình.

Để SignalR hoạt động, một app.MapSignalR () được yêu cầu cho tệp Startup.cs trong thư mục gốc của dự án của bạn như được đề cập trong readme.txt khi bạn cài đặt gói SignalR.

Startup.cs

using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(SignalRTwitterDemo.Startup))]
namespace SignalRTwitterDemo
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();

            ConfigureAuth(app);
        }
    }
}

Khi dòng ( app.MapSignalR();) được bao gồm trong Khởi động, chúng ta có thể di chuyển về phía UI.

Chỉ số nhà

Giao diện người dùng không phải là bất cứ điều gì để có hứng thú. Tôi đã loại bỏ các DIV phụ và giữ menu ở trên cùng.

Màn hình có hai nút trên đó: Một để kích hoạt luồng Twitter và một để tắt.

/ Xem / Home / Index.cshtml

@{
    ViewBag.Title = "Home Page";
}

<p>&nbsp;</p>

<button id="firehoseOn" class="btn btn-warning">Turn on the firehose</button>
<button id="firehoseOff" class="btn btn-danger">Turn it off! Turn it off!</button>
<label id="firehoseStatus"></label>

<div class="tweets"></div>

@section scripts
{
    <script src="/Scripts/jquery-2.2.3.min.js" type="text/javascript"></script>
    <script src="/Scripts/jquery.signalR-2.2.0.min.js" type="text/javascript"></script>
    <script src="/signalr/hubs" type="text/javascript"></script>
    <script src="/Scripts/twitterLive.js" type="text/javascript"></script>
}

Tôi cũng đã thêm một "firehoseStatus" để hiển thị trạng thái xem luồng có chạy hay không và div.tweets sẽ chứa tất cả các tweet của chúng tôi xảy ra trong thời gian thực.

Ba tập lệnh là tiêu chuẩn và bắt buộc để SignalR chạy đúng. Tệp thứ tư, twitterLive.js là JavaScript homebrew của riêng chúng tôi.

Chúng tôi sẽ trở lại với điều đó trong một phút. Hiện tại, hãy tập trung vào chức năng phía máy chủ.

Luồng và dữ liệu

Một trong những vấn đề tôi gặp phải với kỹ thuật đặc biệt này là theo dõi luồng twitter và biết cách tắt nó đi.

Vì SignalR không đồng bộ và chúng tôi đã thực hiện các cuộc gọi không đồng bộ tới Twitter, điều này gây ra một chút vấn đề.

Sau khi thực hiện một số nghiên cứu, tôi phát hiện ra rằng có một lớp đồng thời có sẵn và quyết định sử dụng nó để theo dõi dữ liệu Twitter cùng với Mã thông báo hủy.

CancellingTokens là các thông báo truyền đến các hoạt động khác cho nó biết rằng nó sẽ bị hủy.

Vì vậy, chúng ta cần phải chứa dữ liệu trong một loại nào đó.

Hubs \ TwitterTaskData.cs

public class TwitterTaskData
{
    public string Id { get; set; }
    public string Status { get; set; }
    public IOEmbedTweet Tweet { get; set; }
    public CancellationTokenSource CancelToken { get; set; }
}

IOEmbedTweet là một phần thưởng từ TweetInvi. Khi nhận được tweet, TweetInvi tạo thẻ Twitter và gửi HTML dưới dạng IOEmbedTweet. Khi chúng tôi tạo ra nó, chúng tôi chỉ cần gửi nó cho khách hàng và để nó hiển thị nó.

Điều này dẫn chúng ta đến lớp TwitterStream của chúng tôi.

Hubs \ TwitterStream.cs

public static class TwitterStream
{
    private static IUserStream _stream;

    private static readonly IHubContext _context = GlobalHost.ConnectionManager.GetHubContext<TwitterHub>();

    public static async Task StartStream(CancellationToken token)
    {
        // Go to https://apps.twitter.com to get your own tokens.
        Auth.SetUserCredentials("CONSUMER_KEY", "CONSUMER_SECRET", "ACCESS_TOKEN", "ACCESS_TOKEN_SECRET");

        if (_stream == null)
        {
            _stream = Stream.CreateUserStream();

            // Other events can be used. This is just on YOUR twitter feed.
            _stream.TweetCreatedByAnyone += async (sender, args) =>
            {
                if (token.IsCancellationRequested)
                {
                    _stream.StopStream();
                    token.ThrowIfCancellationRequested();
                }

                // let's use the embeded tweet from tweetinvi
                var embedTweet = Tweet.GenerateOEmbedTweet(args.Tweet);

                await _context.Clients.All.updateTweet(embedTweet);
            };

            // If anything changes the state, update the UI.
            _stream.StreamPaused += async (sender, args) => { await _context.Clients.All.updateStatus("Paused."); };
            _stream.StreamResumed += async (sender, args) => { await _context.Clients.All.updateStatus("Streaming..."); };
            _stream.StreamStarted += async (sender, args) => { await _context.Clients.All.updateStatus("Started."); };
            _stream.StreamStopped += async (sender, args) => { await _context.Clients.All.updateStatus("Stopped (event)"); };

            await _stream.StartStreamAsync();
        }
        else
        {
            _stream.ResumeStream();
        }

        await _context.Clients.All.updateStatus("Started.");
    }
}

Khi bắt đầu phương pháp này, bạn sẽ nhận thấy chúng tôi có một trình giữ chỗ cho thông tin đăng nhập của bạn cho Twitter. Đặt thông tin đăng nhập của bạn bằng cách sử dụng mã thông báo từ apps.twitter.com và đặt mã đó vào mã (Không, tôi sẽ không cung cấp cho bạn thông tin của bạn). ;-)

Tiếp theo, chúng tôi thiết lập một sự kiện để nhận một tweet khi được tạo bởi bất kỳ ai. Tuy nhiên, nếu chúng tôi nhận được Hủy bỏ, chúng tôi cần ngừng xử lý ngay lập tức.

Khi chúng tôi nhận được tweet, chúng tôi tạo một Tweet được nhúng và gửi nó đến phương thức của khách hàng, updateTweet.

Chúng tôi cũng muốn người dùng của chúng tôi có trải nghiệm người dùng tốt vì vậy chúng tôi cũng thêm các sự kiện khi một luồng Twitter bị tạm dừng, tiếp tục, bắt đầu hoặc dừng.

Cuối cùng, chúng tôi khởi động một luồng không đồng bộ và gửi trạng thái "Đã bắt đầu". đến máy khách thông qua JavaScript updateStatus.

Làm trung tâm

Các trung tâm là phần quan trọng nhất và cũng dễ dàng nhất một khi mọi thứ được đặt ra.

Tất cả những gì cần thiết cho chức năng này là Đồng thời Từ điển được xác định ở đầu và các phương thức bắt đầu và dừng twitter của chúng tôi.

Trung tâm \ TwitterHub.cs

[HubName("twitterHub")]
public class TwitterHub : Hub
{
    private static ConcurrentDictionary<string, TwitterTaskData> _currentTasks;

    private ConcurrentDictionary<string, TwitterTaskData> CurrentTasks
    {
        get { return _currentTasks ?? (_currentTasks = new ConcurrentDictionary<string, TwitterTaskData>()); }
    }

    public async Task StartTwitterLive()
    {
        var tokenSource = new CancellationTokenSource();

        var taskId = string.Format("T-{0}", Guid.NewGuid());

        CurrentTasks.TryAdd(taskId, new TwitterTaskData
        {
            CancelToken = tokenSource,
            Id = taskId,
            Status = "Started."
        });

        await Clients.Caller.setTaskId(taskId);

        var task = TwitterStream.StartStream(tokenSource.Token);

        await task;
    }

    public async Task StopTwitterLive(string taskId)
    {
        if (CurrentTasks.ContainsKey(taskId))
        {
            CurrentTasks[taskId].CancelToken.Cancel();
        }

        await Clients.Caller.updateStatus("Stopped.");
    }
}

Bạn có thể tự hỏi tại sao chúng tôi gửi taskId cho khách hàng. Điều này là để đảm bảo chúng tôi có một tác vụ phù hợp với luồng Twitter trong trường hợp họ muốn tắt nó.

Cuối cùng, JavaScript

JavaScript SignalR chỉ là một tập hợp các phương thức C # phía máy chủ.

Tập lệnh \ twitterLive.js

$(function () {
     var twitterHub = $.connection.twitterHub;

    twitterHub.client.setTaskId = function (id) {
        $("#firehoseOff").attr("data-id", id);
    }

    twitterHub.client.updateStatus = function (status) {
        $("#firehoseStatus").html(status);
    }

    twitterHub.client.updateTweet = function (tweet) {
        $(tweet.HTML)
            .hide()
            .prependTo(".tweets")
            .fadeIn("slow");
    };

    $("#firehoseOn").on("click", function () {
        twitterHub.server.startTwitterLive();
    });

    $("#firehoseOff").on("click", function () {
        var id = $(this).attr("data-id");
        twitterHub.server.stopTwitterLive(id);
    });

    $.connection.hub.start();

});

Như bạn có thể thấy, setTaskId nhắm vào nút #firehose Offer và đặt id dữ liệu thuộc tính thành taskId.

Chúng tôi cũng đặt updateStatus theo hàm Html.

Ghi nhớ OEmbedTweet? UpdateTweet nhận đối tượng đó và bao gồm một thuộc tính HTML mà chúng ta biến thành đối tượng jQuery, ẩn nó, đưa nó vào div.tweets và làm mờ dần nó.

Nút FirehoseOn gọi phương thức C # startTwitterLive và khởi động luồng Twitter trong khi nút Firehose Offer lấy nhiệm vụ khỏi thẻ của nó và gửi nó đến phương thức C # stopTwitterLive.

Phần kết luận

Hôm nay, tôi đã trình bày một cách để bạn thực hiện các cuộc gọi không đồng bộ từ SignalR để hiển thị luồng Twitter thời gian thực.

Bạn có thể dễ dàng thay đổi mã để tạo một thanh tiến trình, tải lên tệp hoặc thậm chí một tác vụ khác có thể hoạt động ở chế độ nền.

Trong khi bộ đồ mạnh mẽ của tôi không xâu chuỗi, tôi rất vui khi làm việc này để chia sẻ với độc giả của mình.

Tải về kho git tại đây .

Bạn đã theo dõi dự án này? Bạn sẽ làm nó khác đi? Gửi ý kiến ​​của bạn dưới đây. Luôn luôn yêu một cuộc thảo luận tốt.

Hữu ích 4 Chia sẻ Viết bình luận 0
Đã xem 4491