Reflect_Proxy.cs 14.4 KB
Newer Older
潘栩锋's avatar
潘栩锋 committed
1 2 3 4 5 6 7 8 9 10 11 12 13
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.ServiceModel.Security;
using System.Text;
using System.Threading.Tasks;

namespace FObjBase.Reflect
{
潘栩锋's avatar
潘栩锋 committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
    /// <summary>
    /// obj 服务代理;
    /// 1.如果代理的对象为 INotifyPropertyChanged, 对象内的 property 改变,能推送给客户端( [JsonIgnore] 除外);
    /// 2.代理的对象不为INotifyPropertyChanged, 但 对象内的 property 
    ///     a.是 [PropertyPush], 
    ///     b.且是 INotifyPropertyChanged, 
    ///     c.且 只能是get,不能有set,
    /// 那这个 property 内的 子property 改变,也会推送给 客户端 且 子property 是 [PropertyPush],会继续向下全部注册 PropertyChanged,
    /// 也推送给 客户端;
    /// 3. 客户端 可以通过 Call(.....) 调用 服务 的function,  function返回的内容,需要通过[Call(...)] 定义; 且function 必须是
    /// void function(object param1, object param2,object paramN, AsyncCBHandler asyncDelegate, object asyncContext);
    /// 必须有参数 AsyncCBHandler asyncDelegate, object asyncContext, 名字不能改。 前面的 param1~paramN, 多少个都行
    /// 4. 服务中的event, 通过 [Push(...)] 可以推送给客户端, 但event 只能是 EventHandler
    /// [Push(typeof(BulkDBTempFrameChangedEventArgs))]
    ///  public event EventHandler TempFrameChanged;
    ///  
    /// </summary>
潘栩锋's avatar
潘栩锋 committed
31 32
    public class Reflect_Proxy : FObj
    {
33 34 35 36
        #region Core
        /// <summary>
        /// 对象的接口类型
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
37
        Type interfaceType;
38 39 40
        /// <summary>
        /// 代理对象
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
41
        object obj;
42 43 44
        /// <summary>
        /// 忽略设置
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
45
        public bool ignoreSet = false;
46 47 48
        /// <summary>
        /// 对象的全部event
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
49
        List<AnyEvent> anyEvents = new List<AnyEvent>();
50 51 52 53 54 55 56
        /// <summary>
        /// [PropertyPush] 标签树 
        /// </summary>
        SubPropertyNode rootNode;
        /// <summary>
        /// interfaceType 及其父类 的全部属性
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
57
        List<string> properties = new List<string>();
58 59
        #endregion

潘栩锋's avatar
潘栩锋 committed
60 61 62 63

        public Reflect_Proxy(int objsys_idx, UInt32 id, Type interfaceType, object obj) : base(objsys_idx)
        {
            ID = id;
64 65
            Init(interfaceType, obj);
        }
潘栩锋's avatar
潘栩锋 committed
66

67 68 69
        #region Core
        public void Init(Type interfaceType, object obj)
        {
潘栩锋's avatar
潘栩锋 committed
70 71 72
            this.interfaceType = interfaceType;
            this.obj = obj;

73 74 75 76 77 78
            rootNode = new SubPropertyNode
            {
                Obj = obj,
                InterfaceType = interfaceType,
                SubPropertyChanged = Sub_PropertyChanged
            };
潘栩锋's avatar
潘栩锋 committed
79 80

            //注册 obj 的PropertyChanged 事件,获取 interfaceType 全部属性名称,包括它的父类的全部属性名称
潘栩锋's avatar
潘栩锋 committed
81 82 83
            InitPropertyChanged();

            //处理[PropertyPush]
84
            COMMON.InitPropertyPush(rootNode);
潘栩锋's avatar
潘栩锋 committed
85 86 87 88

            //处理[Push]
            InitEventPush();
        }
89
        void InitPropertyChanged()
潘栩锋's avatar
潘栩锋 committed
90 91 92 93 94
        {
            if (!typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
                return;

            //继承了INotifyPropertyChanged
95
            ((INotifyPropertyChanged)(this.obj)).PropertyChanged += rootNode.PropertyChanged;
潘栩锋's avatar
潘栩锋 committed
96

97 98 99 100
            var propertyInfos = COMMON.GetAllPropertyInfos(this.interfaceType);//获取全部属性, 包括父类的属性

            foreach (var propertyInfo in propertyInfos)
            {
潘栩锋's avatar
潘栩锋 committed
101 102 103 104

                if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
                    continue;//这个不需要推送

105
                if (properties.Contains(propertyInfo.Name))
潘栩锋's avatar
潘栩锋 committed
106 107 108 109
                    continue;
                properties.Add(propertyInfo.Name);
            }
        }
潘栩锋's avatar
潘栩锋 committed
110

111
        void InitEventPush()
潘栩锋's avatar
潘栩锋 committed
112 113 114 115 116 117 118 119
        {
            var interfaceTypes = new List<Type>();

            interfaceTypes.Add(this.interfaceType);
            interfaceTypes.AddRange(this.interfaceType.GetInterfaces());


            var eventInfos = new List<EventInfo>();
120 121
            foreach (var ifaceType in interfaceTypes)
            {
潘栩锋's avatar
潘栩锋 committed
122 123
                eventInfos.AddRange(ifaceType.GetEvents());
            }
124

潘栩锋's avatar
潘栩锋 committed
125 126 127 128 129 130 131 132 133 134 135 136
            foreach (var eventInfo in eventInfos)
            {
                var pushAttribute = eventInfo.GetCustomAttribute<PushAttribute>();
                if (pushAttribute == null)
                    continue;

                if (anyEvents.Any(ae => ae.eventName == eventInfo.Name))
                    continue;//已经添加了

                var anyEvent = new AnyEvent()
                {
                    eventName = eventInfo.Name,
137
                    PushObjInfoEx = (rd) => reponse_PushObjInfoEx(rd, true)
潘栩锋's avatar
潘栩锋 committed
138 139 140 141 142 143 144
                };
                //这个事件需要推送
                eventInfo.AddEventHandler(obj, anyEvent.eventHandler);
                anyEvents.Add(anyEvent);

            }
        }
145 146 147 148 149
        void Sub_PropertyChanged(SubPropertyNode node, PropertyChangedEventArgs e)
        {
            //if (ignoreSet)//从服务器接收的数据,不用再推送给服务器
            //    return;
            var type = node.Obj.GetType();
潘栩锋's avatar
潘栩锋 committed
150

151 152 153
            var propertyInfo = type.GetProperty(e.PropertyName);
            if (propertyInfo == null)
                return;//获取失败!!!
潘栩锋's avatar
潘栩锋 committed
154

155 156
            if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() != null)
                return;//这个不需要推送
潘栩锋's avatar
潘栩锋 committed
157

158 159 160 161 162 163
            var v = propertyInfo.GetValue(node.Obj);
            var jObject = new JObject();
            if (v == null)
                jObject.Add(propertyInfo.Name, null);
            else
                jObject.Add(propertyInfo.Name, JToken.FromObject(v));
潘栩锋's avatar
潘栩锋 committed
164

165
            var rData = new Reflect_OBJ_INTERFACE.ReflectData
潘栩锋's avatar
潘栩锋 committed
166
            {
167 168 169 170
                name = COMMON.GetNodePath(node),
                data = jObject
            };
            reponse_PushObjInfoEx(rData, false);
潘栩锋's avatar
潘栩锋 committed
171 172
        }

173
        Reflect_OBJ_INTERFACE.ReflectData request_CALL_GetAllProperties()
潘栩锋's avatar
潘栩锋 committed
174
        {
175 176 177 178 179 180

            var jObject = new JObject();

            var type = obj.GetType();

            foreach (var propertyName in properties)
潘栩锋's avatar
潘栩锋 committed
181
            {
182 183 184 185 186 187
                var propertyInfo = type.GetProperty(propertyName);
                var v = propertyInfo.GetValue(obj);
                if (v == null)
                    jObject.Add(propertyInfo.Name, null);
                else
                    jObject.Add(propertyInfo.Name, JToken.FromObject(v));
潘栩锋's avatar
潘栩锋 committed
188 189
            }

190 191 192 193 194
            var rData = new Reflect_OBJ_INTERFACE.ReflectData
            {
                data = jObject
            };
            return rData;
潘栩锋's avatar
潘栩锋 committed
195 196
        }

197
        void request_CALL_SetProperty(Reflect_OBJ_INTERFACE.ReflectData rData)
潘栩锋's avatar
潘栩锋 committed
198
        {
199
            //ignoreSet = true;
潘栩锋's avatar
潘栩锋 committed
200

201 202 203 204 205 206
            //sub property
            var node = COMMON.FindNode(rootNode, rData.name);
            if (node == null)
            {
                //异常
                //客户端乱发过来
潘栩锋's avatar
潘栩锋 committed
207
                return;
208
            }
潘栩锋's avatar
潘栩锋 committed
209

210 211
            string json = rData.data.ToString();
            JsonConvert.PopulateObject(json, node.Obj);
潘栩锋's avatar
潘栩锋 committed
212

213
            //ignoreSet = false;
潘栩锋's avatar
潘栩锋 committed
214 215
        }

216
        void request_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
潘栩锋's avatar
潘栩锋 committed
217
        {
218 219 220 221 222 223 224
            var type = obj.GetType();
            var paramNames_req = rData.data.Children().OfType<JProperty>().Select(p => p.Name);
            MethodInfo methodInfo = GetMethodInfo(type, rData.name, paramNames_req);
            if (methodInfo == null)
            {
                //不能找到,
                throw new Exception($"程序写错了, 不能找到 rData.name={rData.name} 或者 参数名称不对,没法完全匹配");
潘栩锋's avatar
潘栩锋 committed
225 226
            }

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
            var parameterInfos = methodInfo.GetParameters();
            object[] parameters = new object[parameterInfos.Count()];
            for (int i = 0; i < parameters.Count(); i++)
            {
                var ptype = parameterInfos[i].ParameterType;
                var pname = parameterInfos[i].Name;
                if (string.Compare(pname, Reflect_OBJ_INTERFACE.asyncDelegate, true) == 0)
                {
                    parameters[i] = new AsyncCBHandler(asyncDelegate);
                }
                else if (string.Compare(pname, Reflect_OBJ_INTERFACE.asyncContext, true) == 0)
                {
                    cc.methodName = rData.name;
                    parameters[i] = cc;
                }
                else
                {
                    parameters[i] = rData.data[pname].ToObject(ptype);
                }
            }
            methodInfo.Invoke(obj, parameters);
潘栩锋's avatar
潘栩锋 committed
248 249
        }

250
        void asyncDelegate(object asyncContext, object retData)
潘栩锋's avatar
潘栩锋 committed
251
        {
252 253 254
            var cc = (CC)asyncContext;

            var rData = new Reflect_OBJ_INTERFACE.ReflectData()
潘栩锋's avatar
潘栩锋 committed
255
            {
256 257 258
                name = cc.methodName,
                data = retData == null ? null : JToken.FromObject(retData)
            };
潘栩锋's avatar
潘栩锋 committed
259

260
            reponse_CALL_MethodInvoke(rData, cc);
潘栩锋's avatar
潘栩锋 committed
261
        }
262 263

        MethodInfo GetMethodInfo(Type type, string name, IEnumerable<string> parameterNames)
264
        {
265

266
            var methodInfos = from mi in type.GetMethods() where mi.Name == name select mi;
267
            if (methodInfos.Count() == 0)
268 269 270 271 272 273 274 275
                return null;
            if (methodInfos.Count() == 1)
                return methodInfos.First();

            //必须完全匹配
            foreach (var methodInfo in methodInfos)
            {
                var parameterInfos = methodInfo.GetParameters();
276 277 278
                //全部参数名称
                var names = parameterInfos.Select(pi => pi.Name).ToList();
                //删除掉 asyncDelegate,asyncContext
279 280
                names.Remove(Reflect_OBJ_INTERFACE.asyncDelegate);
                names.Remove(Reflect_OBJ_INTERFACE.asyncContext);
281

282 283
                var names_req = parameterNames;

284 285 286 287 288 289 290 291 292 293 294
                if (names.Count() != names_req.Count())
                    continue;//数量不一致,肯定不同

                var sames = names_req.Intersect(names);

                if (sames.Count() != names_req.Count())
                    continue;// names 与 names_req 的交集数量与names_req不一样,肯定不同

                //就是它
                return methodInfo;

295 296 297
            }
            return null;
        }
298 299

        public void Dispose()
潘栩锋's avatar
潘栩锋 committed
300
        {
301
            if (typeof(INotifyPropertyChanged).IsAssignableFrom(interfaceType))
潘栩锋's avatar
潘栩锋 committed
302
            {
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
                //继承了INotifyPropertyChanged
                ((INotifyPropertyChanged)(this.obj)).PropertyChanged -= rootNode.PropertyChanged;
            }

            //释放subProperties
            COMMON.NodeDispose(rootNode);
        }
        #endregion


        void reponse_PushObjInfoEx(Reflect_OBJ_INTERFACE.ReflectData rData, bool isEvent)
        {
            //数据推送!!!
            //再嵌套
            var pkgName = isEvent ? Reflect_OBJ_INTERFACE.PUSH_Event : Reflect_OBJ_INTERFACE.PUSH_PropertyChanged;
潘栩锋's avatar
潘栩锋 committed
318

319 320 321 322 323 324 325 326 327
            string json = JsonConvert.SerializeObject(rData);

            CurrObjSys.PushObjInfoEx(this,
                pkgName,
                Misc.Converter.StringToBytes(json));
        }

        void reponse_CALL_MethodInvoke(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
        {
潘栩锋's avatar
潘栩锋 committed
328 329
            string json = JsonConvert.SerializeObject(rData);
            CurrObjSys.PushCallFunctionEx(
330
                cc.from, cc.srcid, ID, cc.magic,
潘栩锋's avatar
潘栩锋 committed
331 332 333
                Reflect_OBJ_INTERFACE.CALL_MethodInvoke,
                Misc.Converter.StringToBytes(json));
        }
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376

        void reponse_CALL_GetAllProperties(Reflect_OBJ_INTERFACE.ReflectData rData, CC cc)
        {
            string json = JsonConvert.SerializeObject(rData);

            CurrObjSys.PushCallFunctionEx(
                cc.from, cc.srcid, ID, cc.magic, 
                Reflect_OBJ_INTERFACE.CALL_GetAllProperties, 
                Misc.Converter.StringToBytes(json));
        }

        public override void CallFunction(IFConn from, uint srcid, uint magic, ushort funcid, byte[] infodata)
        {
            switch (funcid)
            {
                case Reflect_OBJ_INTERFACE.CALL_GetAllProperties:
                    {
                        var rData = request_CALL_GetAllProperties();

                        reponse_CALL_GetAllProperties(rData, new CC() {  from = from, srcid = srcid, magic = magic});
                    }
                    break;
                
                case Reflect_OBJ_INTERFACE.CALL_SetProperty:
                    {
                        string json = Misc.Converter.BytesToString(infodata);
                        var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);

                        request_CALL_SetProperty(rData);
                    }
                    break;

                case Reflect_OBJ_INTERFACE.CALL_MethodInvoke:
                    {
                        string json = Misc.Converter.BytesToString(infodata);
                        var rData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.ReflectData>(json);

                        request_CALL_MethodInvoke(rData, new CC() { from = from, srcid = srcid, magic = magic });
                    }
                    break;
            }
        }

潘栩锋's avatar
潘栩锋 committed
377 378 379 380 381
        class CC
        {
            public IFConn from;
            public UInt32 srcid;
            public UInt32 magic;
382 383 384 385

            /// <summary>
            /// CALL_MethodInvoke 时使用
            /// </summary>
潘栩锋's avatar
潘栩锋 committed
386 387 388
            public string methodName;
        }
    }
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420

    /// <summary>
    /// 事件推送包装
    /// </summary>
    class AnyEvent
    {
        /// <summary>
        /// 事件名称
        /// </summary>
        public string eventName;
        /// <summary>
        /// json包装后的ReflectData 推送
        /// </summary>
        public Action<Reflect_OBJ_INTERFACE.ReflectData> PushObjInfoEx;
        /// <summary>
        /// 给 EventInfo 调用
        /// </summary>
        public EventHandler eventHandler;
        public AnyEvent()
        {
            eventHandler = new EventHandler(Obj_AnyEvent);
        }
        void Obj_AnyEvent(object sender, EventArgs e)
        {
            var rData = new Reflect_OBJ_INTERFACE.ReflectData()
            {
                name = eventName,
                data = JObject.FromObject(e)
            };
            PushObjInfoEx?.Invoke(rData);
        }
    }
潘栩锋's avatar
潘栩锋 committed
421
}