dotnet remoting 拋出異常

  • 2019 年 10 月 8 日
  • 筆記

本文告訴大家如何在使用 .net remoting 的時候,拋出異常。

所有在遠程軟件運行的類,如果需要傳輸到本地,都需要繼承 MarshalByRefObject 或其他可以序列化的類。

在 .net Framework 4.0 就默認指定只反序列化基礎類型,如果需要反序列化其他的類型,那麼就需要設置TypeFilterLevel,設置的方法是在使用下面代碼

      public static IChannel CreatChannel(string port = "")          {              if (string.IsNullOrEmpty(port))              {                  port = Guid.NewGuid().ToString("N");              }                var serverProvider = new SoapServerFormatterSinkProvider();              var clientProvider = new SoapClientFormatterSinkProvider();              serverProvider.TypeFilterLevel = TypeFilterLevel.Full;              IDictionary props = new Hashtable();              props["portName"] = port.ToString();                return new IpcChannel(props, clientProvider, serverProvider);          }

但是設置了TypeFilterLevel不是對所有的類型都可以進行轉換,如果不小心直接在調用方法拋出異常,那麼會因為無法反序列,讓本地拿不到

 // 遠程     public void Foo()   {   	throw new CsdnNotFoundException();   }     public class CsdnNotFoundException : Exception   {   	public CsdnNotFoundException(string str) :   	       base(str)   	{     	}   }

這時本地會提示System.Runtime.Serialization.SerializationException程序無法序列。

如果需要在 .net remoting 使用異常,那麼需要自己創建一個異常,繼承 RemotingException

反序列

因為默認的 RemotingException 沒有反序列,所以需要添加 Serializable 特性

 [Serializable]   public class CsdnNotFoundException : RemotingException   {   	public CsdnNotFoundException(string str) :   	       base(str)   	{     	}   }

微軟建議繼承ISerializable,標記特性

 [Serializable]   public class CsdnNotFoundException : RemotingException, ISerializable   {   	public CsdnNotFoundException(string str) :   	       base(str)   	{     	}   }

如果直接運行,會發現報告System.Runtime.Serialization.SerializationException:「未找到反序列化「lindexi.Csdn.CsdnNotFoundException」類型對象的構造函數

解決方法是創建一個構造函數,寫入這個函數就不需要再寫其他的代碼。

        protected CsdnNotFoundException([NotNull] SerializationInfo info, StreamingContext context) : base(info,              context)          {          }

如果有一些特殊的屬性需要自己設置,建議創建一個默認構造函數,和兩個方法,因為使用上面的方法不會序列化自己定義的屬性。

 [Serializable]   public class CsdnNotFoundException : RemotingException, ISerializable   {      public CsdnNotFoundException()      {      	//默認構造,可以在反射創建      }     	public CsdnNotFoundException(string str) :   	       base(str)   	{     	}     	      protected CsdnNotFoundException([NotNull] SerializationInfo info, StreamingContext context)   	      //: base(info, context) 不使用基類的原因是基類會報告 找不到 ClassName 和其他很多的坑          {              //反序列化創建                Message = (string) info.GetValue(MessageSerialization, typeof(string));          }            // 重寫消息,用於在構造設置值          public override string Message { get; }            // 用於在構造拿到消息的值          private const string MessageSerialization = "Message";            // 重寫這個方法,在序列化調用          public override void GetObjectData(SerializationInfo info, StreamingContext context)          {              info.AddValue(MessageSerialization, Message);          }   }

在 GetObjectData 拿到必要的屬性,這個需要自己把需要的屬性寫入。然後在構造函數重寫[NotNull] SerializationInfo info, StreamingContext context方法的,可以拿到值

因為上面的代碼用到 Message ,需要重寫這個屬性,因為默認是只讀,不能在構造函數設置。

是不是覺得很複雜,實際上簡單的方法是通過 json 在GetObjectData把類轉換為json,在構造轉換為類。

ISerializable

那麼為什麼在使用 Serializable 特性還需要繼承 ISerializable ,因為繼承 ISerializable 就可以在一個構造函數xx([NotNull] SerializationInfo info, StreamingContext context)進行處理和處理如何序列化。處理如何序列化可以提高性能,因為自己知道哪些需要序列化,哪些不需要。

關於 ISerializable 請看 c# – What is the point of the ISerializable interface? – Stack Overflow

How to: Create an Exception Type That Can be Thrown by Remote Objects

我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=19bm8i8js1ezb