@@ -47,25 +47,52 @@ public void AddOrReplacePart<T>(string partName, string contentType, T partValue
4747 {
4848 throw new ArgumentNullException ( nameof ( partValue ) ) ;
4949 }
50+ var key = ( partName , fileName ?? "" ) ;
5051 var value = new Part ( partName , partValue , contentType , fileName ) ;
51- if ( ! _parts . TryAdd ( partName , value ) )
52+ if ( ! _parts . TryAdd ( key , value ) )
5253 {
53- _parts [ partName ] = value ;
54+ _parts [ key ] = value ;
5455 }
5556 }
57+ // TODO: Remove with next major release
5658 /// <summary>
5759 /// Gets the value of a part from the multipart body.
5860 /// </summary>
5961 /// <typeparam name="T">The type of the part value.</typeparam>
6062 /// <param name="partName">The name of the part.</param>
6163 /// <returns>The value of the part.</returns>
6264 public T ? GetPartValue < T > ( string partName )
65+ {
66+ var value = GetPartValue < T > ( partName , null ) ;
67+
68+ if ( EqualityComparer < T ? > . Default . Equals ( value , default ) )
69+ {
70+ foreach ( var key in _parts . Keys )
71+ {
72+ if ( key . Item1 == partName )
73+ {
74+ value = GetPartValue < T > ( partName , key . Item2 ) ;
75+ break ;
76+ }
77+ }
78+ }
79+
80+ return value ;
81+ }
82+ /// <summary>
83+ /// Gets the value of a part from the multipart body.
84+ /// </summary>
85+ /// <typeparam name="T">The type of the part value.</typeparam>
86+ /// <param name="partName">The name of the part.</param>
87+ /// <param name="fileName">An optional file name for the part.</param>
88+ /// <returns>The value of the part.</returns>
89+ public T ? GetPartValue < T > ( string partName , string ? fileName )
6390 {
6491 if ( string . IsNullOrEmpty ( partName ) )
6592 {
6693 throw new ArgumentNullException ( nameof ( partName ) ) ;
6794 }
68- if ( _parts . TryGetValue ( partName , out var value ) )
95+ if ( _parts . TryGetValue ( ( partName , fileName ?? "" ) , out var value ) )
6996 {
7097 if ( value == null )
7198 return default ;
@@ -74,21 +101,47 @@ public void AddOrReplacePart<T>(string partName, string contentType, T partValue
74101 }
75102 return default ;
76103 }
104+ // TODO: Remove with next major release
77105 /// <summary>
78106 /// Removes a part from the multipart body.
79107 /// </summary>
80108 /// <param name="partName">The name of the part.</param>
81109 /// <returns>True if the part was removed, false otherwise.</returns>
82110 public bool RemovePart ( string partName )
111+ {
112+ bool success = RemovePart ( partName , null ) ;
113+
114+ if ( ! success )
115+ {
116+ foreach ( var key in _parts . Keys )
117+ {
118+ if ( key . Item1 == partName )
119+ {
120+ success = RemovePart ( partName , key . Item2 ) ;
121+ break ;
122+ }
123+ }
124+ }
125+
126+ return success ;
127+ }
128+
129+ /// <summary>
130+ /// Removes a part from the multipart body.
131+ /// </summary>
132+ /// <param name="partName">The name of the part.</param>
133+ /// <param name="fileName">An optional file name for the part.</param>
134+ /// <returns>True if the part was removed, false otherwise.</returns>
135+ public bool RemovePart ( string partName , string ? fileName )
83136 {
84137 if ( string . IsNullOrEmpty ( partName ) )
85138 {
86139 throw new ArgumentNullException ( nameof ( partName ) ) ;
87140 }
88- return _parts . Remove ( partName ) ;
141+ return _parts . Remove ( ( partName , fileName ?? "" ) ) ;
89142 }
90143
91- private readonly Dictionary < string , Part > _parts = new Dictionary < string , Part > ( StringComparer . OrdinalIgnoreCase ) ;
144+ private readonly Dictionary < ValueTuple < string , string > , Part > _parts = new Dictionary < ValueTuple < string , string > , Part > ( new ValueTupleComparer ( ) ) ;
92145 /// <inheritdoc />
93146 public IDictionary < string , Action < IParseNode > > GetFieldDeserializers ( ) => throw new NotImplementedException ( ) ;
94147 private const char DoubleQuote = '"' ;
@@ -196,4 +249,20 @@ private sealed class Part(string name, object content, string contentType, strin
196249 public string ContentType { get ; } = contentType ;
197250 public string ? FileName { get ; } = fileName ;
198251 }
252+
253+ private sealed class ValueTupleComparer : IEqualityComparer < ValueTuple < string , string > >
254+ {
255+ public bool Equals ( ( string , string ) x , ( string , string ) y )
256+ {
257+ return StringComparer . Ordinal . Equals ( x . Item1 , y . Item1 ) &&
258+ StringComparer . Ordinal . Equals ( x . Item2 , y . Item2 ) ;
259+ }
260+
261+ public int GetHashCode ( ValueTuple < string , string ? > obj )
262+ {
263+ int hash1 = StringComparer . Ordinal . GetHashCode ( obj . Item1 ) ;
264+ int hash2 = obj . Item2 != null ? StringComparer . Ordinal . GetHashCode ( obj . Item2 ) : 0 ;
265+ return hash1 ^ hash2 ;
266+ }
267+ }
199268}
0 commit comments