亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

SignalR循序漸進(二)泛型Hub

2019-11-17 01:33:22
字體:
來源:轉載
供稿:網友

SignalR循序漸進(二)泛型Hub

接上一篇,文章末尾拋出了2個問題:

  1. 能不能讓客戶端聲明一個強類型的方法列表呢?這樣首先不容易寫錯。
  2. 同樣的,能不能讓服務端聲明一個強類型的方法列表給客戶端調用呢?

如果要讓客戶端的方法以強類型出現在服務端,同樣的,服務端的方法也以強類型出現在客戶端,那就必須聲明類似契約一樣的載體。比如:

public interface IChatClient    {        void broadcast(string name, string message);    }
public interface IChatHub    {        void Send(string name, string message);    }

分別建立ChatClient接口和ChatHub的接口。

public class ChatHub : Hub<IChatClient>{...}

這是最終的目標,一個泛型Hub。

好,現在需要進行一些分析,怎樣才能讓Hub支持泛型。

首先,看一下Hub是如何操作客戶端方法的:

Clients.AllExcept(Context.ConnectionId).broadcast(name, message);

Hub通過Clients來操作所有客戶端的行為。那么這個Clients又是什么類型的呢?

// 摘要:         //     Gets a dynamic object that rePResents all clients connected to this hub (not        //     hub instance).        IHubCallerConnectionContext Clients { get; set; }

通過IHub接口看到,Clients的類型是IHubCallerConnectionContext,點進去看:

// 摘要:     //     Encapsulates all information about an individual SignalR connection for an    //     Microsoft.aspNet.SignalR.Hubs.IHub.    public interface IHubCallerConnectionContext : IHubConnectionContext    {        [Dynamic]        dynamic Caller { get; }        [Dynamic]        dynamic Others { get; }        dynamic OthersInGroup(string groupName);        dynamic OthersInGroups(IList<string> groupNames);    }

IHubCallerConnectionContext又繼承IHubConnectionContext,再點進去看:

// 摘要:     //     Encapsulates all information about a SignalR connection for an Microsoft.AspNet.SignalR.Hubs.IHub.    public interface IHubConnectionContext    {        [Dynamic]        dynamic All { get; }        dynamic AllExcept(params string[] excludeConnectionIds);        dynamic Client(string connectionId);        dynamic Clients(IList<string> connectionIds);        dynamic Group(string groupName, params string[] excludeConnectionIds);        dynamic Groups(IList<string> groupNames, params string[] excludeConnectionIds);        dynamic User(string userId);    }

一目了然,所有Clients的操作方法都在這兒了,全是動態類型的,這也是為什么在Hub中寫到Clients.All.xxx的時候已經是動態的了,那么運行時,這些操作都是什么類型的呢?試一下:

image

運行時,Clients的操作返回的是ClientProxy類型,從代碼中扒出來:

public class ClientProxy : DynamicObject, IClientProxy    {        public ClientProxy(IConnection connection, IHubPipelineInvoker invoker, string hubName, IList<string> exclude);        public Task Invoke(string method, params object[] args);        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result);    }
// 摘要:     //     A server side proxy for the client side hub.    public interface IClientProxy    {        // 摘要:         //     Invokes a method on the connection(s) represented by the Microsoft.AspNet.SignalR.Hubs.IClientProxy        //     instance.        //        // 參數:         //   method:        //     name of the method to invoke        //        //   args:        //     argumetns to pass to the client        //        // 返回結果:         //     A task that represents when the data has been sent to the client.        Task Invoke(string method, params object[] args);    }}

可以看到,運行時如果以IClientProxy注入,就一個Invoke方法。

好,挖到這兒,可以有一些思路了。

  1. Clients所有的操作最終都是通過IClientProxy的Invoke來執行的。
  2. 如果讓IChatClient通過某種方式和IClientProxy建立起非運行時的聯系,就能實現強類型了。
  3. 這樣的話,就需要有一個Hub<T>的類,然后把Clients里所有的操作在Hub<T>中重新實現一次。
  4. 然后T又是客戶端的行為接口,因此,需要對Hub<T>進行靜態擴展,讓IClientProxy的Invoke方法能夠被T的所有方法自動調用。

核心攻克點找到了,解決了4,就能一路解決1。怎樣才能讓IClientProxy的Invoke自動的被T的所有方法調用呢?AOP可以!可以用Castle對T進行動態織入。到這兒可以動手了,先建立一個Hub擴展類:

public static class HubExtensions    {        static readonly ProxyGenerator generator = new ProxyGenerator();        public static T GetClientBehavior<T>(this IClientProxy clientProxy) where T : class        {            return (T)generator.CreateInterfaceProxyWithoutTarget<T>(new ClientBehaviorInterceptor(clientProxy));        }    }

讓所有的IClientProxy執行GetClientBehavior方法,然后內部進行攔截器裝載,并將IClientProxy塞進攔截器。

public class ClientBehaviorInterceptor:IInterceptor    {        public ClientBehaviorInterceptor(IClientProxy clientProxy)        {            this.clientProxy = clientProxy;        }        IClientProxy clientProxy;        public void Intercept(IInvocation invocation)        {            clientProxy.Invoke(invocation.Method.Name, invocation.Arguments);        }    }

攔截器中,每當T執行方法的時候,clientProxy就執行Invoke方法,把T的方法名和T的參數傳入,這就達到了原先動態調用客戶端方法傳入參數并執行的效果。

然后就是寫一個Hub<T>了。

public abstract class Hub<T> : Hub where T : class    {        protected T All { get { return (Clients.All as IClientProxy).GetClientBehavior<T>(); } }        protected T Any(params string[] connectionIds)        {            return (Clients.Clients(connectionIds) as IClientProxy).GetClientBehavior<T>();        }        protected T Except(params string[] connectionIds)        {            return (Clients.AllExcept(connectionIds) as IClientProxy).GetClientBehavior<T>();        }        protected T Client(string connectionId)        {            return (Clients.Client(connectionId) as IClientProxy).GetClientBehavior<T>();        }        protected T Caller { get { return (Clients.Caller as IClientProxy).GetClientBehavior<T>(); } }    }

把Clients中所有的操作都在這兒寫一遍,例子中就寫了5個。通過剛才的擴展方法,返回的T已經是經過AOP的了。最后,把最初的ChatHub改一下:

image

讓ChatHub繼承Hub<T>,T為IChatClient,如圖示,已經可以通過Except方法用強類型調用客戶端方法了。執行一下看看:

image

到此,服務端改造結束。服務端已經可以接受強類型的客戶端行為。

下一篇將對客戶端部分進行強類型改造。

最后附上一個基于SignalR的聊天室玩具,綠色無毒:http://www.royarea.cn/chatroom

轉載請注明出處:http://www.49028c.com/royding/p/3750412.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久久久久久久av| 久久免费少妇高潮久久精品99| 亚洲iv一区二区三区| 国产精品精品久久久久久| 国产欧美一区二区| 久久精品国产欧美亚洲人人爽| 亚洲精品视频免费| 精品呦交小u女在线| 欧美日韩在线观看视频| 国产精品视频不卡| 国产精品电影网站| 亚洲男女自偷自拍图片另类| 亚洲激情小视频| 韩国精品美女www爽爽爽视频| 欧美国产日韩在线| 色悠久久久久综合先锋影音下载| 都市激情亚洲色图| 97精品国产97久久久久久免费| 欧美日韩成人在线观看| 国产日韩欧美91| 日韩在线视频观看正片免费网站| 中文字幕在线亚洲| 欧美日韩国产成人高清视频| 午夜精品蜜臀一区二区三区免费| 亚洲成人性视频| 黑人巨大精品欧美一区二区三区| 国产午夜精品全部视频播放| 亚洲电影免费观看| 欧美亚洲在线视频| 668精品在线视频| 亚洲精品综合精品自拍| 精品久久久香蕉免费精品视频| 久久精品成人欧美大片| 国产精品一区二区3区| 日韩视频第一页| 久久人人爽人人爽人人片av高清| 97视频在线观看免费| 欧美日韩第一页| 中文字幕亚洲字幕| 欧美成人精品一区二区三区| 国产精品中文字幕在线观看| 欧美成人三级视频网站| 亚洲国产毛片完整版| 最近2019中文免费高清视频观看www99| 国产精品视频一区国模私拍| 欧美最顶级丰满的aⅴ艳星| 亚洲a在线观看| 日韩一二三在线视频播| 96国产粉嫩美女| 久久夜色精品国产| 97久久超碰福利国产精品…| 欧美精品激情blacked18| 欧美亚州一区二区三区| 亚洲精品国产欧美| 久久伊人精品天天| 9.1国产丝袜在线观看| 91老司机在线| 国产高清视频一区三区| 在线不卡国产精品| 亚洲激情国产精品| 欧美精品免费在线| 欧美精品制服第一页| 91美女高潮出水| 国产精品福利网站| 欧美激情精品久久久| 久久这里只有精品视频首页| 丝袜美腿亚洲一区二区| 亚洲高清免费观看高清完整版| 国产一区视频在线播放| 色婷婷久久一区二区| 亚洲成人亚洲激情| 欧美日韩精品二区| 一本色道久久综合狠狠躁篇怎么玩| 日韩av毛片网| 欧美激情按摩在线| 成人网页在线免费观看| 精品亚洲精品福利线在观看| 国产精品美乳在线观看| 国产精品爽爽爽爽爽爽在线观看| 亚洲iv一区二区三区| 亚洲桃花岛网站| 精品成人久久av| 国产精品视频永久免费播放| 国产精品久久久久久久久久尿| 亚洲综合色av| 国内精品久久久久久久久| 亚洲精品999| 欧美视频在线看| 欧美日韩国产精品一区二区不卡中文| 亚洲日本成人女熟在线观看| 亚洲国产精品va在看黑人| 亚洲精品国产精品自产a区红杏吧| 青青草国产精品一区二区| 国内免费久久久久久久久久久| 欧美在线视频播放| 欧美午夜激情小视频| 亚洲午夜精品久久久久久性色| 国产精品国产福利国产秒拍| 国产精品九九久久久久久久| 国产精品久久久久91| 日本午夜精品理论片a级appf发布| 中文字幕最新精品| 色噜噜狠狠狠综合曰曰曰88av| 国产精品美女呻吟| 日韩网站免费观看| 欧美成aaa人片在线观看蜜臀| 55夜色66夜色国产精品视频| 欧美日韩爱爱视频| 国产suv精品一区二区三区88区| 2023亚洲男人天堂| 国产精品久久久久久久久久三级| 亚洲欧洲日产国产网站| 欧美极品美女电影一区| 久久精品人人爽| 97超碰国产精品女人人人爽| 久久亚洲成人精品| 欧美大人香蕉在线| 欧美性生交大片免网| 黑人与娇小精品av专区| 亚洲欧美精品一区二区| 日本精品久久中文字幕佐佐木| 国产精品香蕉在线观看| 欧美丰满少妇xxxxx做受| 亚洲免费一级电影| 青青青国产精品一区二区| 久久免费在线观看| 国产丝袜一区二区三区| 亚洲欧美日韩国产中文专区| 亚洲va久久久噜噜噜| 亚洲视频欧洲视频| 亚洲免费电影在线观看| 亚洲天堂网站在线观看视频| 欧美日韩国产色视频| 欧美国产日产韩国视频| 久久伊人免费视频| 欧美激情2020午夜免费观看| 亚洲精品大尺度| 色中色综合影院手机版在线观看| 成人久久18免费网站图片| 亚洲自拍欧美色图| 欧美日韩一区二区三区在线免费观看| 亚洲欧美日韩高清| 成人激情视频免费在线| 岛国视频午夜一区免费在线观看| 亚洲日本中文字幕免费在线不卡| 97视频国产在线| 亚洲一区二区三区毛片| 中文字幕久久久av一区| 欧美大成色www永久网站婷| 国产精品美女免费| 欧美性猛交xxxx黑人| 精品国产美女在线| 国产精品稀缺呦系列在线| 亚洲91精品在线观看| 欧美激情精品久久久久久黑人| 国产精品com| 色狠狠av一区二区三区香蕉蜜桃| 日韩va亚洲va欧洲va国产| 成人性生交xxxxx网站| 成人伊人精品色xxxx视频| 色悠悠久久88| 96精品视频在线| 欧美激情成人在线视频| 日韩av色在线|