前两章分别讲了Socket的数据传输,本章开始将在前两章的基础上构建一个消息传输机制.
因为服务端和客户端都离不开消息的传输,所以先讲如何在前两章的基础上构建消息传输的信道,本例构造了一个类MessageSession,该类负责消息在网络中传送,并且该类实现了一个接口IMessageSession,其目的同前一章实现接口的目的一样,都是为了方便以后的扩展,该类的主要传输主体为一个接口IMessage,可以说这是一个消息调用的接口,是为了远程调用而定义的一个接口,本篇中先给出它的接口定义,其实现在后续章节中给出
IMessage接口的定义如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace YZKStdLibrary.Message 7 { 8 ///9 /// 消息接口 10 /// 11 public interface IMessage 12 { 13 ///14 /// 在服务进程中的消息唯一ID 15 /// 16 long MessageID { get; } 17 ///18 /// 获取登录凭证,该凭证为经过服务端验证的唯一标识 19 /// 20 string LoginedAuthentication { get; } 21 ///22 /// 获取调用成员名称或Guid 23 /// 24 string InvokeMemberGuid { get; } 25 ///26 /// 获取处理该消息的服务类标识,使用该标识确定是哪个服务类处理该消息 27 /// 28 string ServiceGuid { get; } 29 ///30 /// 获取处理该消息的程序集 31 /// 32 string AssemblyGuid { get; } 33 ///34 /// 消息参数数组 35 /// 36 object[] Paramets { get; } 37 } 38 }
1 ///2 /// 传输进度回调 3 /// 4 /// 要传输的数据的字节数 5 /// 已传输的字节数 6 /// 传输的消息 7 /// 传输方向 8 public delegate void OnTransingCallback(long transesize, long tranfferedbytes, IMessage message, DataTranseDirection transedirection);
该类定义了三个异步传输方法,由于使用IAsyncResult的返回机制,所以没有定义同不方法,要同步只需等待返回的完成信号即可,当然你也可以定义同步方法,这个在前一章的同步方法上构建比教简单,有兴趣的网友可以自己试试.三个异步传输方法分别是BeginTranseMessage,BeginSendMessage,BeginReceiveMessage,同时它们都对应一个结束方法EndTranseMessage,EndSendMessage,EndReceiveMessage,下面分别先说一下这三个方法的用途.
BeginTranseMessage:一般使用在客户端操作,也就是使用在发送完数据并且等待响应数据的应用场景下,大家可以想一下,客户端的调用一般都是一发一收的,即使是过程调用没有返回数据你也应该返回一个调用结束的消息通知调用方是否成功调用或返回一个错误通知错误信息.
BeginSendMessage和BeginReceiveMessage;一般使用在服务端,也就是在先接收消息再返回消息响应的应用场景下.
下面讲一下这三个方法:
BeginTranseMessageCore:先获取参数ITranseParamets,并将它设置成发送的状态,再设置传输时使用的流类型SR_StreamTypeEnum,然后开始数据传输,这里就涉及到接口ITranseParamets的实现类MessageTranseParamets
这个类在三个异步传输方法中都要用到,因此先讲讲这个类:MessageTranseParamets
SR_StreamType属性:定义传输流的类型
WaitReceiveMessage属性:定义是否等待消息响应
AsyncResult属性:一个IAsyncResult接口的实现
p_Serialize变量:一个序列化接口的对象,该序列化接口是自定义的,当然也可以使用MS本身的序列化
p_BufferIndexe变量:这是一个使用的缓冲区索引的结构,该结构的目的是指明使用的缓冲区的开始索引和长度,由于本例是从一个更大的应用中摘录的,在该应用中定义了一个缓冲区机制,即所有使用位数组的场景都使用同一个大的位数组,它是一开始就创建好的,使用者通过一些方法获取它的可用开始索引和长度后使用,本例中的位数组流和传输缓冲区都是使用这样一个机制.至于如何实现请网友们等待后续文章.
g_TempFileName变量:文件流的文件名称
Message属性:要发送的消息主体
TransingCallback属性:传输进度回调代理
其它接口的属性我就不讲了,请参看上一章接口的定义.
TranseBuffer,TranseBufferOffset,TranseBufferSize大家先用new byte[]和0,byte[].Length代替
ResetToSendParamets方法:将参数设置成等待发送的状态,该方法就是初始化发送时的参数,并且调用InitSendMessage方法初始化发送流,流的类型取决于属性SR_StreamType,对于Auto默任使用位数组流,对于创建位数组流CreateBytesStream方法中的类型BytesBufferStream已说过在后续章节中给出,大家不妨先用CreateBytesStream2使用MemoryStream代替.并且将消息序列化到流中(此时可以根据约定进行加密或压缩等操作),大家请注意了在InitSendMessage方法中最后设置了传输约定中的ITranseHeader.TranseSize和传输流的位置
ResetToRcvParamets方法:将参数设置成等待接收的状态.
ChangeToRcvParamets方法:将参数送发送状态转为接收状态
ResetToConnectParamets方法:将参数设置成连接状态
HeaderTransed方法:该方法是接口中定义的方法,用于通讯模块通知本接口约定已传输完成,在前一章中使用到本方法,
在该方法中首先将约定已传输标识置位,并且如果是接收操作则根据约定初始化接收流,接收流的初始化也是根据SR_StreamType属性创建的,所以发送和接收双方都应该使用同一个SR_StreamType的值.同样在没有给出BytesBufferStream流的定义之前,大家先用MemoryStream代替
AsyncTranseOver方法:该方法是接口中定义的方法,用于通讯模块通知本接口数据主体已传输完成,在前一章中使用到本方法,在该方法中如果是连接则直接调用连接完成的回调就完事,如果是接收则反序列化对象(此时可以根据约定进行解密或解压等操作),最后完成传输(调用MessageSession.FinshSession方法)
AsyncNotyTransing:该方法是接口中定义的方法,用于通讯模块通知本接口约定已传输完成,在前一章中使用到本方法,用于接收传输进度的通知,本例只是简单调用OnTransingCallback回调(如果不为null的话)就完事,
以下为该类的定义:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using YZKStdLibrary.Network.Transe; 6 using System.Net; 7 using System.Threading; 8 using System.IO; 9 using System.IO.MemoryMappedFiles; 10 using YZKStdLibrary.IO; 11 using YZKStdLibrary.Serialize; 12 13 namespace YZKStdLibrary.Message.Channel 14 { 15 internal class MessageTranseParamets : ITranseParamets 16 { 17 18 public MessageTranseParamets() 19 { 20 p_TranseHeader = new TranseHeader(); 21 p_AsyncResult = new MessageSessionAsyncResult(null, null); 22 p_SR_StreamType = SR_StreamTypeEnum.Auto; 23 } 24 25 private SR_StreamTypeEnum p_SR_StreamType; 26 27 public SR_StreamTypeEnum SR_StreamType 28 { 29 get { return p_SR_StreamType; } 30 set { p_SR_StreamType = value; } 31 } 32 33 private bool p_WaitReceiveMessage; 34 35 public bool WaitReceiveMessage 36 { 37 get { return p_WaitReceiveMessage; } 38 } 39 40 private MessageSession g_Owner; 41 42 private MessageSessionAsyncResult p_AsyncResult; 43 44 internal MessageSessionAsyncResult AsyncResult 45 { 46 get { return p_AsyncResult; } 47 } 48 49 private IFormattSerialize p_Serialize; 50 51 private BufferIndexHandle p_BufferIndexe; 52 53 private string g_TempFileName; 54 55 private void DeleteTempFile() 56 { 57 if (!string.IsNullOrEmpty(g_TempFileName)) 58 { 59 StandHelperMethod.DeleteFile(g_TempFileName); 60 g_TempFileName = null; 61 } 62 } 63 64 private void CloseStream() 65 { 66 if (p_TranseStream != null) 67 { 68 try 69 { 70 p_TranseStream.Close(); 71 } 72 catch { } 73 try 74 { 75 p_TranseStream.Dispose(); 76 } 77 catch { } 78 p_TranseStream = null; 79 } 80 } 81 82 private void CreateMappFileStream() 83 { 84 g_TempFileName = MessageHelper.GetTempFileName(); 85 //MemoryMappedFile mp = MemoryMappedFile.CreateFromFile(g_TempFileName, FileMode.Create, null, 5 * 1024 * 1024); 86 //p_TranseStream = mp.CreateViewStream(); 87 //mp.Dispose(); 88 p_TranseStream = new FileStream(g_TempFileName, FileMode.Create); 89 } 90 91 private void CreateBytesStream() 92 { 93 p_TranseStream = new BytesBufferStream(MessageHelper.StreamBuffer); 94 } 95 96 private void CreateBytesStream2() 97 { 98 p_TranseStream = new MemoryStream(); 99 } 100 101 private IMessage p_Message; 102 103 public IMessage Message 104 { 105 get { return p_Message; } 106 } 107 108 private OnTransingCallback p_TransingCallback; 109 110 public OnTransingCallback TransingCallback 111 { 112 get { return p_TransingCallback; } 113 } 114 115 private bool TrySerializeMessage(IMessage message) 116 { 117 try 118 { 119 p_Serialize.Serialize(p_TranseStream, message); 120 } 121 catch (BytesBufferManagerAssignException) 122 { 123 return false; 124 } 125 catch (Exception e) 126 { 127 p_TranseError = e; 128 } 129 return true; 130 } 131 132 private bool InitSendMessage(IMessage message) 133 { 134 try 135 { 136 switch (p_SR_StreamType) 137 { 138 case SR_StreamTypeEnum.Auto: 139 { 140 CreateBytesStream(); 141 if (!TrySerializeMessage(message)) 142 { 143 CloseStream(); 144 CreateMappFileStream(); 145 TrySerializeMessage(message); 146 } 147 break; 148 } 149 case SR_StreamTypeEnum.Bytes: 150 { 151 CreateBytesStream(); 152 p_Serialize.Serialize(p_TranseStream, message); 153 break; 154 } 155 case SR_StreamTypeEnum.Files: 156 { 157 CreateMappFileStream(); 158 p_Serialize.Serialize(p_TranseStream, message); 159 break; 160 } 161 } 162 } 163 catch (Exception e) 164 { 165 p_TranseError = e; 166 } 167 168 if (p_TranseError != null) 169 return false; 170 p_Message = message; 171 p_TranseHeader.TranseSize = p_TranseStream.Length; 172 p_TranseStream.Seek(0, SeekOrigin.Begin); 173 return true; 174 } 175 176 private void InitReceiveStream() 177 { 178 long x = p_TranseHeader.TranseSize; 179 switch (p_SR_StreamType) 180 { 181 case SR_StreamTypeEnum.Auto: 182 { 183 if (x < MessageHelper.StreamBuffer.TotalBytesCount) 184 { 185 BufferIndexHandle bh; 186 if (x <= 0) 187 bh = MessageHelper.StreamBuffer.TryAssignBufferHandle(); 188 else 189 bh = MessageHelper.StreamBuffer.TryAssignBufferHandle((int)x); 190 if (!bh.IsEmpty) 191 { 192 p_TranseStream = new BytesBufferStream( 193 MessageHelper.StreamBuffer, 194 bh, 195 0, true, true, true, true); 196 //((BytesBufferStream)p_TranseStream).InitFixStream(); 197 } 198 else 199 CreateMappFileStream(); 200 } 201 else 202 { 203 CreateMappFileStream(); 204 } 205 break; 206 } 207 case SR_StreamTypeEnum.Bytes: 208 { 209 BufferIndexHandle bh; 210 if (x <= 0) 211 bh = MessageHelper.StreamBuffer.TryAssignBufferHandle(); 212 else 213 bh = MessageHelper.StreamBuffer.TryAssignBufferHandle((int)x); 214 if (!bh.IsEmpty) 215 { 216 p_TranseStream = new BytesBufferStream( 217 MessageHelper.StreamBuffer, 218 bh, 219 0, true, true, true,true); 220 //((BytesBufferStream)p_TranseStream).InitFixStream(); 221 } 222 break; 223 } 224 case SR_StreamTypeEnum.Files: 225 { 226 CreateMappFileStream(); 227 break; 228 } 229 } 230 231 } 232 233 private void DeSerializeRcvMessage() 234 { 235 p_TranseStream.Seek(0, SeekOrigin.Begin); 236 p_AsyncResult.Response = 237 p_Serialize.DeSerialize(p_TranseStream) as IMessage; 238 } 239 240 #region ITranseParamets 成员 241 242 private TranseHeader p_TranseHeader; 243 244 public ITranseHeader TranseHeader 245 { 246 get { return p_TranseHeader; } 247 } 248 249 private Stream p_TranseStream; 250 251 public Stream TranseStream 252 { 253 get { return p_TranseStream; } 254 } 255 256 public byte[] TranseBuffer 257 { 258 get { return MessageHelper.ReadWriteBuffer.Buffer; } 259 } 260 261 public int TranseBufferOffset 262 { 263 get { return p_BufferIndexe.Index; } 264 } 265 266 public int TranseBufferSize 267 { 268 get { return p_BufferIndexe.Count; } 269 } 270 271 private long p_BytesTransferred; 272 273 public long BytesTransferred 274 { 275 get 276 { 277 return p_BytesTransferred; 278 } 279 set 280 { 281 p_BytesTransferred = value; 282 } 283 } 284 285 private bool p_IsAsyncTranse; 286 287 public bool IsAsyncTranse 288 { 289 get { return p_IsAsyncTranse; } 290 set { p_IsAsyncTranse = value; } 291 } 292 293 private DataTranseDirection p_DataTranseDirection; 294 295 public DataTranseDirection DataTranseDirection 296 { 297 get { return p_DataTranseDirection; } 298 } 299 300 private Exception p_TranseError; 301 302 public Exception TranseError 303 { 304 get 305 { 306 return p_TranseError; 307 } 308 set 309 { 310 p_TranseError = value; 311 } 312 } 313 314 private bool p_IsCancel; 315 316 public bool IsCancel 317 { 318 get { return p_IsCancel; } 319 } 320 321 private bool p_HeaderTransedOver; 322 323 public bool HeaderTransedOver 324 { 325 get { return p_HeaderTransedOver; } 326 } 327 328 private EndPoint p_ConnectToEndPoint; 329 330 public EndPoint ConnectToEndPoint 331 { 332 get { return p_ConnectToEndPoint; } 333 } 334 335 private object p_ConnectTranseInterfaceSetting; 336 337 public object ConnectTranseInterfaceSetting 338 { 339 get { return p_ConnectTranseInterfaceSetting; } 340 } 341 342 public void HeaderTransed() 343 { 344 p_HeaderTransedOver = true; 345 if (p_DataTranseDirection == DataTranseDirection.ReceivingData) 346 { 347 InitReceiveStream(); 348 } 349 } 350 351 public void AsyncTranseOver() 352 { 353 if (p_DataTranseDirection == Network.Transe.DataTranseDirection.Connecting) 354 { 355 if (p_Cb != null) 356 p_Cb(this); 357 return; 358 } 359 if (p_TranseError == null) 360 { 361 if (p_DataTranseDirection == Network.Transe.DataTranseDirection.ReceivingData) 362 { 363 try 364 { 365 DeSerializeRcvMessage(); 366 } 367 catch (Exception e) 368 { 369 p_TranseError = e; 370 } 371 } 372 } 373 if (g_Owner != null) 374 g_Owner.FinshSession(this); 375 } 376 377 public void AsyncNotyTransing() 378 { 379 if (p_TransingCallback != null) 380 p_TransingCallback(p_TranseHeader.TranseSize, p_BytesTransferred, p_Message, p_DataTranseDirection); 381 } 382 383 #endregion 384 385 internal void ResetToNull(bool asyncrest) 386 { 387 CloseStream(); 388 DeleteTempFile(); 389 MessageHelper.ReadWriteBuffer.RecoveryBufferHandle(p_BufferIndexe); 390 p_BufferIndexe = BufferIndexHandle.Empty; 391 if (asyncrest) 392 p_AsyncResult.ResetToNull(); 393 else 394 p_AsyncResult = null; 395 p_Serialize = null; 396 p_BytesTransferred = 0; 397 p_DataTranseDirection = DataTranseDirection.Unkown; 398 p_IsAsyncTranse = false; 399 p_TranseError = null; 400 p_IsCancel = false; 401 p_HeaderTransedOver = false; 402 p_ConnectToEndPoint = null; 403 p_ConnectTranseInterfaceSetting = null; 404 p_TransingCallback = null; 405 p_Message = null; 406 p_TranseHeader.RecyValue(); 407 g_Owner = null; 408 p_WaitReceiveMessage = false; 409 p_Cb = null; 410 } 411 412 internal bool ResetToSendParamets( 413 MessageSession owner, 414 IMessage sendmessage, 415 int headerflag, 416 object state, 417 AsyncCallback callback, 418 OnTransingCallback tccbk, 419 bool waitrcvmsg) 420 { 421 g_Owner = owner; 422 p_BufferIndexe = MessageHelper.ReadWriteBuffer.AssignBufferHandle(); 423 p_Serialize = CurrentAppConfiger.CurrentErpConfinger.Formattor; 424 if (p_AsyncResult == null) 425 p_AsyncResult = new MessageSessionAsyncResult(state, callback); 426 else 427 p_AsyncResult.Reset(state, callback); 428 p_DataTranseDirection = Network.Transe.DataTranseDirection.SendingData; 429 p_IsAsyncTranse = true; 430 p_TransingCallback = tccbk; 431 p_TranseHeader.TranseFlags = headerflag; 432 p_WaitReceiveMessage = waitrcvmsg; 433 return InitSendMessage(sendmessage); 434 } 435 436 internal void ResetToRcvParamets( 437 MessageSession owner, 438 int headerflag, 439 object state, 440 AsyncCallback callback, 441 OnTransingCallback tccbk) 442 { 443 g_Owner = owner; 444 p_BufferIndexe = MessageHelper.ReadWriteBuffer.AssignBufferHandle(); 445 p_Serialize = CurrentAppConfiger.CurrentErpConfinger.Formattor; 446 if (p_AsyncResult == null) 447 p_AsyncResult = new MessageSessionAsyncResult(state, callback); 448 else 449 p_AsyncResult.Reset(state, callback); 450 p_DataTranseDirection = Network.Transe.DataTranseDirection.ReceivingData; 451 p_IsAsyncTranse = true; 452 p_TransingCallback = tccbk; 453 p_TranseHeader.TranseFlags = headerflag; 454 p_WaitReceiveMessage = false; 455 } 456 457 internal void ChangeToRcvParamets() 458 { 459 CloseStream(); 460 DeleteTempFile(); 461 p_Cb = null; 462 p_BytesTransferred = 0; 463 p_DataTranseDirection = DataTranseDirection.ReceivingData; 464 p_IsAsyncTranse = true; 465 p_TranseError = null; 466 p_IsCancel = false; 467 p_HeaderTransedOver = false; 468 p_ConnectToEndPoint = null; 469 p_ConnectTranseInterfaceSetting = null; 470 p_Message = null; 471 p_TranseHeader.TranseSize = 0; 472 p_WaitReceiveMessage = false; 473 } 474 475 internal void ResetToConnectParamets( 476 IMessage sendmessage, 477 EndPoint ep, 478 ConnectCallback cb, 479 object facesetting, 480 object state, 481 OnTransingCallback tccbk) 482 { 483 p_TransingCallback = tccbk; 484 p_IsAsyncTranse = true; 485 p_ConnectToEndPoint = ep; 486 p_DataTranseDirection = Network.Transe.DataTranseDirection.Connecting; 487 p_ConnectTranseInterfaceSetting = facesetting; 488 p_Cb = cb; 489 p_Message = sendmessage; 490 if (p_AsyncResult == null) 491 p_AsyncResult = new MessageSessionAsyncResult(state, null); 492 else 493 p_AsyncResult.Reset(state, null); 494 } 495 496 private ConnectCallback p_Cb; 497 } 498 499 internal class MessageSessionAsyncResult : IAsyncResult,IDisposable 500 { 501 502 internal MessageSessionAsyncResult(object state,AsyncCallback callback) 503 { 504 p_AsyncState = state; 505 p_CompletedSynchronously = false; 506 p_IsCompleted = false; 507 p_Callback = callback; 508 p_AsyncWaitHandle = null; 509 g_WaitLock = new object(); 510 } 511 512 private object p_AsyncState; 513 514 private bool p_CompletedSynchronously; 515 516 private bool p_IsCompleted; 517 518 private AsyncCallback p_Callback; 519 520 private ManualResetEvent p_AsyncWaitHandle; 521 522 private object g_WaitLock; 523 524 #region IAsyncResult 成员 525 526 public object AsyncState 527 { 528 get { return p_AsyncState; } 529 } 530 531 public WaitHandle AsyncWaitHandle 532 { 533 get 534 { 535 lock (g_WaitLock) 536 { 537 if (p_AsyncWaitHandle == null) 538 p_AsyncWaitHandle = new ManualResetEvent(false); 539 return p_AsyncWaitHandle; 540 } 541 } 542 } 543 544 public bool CompletedSynchronously 545 { 546 get { return p_CompletedSynchronously; } 547 } 548 549 public bool IsCompleted 550 { 551 get { return p_IsCompleted; } 552 } 553 554 #endregion 555 556 internal bool SetHandle() 557 { 558 p_IsCompleted = true; 559 bool set = false; 560 lock (g_WaitLock) 561 { 562 if (p_AsyncWaitHandle != null) 563 { 564 p_AsyncWaitHandle.Set(); 565 set = true; 566 } 567 } 568 if (!set) 569 { 570 if (p_Callback != null) 571 p_Callback(this); 572 } 573 return set; 574 } 575 576 #region IDisposable 成员 577 578 public void Dispose() 579 { 580 lock (g_WaitLock) 581 { 582 if (p_AsyncWaitHandle != null) 583 { 584 try 585 { 586 p_AsyncWaitHandle.Close(); 587 } 588 catch { } 589 try 590 { 591 p_AsyncWaitHandle.Dispose(); 592 } 593 catch { } 594 p_AsyncWaitHandle = null; 595 } 596 } 597 } 598 599 #endregion 600 601 private IMessage p_Response; 602 603 internal IMessage Response 604 { 605 get { return p_Response; } 606 set { p_Response = value; } 607 } 608 609 internal void ResetToNull() 610 { 611 Dispose(); 612 p_AsyncState = null; 613 p_CompletedSynchronously = false; 614 p_IsCompleted = false; 615 p_Callback = null; 616 p_Response = null; 617 p_Error = null; 618 p_ConnecteFace = null; 619 p_Session = null; 620 } 621 622 internal void Reset(object state, AsyncCallback callback) 623 { 624 p_AsyncState = state; 625 p_Callback = callback; 626 p_IsCompleted = false; 627 } 628 629 private Exception p_Error; 630 631 internal Exception Error 632 { 633 get { return p_Error; } 634 set { p_Error = value; } 635 } 636 637 private ITranseInterface p_ConnecteFace; 638 639 internal ITranseInterface ConnectFace 640 { 641 get { return p_ConnecteFace; } 642 set { p_ConnecteFace = value; } 643 } 644 645 private IMessageSession p_Session; 646 647 internal IMessageSession Session 648 { 649 get { return p_Session; } 650 set { p_Session = value; } 651 } 652 }
653 }
1 public enum SR_StreamTypeEnum 2 { 3 ///4 /// 自动选择 5 /// 6 Auto, 7 ///8 /// 位数组流 9 /// 10 Bytes, 11 ///12 /// 文件流 13 /// 14 Files 15 } 16 17 internal delegate void ConnectCallback(MessageTranseParamets par);
BeginSendMessage方法:它和BeginTranseMessage方法一样,只不过对waitrcv传进False,也就是说该方法不等响应一旦发送完成就调用回调,而BeginTranseMessage方法要等待响应接收完成后再调用回调.
BeginReceiveMessage方法:它将参数ITranseParamets设为接收状态后就开始等待接收数据,接收完成后就调用回调.
由于存在BeginSendMessage和BeginReceiveMessage方法,使用方可以进行N次发送和接收,这都是根据具体应用而定的,所以提供了Close和WaitClose方法由使用方负责在适当的时机关闭信道.
下面是IMessage接口定义,先贴出来:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace YZKStdLibrary.Message 7 { 8 ///9 /// 消息接口 10 /// 11 public interface IMessage 12 { 13 ///14 /// 在服务进程中的消息唯一ID 15 /// 16 long MessageID { get; } 17 ///18 /// 获取登录凭证,该凭证为经过服务端验证的唯一标识 19 /// 20 string LoginedAuthentication { get; } 21 ///22 /// 获取调用成员名称或Guid 23 /// 24 string InvokeMemberGuid { get; } 25 ///26 /// 获取处理该消息的服务类标识,使用该标识确定是哪个服务类处理该消息 27 /// 28 string ServiceGuid { get; } 29 ///30 /// 获取处理该消息的程序集 31 /// 32 string AssemblyGuid { get; } 33 ///34 /// 消息参数数组 35 /// 36 object[] Paramets { get; } 37 } 38 }
OK,这一章就先到这了.