国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

SignalR循序漸進(二)泛型Hub

2019-11-17 01:33:22
字體:
供稿:網(wǎng)友

SignalR循序漸進(二)泛型Hub

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

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

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

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。

好,現(xiàn)在需要進行一些分析,怎樣才能讓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的操作方法都在這兒了,全是動態(tài)類型的,這也是為什么在Hub中寫到Clients.All.xxx的時候已經(jīng)是動態(tài)的了,那么運行時,這些操作都是什么類型的呢?試一下:

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.        //        // 參數(shù):         //   method:        //     name of the method to invoke        //        //   args:        //     argumetns to pass to the client        //        // 返回結(jié)果:         //     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來執(zhí)行的。
  2. 如果讓IChatClient通過某種方式和IClientProxy建立起非運行時的聯(lián)系,就能實現(xiàn)強類型了。
  3. 這樣的話,就需要有一個Hub<T>的類,然后把Clients里所有的操作在Hub<T>中重新實現(xiàn)一次。
  4. 然后T又是客戶端的行為接口,因此,需要對Hub<T>進行靜態(tài)擴展,讓IClientProxy的Invoke方法能夠被T的所有方法自動調(diào)用。

核心攻克點找到了,解決了4,就能一路解決1。怎樣才能讓IClientProxy的Invoke自動的被T的所有方法調(diào)用呢?AOP可以!可以用Castle對T進行動態(tài)織入。到這兒可以動手了,先建立一個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執(zhí)行GetClientBehavior方法,然后內(nèi)部進行攔截器裝載,并將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執(zhí)行方法的時候,clientProxy就執(zhí)行Invoke方法,把T的方法名和T的參數(shù)傳入,這就達到了原先動態(tài)調(diào)用客戶端方法傳入?yún)?shù)并執(zhí)行的效果。

然后就是寫一個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已經(jīng)是經(jīng)過AOP的了。最后,把最初的ChatHub改一下:

image

讓ChatHub繼承Hub<T>,T為IChatClient,如圖示,已經(jīng)可以通過Except方法用強類型調(diào)用客戶端方法了。執(zhí)行一下看看:

image

到此,服務(wù)端改造結(jié)束。服務(wù)端已經(jīng)可以接受強類型的客戶端行為。

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

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

轉(zhuǎn)載請注明出處:http://www.survivalescaperooms.com/royding/p/3750412.html


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 潞西市| 南部县| 阜南县| 汪清县| 金堂县| 庆阳市| 成武县| 中阳县| 岳普湖县| 松原市| 中方县| 文山县| 新安县| 沙雅县| 神木县| 镇原县| 芒康县| 宁远县| 益阳市| 西乌珠穆沁旗| 泰兴市| 综艺| 金川县| 桦南县| 灵寿县| 鄂州市| 定兴县| 英吉沙县| 乾安县| 来宾市| 家居| 富蕴县| 剑阁县| 柘城县| 长顺县| 瑞丽市| 丰镇市| 揭西县| 栾城县| 日喀则市| 洪洞县|