Skip to content

Commit 27ae5bb

Browse files
committed
优化xml序列化到IBufferWriter
1 parent 8cb8457 commit 27ae5bb

File tree

6 files changed

+36
-69
lines changed

6 files changed

+36
-69
lines changed

WebApiClientCore.Benchmarks/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ static void Main(string[] args)
99
{
1010
BenchmarkRunner.Run<HttpGetBenchmark>();
1111
BenchmarkRunner.Run<HttpGetJsonBenchmark>();
12-
BenchmarkRunner.Run<HttpPostXmlBenchmark>();
1312
BenchmarkRunner.Run<HttpPostJsonBenchmark>();
13+
BenchmarkRunner.Run<HttpPostXmlBenchmark>();
1414
BenchmarkRunner.Run<HttpPutFormBenchmark>();
1515
}
1616
}

WebApiClientCore.Test/Attributes/ParameterAttributes/XmlContentAttributeTest.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@ public async Task OnRequestAsyncTest()
3737
await attr.OnRequestAsync(new ApiParameterContext(context, 0));
3838
var body = await context.HttpContext.RequestMessage.Content!.ReadAsStringAsync();
3939

40-
using var bufferWriter = new RecyclableBufferWriter<byte>();
41-
XmlSerializer.Serialize(bufferWriter, context.Arguments[0], null);
42-
var target = Encoding.GetEncoding(attr.CharSet).GetString(bufferWriter.WrittenSpan);
40+
var target = XmlSerializer.Serialize(context.Arguments[0], null);
4341
Assert.True(body == target);
4442
}
4543
}

WebApiClientCore/ApiParameterContextExtensions.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ public static void SerializeToJson(this ApiParameterContext context, IBufferWrit
8989
/// <returns></returns>
9090
[RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")]
9191
public static string? SerializeToXml(this ApiParameterContext context, Encoding? encoding)
92+
{
93+
using var bufferWriter = new RecyclableBufferWriter<char>();
94+
context.SerializeToXml(encoding, bufferWriter);
95+
return bufferWriter.WrittenSpan.ToString();
96+
}
97+
98+
/// <summary>
99+
/// 序列化参数值为Xml
100+
/// </summary>
101+
/// <param name="context"></param>
102+
/// <param name="bufferWriter">数据写入器</param>
103+
/// <param name="encoding">xml的编码</param>
104+
/// <returns></returns>
105+
[RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")]
106+
public static void SerializeToXml(this ApiParameterContext context, Encoding? encoding, IBufferWriter<char> bufferWriter)
92107
{
93108
var options = context.HttpContext.HttpApiOptions.XmlSerializeOptions;
94109
if (encoding != null && encoding.Equals(options.Encoding) == false)
@@ -97,7 +112,7 @@ public static void SerializeToJson(this ApiParameterContext context, IBufferWrit
97112
options.Encoding = encoding;
98113
}
99114

100-
return XmlSerializer.Serialize(context.ParameterValue, options);
115+
XmlSerializer.Serialize(context.ParameterValue, options, bufferWriter);
101116
}
102117

103118
/// <summary>

WebApiClientCore/Attributes/ParameterAttributes/XmlContentAttribute.cs

+4-8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Text;
44
using System.Threading.Tasks;
55
using WebApiClientCore.HttpContents;
6+
using WebApiClientCore.Internals;
67

78
namespace WebApiClientCore.Attributes
89
{
@@ -34,14 +35,9 @@ public string CharSet
3435
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
3536
protected override Task SetHttpContentAsync(ApiParameterContext context)
3637
{
37-
var options = context.HttpContext.HttpApiOptions.XmlSerializeOptions;
38-
if (encoding != null && encoding.Equals(options.Encoding) == false)
39-
{
40-
options = options.Clone();
41-
options.Encoding = encoding;
42-
}
43-
44-
context.HttpContext.RequestMessage.Content = new XmlContent(context.ParameterValue, options);
38+
using var bufferWriter = new RecyclableBufferWriter<char>();
39+
context.SerializeToXml(this.encoding, bufferWriter);
40+
context.HttpContext.RequestMessage.Content = new XmlContent(bufferWriter.WrittenSpan, this.encoding);
4541
return Task.CompletedTask;
4642
}
4743
}
+2-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
using System.Diagnostics.CodeAnalysis;
1+
using System;
22
using System.Net.Http.Headers;
33
using System.Text;
4-
using System.Xml;
5-
using WebApiClientCore.Serialization;
64

75
namespace WebApiClientCore.HttpContents
86
{
@@ -23,26 +21,12 @@ public class XmlContent : BufferContent
2321
/// </summary>
2422
/// <param name="xml">xml内容</param>
2523
/// <param name="encoding">编码</param>
26-
public XmlContent(string? xml, Encoding encoding)
24+
public XmlContent(ReadOnlySpan<char> xml, Encoding encoding)
2725
{
2826
encoding.GetBytes(xml, this);
2927
this.Headers.ContentType = encoding == Encoding.UTF8
3028
? defaultMediaType :
3129
new MediaTypeHeaderValue(MediaType) { CharSet = encoding.WebName };
3230
}
33-
34-
/// <summary>
35-
/// xml内容
36-
/// </summary>
37-
/// <param name="obj">xml实体</param>
38-
/// <param name="xmlWriterSettings">xml写入设置项</param>
39-
[RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")]
40-
public XmlContent(object? obj, XmlWriterSettings xmlWriterSettings)
41-
{
42-
XmlSerializer.Serialize(this, obj, xmlWriterSettings);
43-
this.Headers.ContentType = xmlWriterSettings.Encoding == Encoding.UTF8
44-
? defaultMediaType
45-
: new MediaTypeHeaderValue(MediaType) { CharSet = xmlWriterSettings.Encoding.WebName };
46-
}
4731
}
4832
}

WebApiClientCore/Serialization/XmlSerializer.cs

+12-38
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
using System.Xml;
9+
using WebApiClientCore.Internals;
910

1011
namespace WebApiClientCore.Serialization
1112
{
@@ -31,10 +32,9 @@ public static class XmlSerializer
3132
return null;
3233
}
3334

34-
var settings = options ?? writerSettings;
35-
using var writer = new EncodingStringWriter(settings.Encoding);
36-
SerializeCore(writer, obj, settings);
37-
return writer.ToString();
35+
using var bufferWriter = new RecyclableBufferWriter<char>();
36+
Serialize(obj, options, bufferWriter);
37+
return bufferWriter.WrittenSpan.ToString();
3838
}
3939

4040
/// <summary>
@@ -44,22 +44,16 @@ public static class XmlSerializer
4444
/// <param name="obj">对象</param>
4545
/// <param name="options">配置选项</param>
4646
[RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")]
47-
public static void Serialize(IBufferWriter<byte> bufferWriter, object? obj, XmlWriterSettings? options)
47+
public static void Serialize(object? obj, XmlWriterSettings? options, IBufferWriter<char> bufferWriter)
4848
{
4949
if (obj == null)
5050
{
5151
return;
5252
}
5353

5454
var settings = options ?? writerSettings;
55-
using var writer = new BufferTextWriter(bufferWriter, settings.Encoding);
56-
SerializeCore(writer, obj, settings);
57-
}
58-
59-
[RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")]
60-
private static void SerializeCore(TextWriter textWriter, object obj, XmlWriterSettings settings)
61-
{
62-
using var xmlWriter = XmlWriter.Create(textWriter, settings);
55+
using var writer = new XmlBufferWriter(bufferWriter, settings.Encoding);
56+
using var xmlWriter = XmlWriter.Create(writer, settings);
6357
var xmlSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
6458
xmlSerializer.Serialize(xmlWriter, obj);
6559
}
@@ -92,25 +86,26 @@ private static void SerializeCore(TextWriter textWriter, object obj, XmlWriterSe
9286
}
9387

9488

95-
private class BufferTextWriter : TextWriter
89+
private class XmlBufferWriter : TextWriter
9690
{
97-
private readonly IBufferWriter<byte> bufferWriter;
91+
private readonly IBufferWriter<char> bufferWriter;
9892

9993
public override Encoding Encoding { get; }
10094

101-
public BufferTextWriter(IBufferWriter<byte> bufferWriter, Encoding encoding)
95+
public XmlBufferWriter(IBufferWriter<char> bufferWriter, Encoding encoding)
10296
{
10397
this.bufferWriter = bufferWriter;
10498
this.Encoding = encoding;
10599
}
100+
106101
public override Task FlushAsync()
107102
{
108103
return Task.CompletedTask;
109104
}
110105

111106
public override void Write(ReadOnlySpan<char> buffer)
112107
{
113-
this.Encoding.GetBytes(buffer, this.bufferWriter);
108+
this.bufferWriter.Write(buffer);
114109
}
115110

116111
public override void Write(char value)
@@ -187,26 +182,5 @@ public override Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationTok
187182
return Task.CompletedTask;
188183
}
189184
}
190-
191-
192-
/// <summary>
193-
/// 表示可指定编码文本写入器
194-
/// </summary>
195-
private class EncodingStringWriter : StringWriter
196-
{
197-
/// <summary>
198-
/// 获取编码
199-
/// </summary>
200-
public override Encoding Encoding { get; }
201-
202-
/// <summary>
203-
/// 可指定编码文本写入器
204-
/// </summary>
205-
/// <param name="encoding">编码</param>
206-
public EncodingStringWriter(Encoding encoding)
207-
{
208-
this.Encoding = encoding;
209-
}
210-
}
211185
}
212186
}

0 commit comments

Comments
 (0)