2015年3月31日 星期二

如何在Codova 上呼叫SignalR


步驟1:安裝SignalR.Client 端套件


















步驟2: 呼叫Server 端的/Scripts/jquery.signalR-2.2.0.js jquery.signalR-2.2.0.jssignalr /hubs

    <script src="scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="http://192.168.1.63/signalr/Scripts/jquery.signalR-2.2.0.js"></script>
    <script type="text/javascript" src="http://192.168.1.63/signalr/signalr/hubs"></script>   
    <link href="Content/Chat.css" rel="stylesheet" />
    <link href="Content/bootstrap.css" rel="stylesheet" />
    <script src="scripts/bootstrap.min.js"></script>
    <script src="scripts/angular.min.js"></script>

注意需事先架設Server 端的ChatHub 並放置IIS上,才能透過手持裝置呼叫Server端的ChatHub ,如不懂ChatHub的朋友們請看Angular 搭配 SignalR的文章 有詳細說明

步驟3: server端的SignalrR 設定允許JSONP
[assembly: OwinStartup(typeof(singalR2.Startup))]
namespace singalR2
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR(new HubConfiguration{ EnableJSONP=true});
        }
    }
}

步驟4: Client 端的呼叫Server端的ChatHub的方式
<script type="text/javascript">
        var app = angular.module("chatModel", []);
        app.controller("chatController", function ($scope) {
            $scope.allMessage = []; //初始化           
            $.connection.hub.url = "http://192.168.1.63/signalr/signalr";
            var proxy = $.connection.chatHub;
            $scope.name = prompt("請輸入您的名字","");
            $.connection.hub.start({ jsonp: true }).done(function () {
                $scope.send = function () {
                    proxy.server.send($scope.name, $scope.message); //廣播給全部的人
                };
            });
            proxy.client.addNewMessageToPage = function (name, message) {
                $scope.allMessage.push({
                    "name": name,
                    "message": message,
                    "time": new Date()
                });
                $scope.$apply(); //更新畫面
            };
        });
    </script>

實驗結果,透過codova將程式成功部署到手持裝置(Android)上,ios目前沒有實機測試過,透過SignalR可以讓手持裝置直接發送訊息給大家(包括桌機的瀏覽器),讓我們Web的工程師可以開發出更多互動式的APP喔。


參考文獻:



2015年3月22日 星期日

如何設定Web API的 Cross Domain

某些情況Web API 需放在獨立的伺服器或不同的網域位置,當其他web應用程式要調用這web API時,就會發生無法讀取該網址(跨源問題),所以需特別針對這隻Web API 做特別處理,讓它允許跨源存取。

NutGet安裝  Microsoft.AspNet.WebApi.Cors

    開啟檔案App_Start/webApiConfig.cs ,並修改webApiConfig.Register 的函式
public static void Register(HttpConfiguration config)
        {         
            config.MapHttpAttributeRoutes();
            config.EnableCors();   // 加上此行,就允許跨源存取
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new
                {
                    id = RouteParameter.Optional
                }
            );
        }

    在apiController 加上enable cros的設定
public class apiPatientController : ApiController
    {
        // GET api/<controller>
         [EnableCors(          
           origins: "http://localhost,http://localhost:19532",//設定允許哪些來源網址,允許存取此web API
            headers: "accept,content-type,origin",
            methods: "get,post")]
        public IEnumerable<entityPatient> Get()
        {
            PublicInfo.CheckClientSide();
            entityPatient tempPatient = new entityPatient();
            return tempPatient.getAllPatients();
        }
    }

    在client端的網頁http://localhost:19532/HtmlPage1.html,呼叫web API,就能成功取回資料,Angular 取得跨源的web API,需事先設定useXDomain=true 


    var app = angular.module("patientModule", []);

    app.config(['$httpProvider', function ($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];

    }]);
  app.controller("patientController", function ($scope, $http) {
        $http.get('http://localhost:11586/api/apiPatient').success(function (data, status, header, config) {           
            $scope.patients = data;
        }).error(function (data, status, headers, config) {
            alert("web api 網址失敗!");
        })



























2015年3月12日 星期四

Angular 搭配 SignalR


步驟1:安裝SignalR相關套件



自動安裝:  透過NutGet 安裝SignalR套件 
手動安裝:  install-package Microsoft.AspNet.SignalR

步驟2: 建立SignalR Hub類別
















ChatHub.cs
 public class ChatHub : Hub
    {     
        public void send(string name, string message)
        {           
           Clients.All.broadcastMessage(name, message);
        }
    }
   
    請切記如果server端使用broadcastMessage 方式接收訊息,前端也要用同樣的方  式broadcastMessage 去傳送資訊

步驟3: 建立Startup.cs
[assembly: OwinStartup(typeof(singalR2.Startup))]
namespace singalR2
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR();
        }
    }
}

    如果您是使用最新版Visual Studio 2015版本,Startup.cs 會自動建立,就不需再自行新增Startup的類別檔。
Chat.html
<body ng-app="chatModel"<!--angular 應用程式-->
    <br />
    <div class="container">
        <div class="row" ng-controller="chatController">
            <div class="col-md-5">
                <div class="panel panel-primary">
                    <div class="panel-heading" id="accordion">
                        <span class="glyphicon glyphicon-comment"></span> Chat
                        <div class="btn-group pull-right">
                            <a type="button" class="btn btn-default btn-xs" data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
                                <span class="glyphicon glyphicon-chevron-down"></span>
                            </a>
                        </div>
                    </div>
                    <div class="panel-collapse collapse" id="collapseOne">
                        <div class="panel-body">
                            <ul class="chat">
<!--  ng-class 條件CSS 可依不同條件顯示不同樣式 -->
<!--  ng-repeat 自動從列舉變數實作出範本的資料列 -->
<!--  ng-if 符合條件判時,才顯示該html段落 -->
<!--  ng-click 按下button 事件觸發 -->

                                <li  ng-class="{'left clearfix': messageObj.name!=name, 'right clearfix': messageObj.name ==name}" ng-repeat="messageObj in allMessage">
                                    <span ng-class="{'chat-img pull-left': messageObj.name!=name,'chat-img pull-right': messageObj.name==name}">
                                        <img src="http://placehold.it/50/FA6F57/fff&text=ME" alt="User Avatar" class="img-circle" ng-if="messageObj.name ==name" />
                                        <img src="http://placehold.it/50/55C1E7/fff&text=U" alt="User Avatar" class="img-circle"  ng-if="messageObj.name!=name" />
                                    </span>
                                    <div class="chat-body clearfix">
                                        <div class="header" ng-if="messageObj.name==name">
                                            <strong class="primary-font">{{messageObj.name}}</strong> <small class="pull-right text-muted">
                                                <span class="glyphicon glyphicon-time"></span>{{messageObj.time}}
                                            </small>
                                        </div>
                                        <div class="header" ng-if="messageObj.name!=name">
                                            <small class=" text-muted"><span class="glyphicon glyphicon-time"></span>{{messageObj.time}}</small>
                                            <strong class="pull-right primary-font">{{messageObj.name}}</strong>
                                        </div>                                    
                                        <p>
                                            {{messageObj.message}}
                                        </p>
                                    </div>
                                </li>
                            </ul>
                        </div>
                        <div class="panel-footer">
                            <div class="input-group">
                                <input type="hidden" ng-model="name" />
                                <input type="hidden" ng-model="group" />
                                <input id="btn-input" type="text" class="form-control input-sm" placeholder="Type your message here..." ng-model="message" />
                                <span class="input-group-btn">
                                    <button class="btn btn-warning btn-sm" id="btn-chat" ng-click="send()">
                                        Send
                                    </button>
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script src="Scripts/jquery-1.10.2.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.0.js"></script>
    <script src="signalr/hubs"></script> <!-- signalr/hubs 是不存在的檔案,但會自動產生 -->
    <script src="Scripts/angular.min.js"></script>   
    <script src="Scripts/bootstrap.min.js"></script>
    <link href="Content/Chat.css" rel="stylesheet" />
    <link href="Content/bootstrap.css" rel="stylesheet" /></body>

目前範本是使用bootsnipp 提供的範本,直接套用Angular 語法更加方便實現互動式的聊天室, 許多的css特效早期用JQuery語法較傳統,維護上有些不易,但引用angular 語法,特效的處理簡化不少了,例如ng-if, ng-class 就可以將條件判斷用那種CSS ,多麼棒的寫法

注意事項:<script src="signalr/hubs"> 是不存在的檔案,所以很多人忘了加上此script,它會編譯時自動產生

Script 檔案
  <script type="text/javascript">
        var app = angular.module("chatModel", []);
        app.controller("chatController", function ($scope) {
$scope.name = prompt("請輸入您的名字","");
            $scope.allMessage = []; //初始化
            var proxy = $.connection.chatHub;
//建立hub的連線
            $.connection.hub.start().done(function () {
//按下send
                $scope.send = function () {
    // 傳送訊息到server
                    proxy.server.send($scope.name, $scope.message);                   
                };
            });

            proxy.client.broadcastMessage = function (name, message) {
//client 取得來自Server 端的資料後,並逐一加到 $scope.allMessage
                $scope.allMessage.push({
                    "name": name,
                    "message": message,
                    "time": new Date()
                });
                $scope.$apply(); //更新畫面
            };
        });
    </script>

多個網頁連線到此網頁,都會即時分享訊息












SignalR發送單一群組
ChatHub.cs
//加入群組
public void Join(string groupName)
{
   Groups.Add(Context.ConnectionId, groupName);
}
//群組發送
public void groupSend(string group, string message)
{
    //如果發送對象是群組時,只需傳遞一個參數時,client 端接收時,也只會有一個參數
    Clients.Group(group).addNewMessageToPage(message);
}

Script 檔案
<script type="text/javascript">
        var app = angular.module("chatModel", []);
        app.controller("chatController", function ($scope) {
            $scope.allMessage = []; //初始化
            var proxy = $.connection.chatHub;           
            $scope.group = prompt("請輸入您的群組", "");
            $scope.name = prompt("請輸入您的名字","");
            $.connection.hub.start().done(function () {
                //先建立群組
                proxy.server.join($scope.group);
                $scope.send = function () {
                    proxy.server.groupSend($scope.group, $scope.message);
                };
            });

            proxy.client.addNewMessageToPage = function (message) {
                $scope.allMessage.push({
                    "message": message,
                    "time": new Date()
                });
                $scope.$apply(); //更新畫面
            };           
        });
    </script>
 標示 : 只需更改的地方

注意無論ChatHub函式名稱開頭是大寫或小寫,javaScript呼叫ChatHub 的函式,均以小寫開發開頭,例如 Join (雖然大寫),但client端呼叫時,仍需呼叫join($scope.group) 函式。


參考文獻