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