[angularjs]angularjs+signalr的即時同步

angularjs+signalr的即時同步

網路上針對signalr和jquery的範例非常多,angularjs的搭配範例比較少,我現在想做一個模擬一個api讓外部調用的,然後我們電腦就能即時的顯示資料在畫面上,範例雖然簡單,但這種例子其實非常多,比如詢價系統,甚至是不同系統的介接,這邊為了不要複雜化,我想用最簡單的方式,來紀錄一下也幫助本人無可救藥的回憶,未來可以自我回顧,首先我們一樣的就是先模擬做一個資料庫吧,細節我就不多說了,我之前的文章也有寫到如何用code first,以下會是我預設要建立的資料庫欄位

using System;
using System.ComponentModel.DataAnnotations.Schema;

namespace signalrDemo.Models
{
    public class MarketPricer
    {
        public int Id { get; set; }
        public string Bank { get; set; }
        public string UserName { get; set; }
        public int Price { get; set; }
        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public DateTime CreateDate { get; set; }
    }
}

 

接著我在Models裡面建立了DefaultConctext.cs,程式碼如下

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace signalrDemo.Models
{
    public class DefaultContext:DbContext
    {
        public DefaultContext()
            :base("DefaultConnection")
        {
           
        }

        public DbSet<MarketPricer> MarketPricer { get; set; }
    }
}

 

然後接著打開Package Manager Console,然後輸入enable-migrations如下圖

 

image

 

然後輸入add-migration init

 

image

 

這時候會產生一支時間日期_init.cs,打開然後把CreateDate = c.DateTime(nullable: false),改成CreateDate = c.DateTime(nullable: false,defaultValueSql:"GetDate()"),,這一行是要把CreateDate改成預設值是抓現在時間,如下圖

 

image

 

最後則是打下update-database

 

image

 

Signalr部份

 

接著我們必須要在nuget下載signalr,如下圖

 

image

 

再來我們在專案新增一支Startup.cs,程式碼如下

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(signalrDemo.Startup))] //signalrDemo是您的專案名稱

namespace signalrDemo
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

 

接著我再新增一個目錄夾,專門放一些hub的cs檔,命名為signalrHub,然後我再此目錄新增一支檔案叫做GetHub.cs

 

using System.Linq;
using Microsoft.AspNet.SignalR;
using signalrDemo.Models;

namespace signalrDemo
{
    public class GetHub : Hub
    {
        DefaultContext db = new DefaultContext();
        public void GetMarketData()  
        {
            Clients.All.MarketData(db.MarketPricer.ToList()); //此行則是廣播client端去接收
        }
    }
}




 

我把預設的ValuesController.cs改成只有一個Post,因為我想要從web api直接去新增資料,這樣可以給異端去呼叫,如下

 

using Microsoft.AspNet.SignalR;
using signalrDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;

namespace signalrDemo.Controllers
{
    public class ValuesController : ApiController
    {
        DefaultContext db = new DefaultContext();
        IHubContext hub = GlobalHost.ConnectionManager.GetHubContext<GetHub>();  //GetHub是我剛剛新增的GetHub.cs檔
        // POST api/values
        public void Post(MarketPricer emp)
        {
            db.MarketPricer.Add(emp);
            db.SaveChanges();
            hub.Clients.All.MarketData(db.MarketPricer.ToList());  //這行則是又主動呼叫client去接收新資料
        }
    }
} 

 

angularjs部份

 

首先我們必須要在用到的頁面加入一支signalr的js檔,jquery則是必要加入的,我是直接加在_Layout.cshtml裡面,如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body ng-app="app">
    <div class="container body-content">
        @Scripts.Render("~/bundles/jquery")
        <script src="~/Scripts/angular.js"></script>
        <script src="~/Scripts/jquery.signalR-2.2.0.js"></script>
        @Scripts.Render("~/bundles/bootstrap")
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>

    @RenderSection("scripts", required: false)
</body>
</html>

 

接著就是Index.cshtml部份,簡單做一個ng-repeat把資料陳列出來就好,說明我都寫在註解裡面了

<div ng-controller="FirstCtrl">
    <table class="table">
        <tr>
            <th>Bank</th>
            <th>UserName</th>
            <th>Price</th>
            <th>CreateDate</th>
        </tr>
        <tr ng-repeat="item in items">
            <td>{{item.Bank}}</td>
            <td>{{item.UserName}}</td>
            <td>{{item.Price}}</td>
            <td>{{item.CreateDate}}</td>
        </tr>
    </table>
</div>

<script>
    angular.module('app', [])
    .controller('FirstCtrl', function ($scope) {
        var hub = $.hubConnection();  
        var proxy = hub.createHubProxy('GetHub');  //GetHub是伺服器端那支cs檔
        proxy.on('MarketData', function (data) {  //MarketData就是這行 Clients.All.MarketData(db.MarketPricer.ToList());
            $scope.items = data;
            $scope.$apply();
        });
        hub.start().done(function () {
            proxy.invoke('GetMarketData');  //這則是一開始我就要先調用資料,所以去呼叫了GetHub.cs裡面的GetMarketData method
        });
            
    });
</script>

 

然後開啟畫面因為資料庫是空的,預設沒有資料,接著我就假設使用PostMan來發個post,新增一筆資料,我們就可以看到瀏覽器自動收到資料了,如下圖

 

image

image

image

image

 

上面的內容,再請大家多多指教。