fix: 修复 XmlSerializer 潜在的内存泄漏问题

This commit is contained in:
Fu Diwei 2021-10-19 10:32:30 +08:00
parent 4edbf3700e
commit 97f58456c2
6 changed files with 99 additions and 47 deletions

View File

@ -79,10 +79,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Api
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
}
using var reader = new StringReader(callbackXml);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(TEvent), new XmlRootAttribute("xml"));
return (TEvent)xmlSerializer.Deserialize(reader)!;
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml);
}
catch (WechatApiException)
{

View File

@ -13,6 +13,21 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
// REF: https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.serialization.xmlserializer#dynamically-generated-assemblies
private static Hashtable _serializers = new Hashtable();
private static XmlSerializer GetTypedSerializer(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
string skey = type.AssemblyQualifiedName;
XmlSerializer? xmlSerializer = (XmlSerializer)_serializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
_serializers[skey] = xmlSerializer;
}
return xmlSerializer;
}
public static string Serialize(Type type, object obj)
{
string xml;
@ -24,19 +39,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
settings.WriteEndDocumentOnClose = false;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
string skey = type.AssemblyQualifiedName;
XmlSerializer? xmlSerializer = (XmlSerializer)_serializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
_serializers[skey] = xmlSerializer;
}
using var stream = new MemoryStream();
using var writer = XmlWriter.Create(stream, settings);
XmlSerializerNamespaces xmlNamespace = new XmlSerializerNamespaces();
xmlNamespace.Add(string.Empty, string.Empty);
xmlSerializer.Serialize(writer, obj, xmlNamespace);
XmlSerializer serializer = GetTypedSerializer(type);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
serializer.Serialize(writer, obj, ns);
writer.Flush();
xml = Encoding.UTF8.GetString(stream.ToArray());
xml = Regex.Replace(xml, "\\s*<\\w+ (xsi|d2p1):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
@ -50,5 +58,18 @@ namespace SKIT.FlurlHttpClient.Wechat.Api.Utilities
{
return Serialize(typeof(T), obj);
}
public static object Deserialize(Type type, string xml)
{
using var reader = new StringReader(xml);
XmlSerializer serializer = GetTypedSerializer(type);
return serializer.Deserialize(reader);
}
public static T Deserialize<T>(string xml)
where T : class
{
return (T)Deserialize(typeof(T), xml);
}
}
}

View File

@ -41,11 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
throw new Exceptions.WechatOpenAIEventSerializationException("Encrypt event failed, because of empty encrypted data.");
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.EncodingAESKey!, out _);
using var reader = new StringReader(callbackXml);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(TEvent), new XmlRootAttribute("xml"));
return (TEvent)xmlSerializer.Deserialize(reader)!;
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml);
}
catch (WechatOpenAIException)
{

View File

@ -13,6 +13,21 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
// REF: https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.serialization.xmlserializer#dynamically-generated-assemblies
private static Hashtable _serializers = new Hashtable();
private static XmlSerializer GetTypedSerializer(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
string skey = type.AssemblyQualifiedName;
XmlSerializer? xmlSerializer = (XmlSerializer)_serializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
_serializers[skey] = xmlSerializer;
}
return xmlSerializer;
}
public static string Serialize(Type type, object obj)
{
string xml;
@ -24,19 +39,12 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
settings.WriteEndDocumentOnClose = false;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
string skey = type.AssemblyQualifiedName;
XmlSerializer? xmlSerializer = (XmlSerializer)_serializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
_serializers[skey] = xmlSerializer;
}
using var stream = new MemoryStream();
using var writer = XmlWriter.Create(stream, settings);
XmlSerializerNamespaces xmlNamespace = new XmlSerializerNamespaces();
xmlNamespace.Add(string.Empty, string.Empty);
xmlSerializer.Serialize(writer, obj, xmlNamespace);
XmlSerializer serializer = GetTypedSerializer(type);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
serializer.Serialize(writer, obj, ns);
writer.Flush();
xml = Encoding.UTF8.GetString(stream.ToArray());
xml = Regex.Replace(xml, "\\s*<\\w+ (xsi|d2p1):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
@ -50,5 +58,18 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
{
return Serialize(typeof(T), obj);
}
public static object Deserialize(Type type, string xml)
{
using var reader = new StringReader(xml);
XmlSerializer serializer = GetTypedSerializer(type);
return serializer.Deserialize(reader);
}
public static T Deserialize<T>(string xml)
where T : class
{
return (T)Deserialize(typeof(T), xml);
}
}
}

View File

@ -71,11 +71,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Work
throw new Exceptions.WechatWorkEventSerializationException("Encrypt event failed, because of empty encrypted data.");
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
using var reader = new StringReader(callbackXml);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(TEvent), new XmlRootAttribute("xml"));
return (TEvent)xmlSerializer.Deserialize(reader)!;
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml);
}
catch (WechatWorkException)
{

View File

@ -13,6 +13,21 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
// REF: https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.serialization.xmlserializer#dynamically-generated-assemblies
private static Hashtable _serializers = new Hashtable();
private static XmlSerializer GetTypedSerializer(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
string skey = type.AssemblyQualifiedName;
XmlSerializer? xmlSerializer = (XmlSerializer)_serializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
_serializers[skey] = xmlSerializer;
}
return xmlSerializer;
}
public static string Serialize(Type type, object obj)
{
string xml;
@ -24,19 +39,12 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
settings.WriteEndDocumentOnClose = false;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
string skey = type.AssemblyQualifiedName;
XmlSerializer? xmlSerializer = (XmlSerializer)_serializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, new XmlRootAttribute("xml"));
_serializers[skey] = xmlSerializer;
}
using var stream = new MemoryStream();
using var writer = XmlWriter.Create(stream, settings);
XmlSerializerNamespaces xmlNamespace = new XmlSerializerNamespaces();
xmlNamespace.Add(string.Empty, string.Empty);
xmlSerializer.Serialize(writer, obj, xmlNamespace);
XmlSerializer serializer = GetTypedSerializer(type);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
serializer.Serialize(writer, obj, ns);
writer.Flush();
xml = Encoding.UTF8.GetString(stream.ToArray());
xml = Regex.Replace(xml, "\\s*<\\w+ (xsi|d2p1):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
@ -50,5 +58,18 @@ namespace SKIT.FlurlHttpClient.Wechat.Work.Utilities
{
return Serialize(typeof(T), obj);
}
public static object Deserialize(Type type, string xml)
{
using var reader = new StringReader(xml);
XmlSerializer serializer = GetTypedSerializer(type);
return serializer.Deserialize(reader);
}
public static T Deserialize<T>(string xml)
where T : class
{
return (T)Deserialize(typeof(T), xml);
}
}
}