Skip to content

Commit 0d63be1

Browse files
Merge pull request #1155 from xeeqqw/xeeqqw/fix-generic-type-wsdl-serializer
fixed generic type serialization in GetSerializedTypeName
2 parents 1368ea6 + 834aeb4 commit 0d63be1

5 files changed

Lines changed: 150 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace SoapCore.Tests.Wsdl.Services;
2+
3+
public class ComplexTypeWithGeneric
4+
{
5+
public int Id { get; set; }
6+
7+
public InnerGenericTypeWithSingleArgument<InnerType> SingleGenericArgument { get; set; }
8+
9+
public InnerGenericTypeWithMultipleArguments<InnerType, InnerType> MultipleGenericArguments { get; set; }
10+
11+
public class InnerGenericTypeWithSingleArgument<T>
12+
where T : class
13+
{
14+
}
15+
16+
public class InnerGenericTypeWithMultipleArguments<T, TK>
17+
where T : class
18+
where TK : class
19+
{
20+
}
21+
22+
public class InnerType
23+
{
24+
public string Text { get; set; }
25+
}
26+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace SoapCore.Tests.Wsdl.Services;
2+
3+
public class ComplexTypeWithMultipleGenericArguments
4+
{
5+
public int Id { get; set; }
6+
7+
public InnerGenericType<InnerType, InnerType> InnerObject { get; set; }
8+
9+
public class InnerGenericType<T, TK>
10+
where T : class
11+
where TK : class
12+
{
13+
}
14+
15+
public class InnerType
16+
{
17+
public string Text { get; set; }
18+
}
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.ServiceModel;
3+
4+
namespace SoapCore.Tests.Wsdl.Services
5+
{
6+
[ServiceContract]
7+
public interface IComplexGenericTypeService
8+
{
9+
[OperationContract]
10+
void Test(ComplexTypeWithGeneric model);
11+
}
12+
13+
public class ComplexGenericTypeService : IComplexGenericTypeService
14+
{
15+
public void Test(ComplexTypeWithGeneric model) => throw new NotImplementedException();
16+
}
17+
}

src/SoapCore.Tests/Wsdl/WsdlTests.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,52 @@ public async Task CheckComplexAnonymousTypeListWsdl(SoapSerializer soapSerialize
13611361
Assert.IsNotNull(arrayElementType);
13621362
}
13631363

1364+
[DataTestMethod]
1365+
[DataRow(SoapSerializer.XmlSerializer)]
1366+
public async Task CheckComplexGenericTypeWithSingleArgumentWsdl(SoapSerializer soapSerializer)
1367+
{
1368+
var wsdl = await GetWsdlFromMetaBodyWriter<ComplexGenericTypeService>(soapSerializer);
1369+
Trace.TraceInformation(wsdl);
1370+
Assert.IsNotNull(wsdl);
1371+
1372+
var root = XElement.Parse(wsdl);
1373+
1374+
var endpointInnerObjectTypeArgument = GetElements(root, _xmlSchema + "element")
1375+
.SingleOrDefault(a => a.Attribute("name")?.Value.Equals(nameof(ComplexTypeWithGeneric.SingleGenericArgument)) == true);
1376+
1377+
Assert.IsNotNull(endpointInnerObjectTypeArgument);
1378+
1379+
var typeName = endpointInnerObjectTypeArgument.Attribute("type")?.Value;
1380+
1381+
const string genericTypeName = "InnerGenericTypeWithSingleArgument";
1382+
const string genericTypeArgumentName = "InnerType";
1383+
1384+
Assert.AreEqual($"tns:{genericTypeName}Of{genericTypeArgumentName}", typeName);
1385+
}
1386+
1387+
[DataTestMethod]
1388+
[DataRow(SoapSerializer.XmlSerializer)]
1389+
public async Task CheckComplexGenericTypeWithMultipleArgumentsWsdl(SoapSerializer soapSerializer)
1390+
{
1391+
var wsdl = await GetWsdlFromMetaBodyWriter<ComplexGenericTypeService>(soapSerializer);
1392+
Trace.TraceInformation(wsdl);
1393+
Assert.IsNotNull(wsdl);
1394+
1395+
var root = XElement.Parse(wsdl);
1396+
1397+
var endpointInnerObjectTypeArgument = GetElements(root, _xmlSchema + "element")
1398+
.SingleOrDefault(a => a.Attribute("name")?.Value.Equals(nameof(ComplexTypeWithGeneric.MultipleGenericArguments)) == true);
1399+
1400+
Assert.IsNotNull(endpointInnerObjectTypeArgument);
1401+
1402+
var typeName = endpointInnerObjectTypeArgument.Attribute("type")?.Value;
1403+
1404+
const string genericTypeName = "InnerGenericTypeWithMultipleArguments";
1405+
const string genericTypeArgumentName = "InnerType";
1406+
1407+
Assert.AreEqual($"tns:{genericTypeName}Of{genericTypeArgumentName}{genericTypeArgumentName}", typeName);
1408+
}
1409+
13641410
[TestMethod]
13651411
public void CheckSchemeOverride()
13661412
{

src/SoapCore/Meta/BodyWriterExtensions.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
34
using System.IO;
45
using System.Linq;
56
using System.Reflection;
67
using System.Runtime.Serialization;
8+
using System.Text;
79
using System.Xml;
810
using System.Xml.Schema;
911
using System.Xml.Serialization;
@@ -237,10 +239,32 @@ public static string GetSerializedTypeName(this Type type)
237239

238240
typeName = GetArrayTypeName(typeName.Replace("[]", string.Empty), isNullableArray);
239241
}
242+
else if (isGenericType)
243+
{
244+
typeName = namedType.GetGenericTypeName();
245+
}
240246

241247
return typeName;
242248
}
243249

250+
/// <summary>
251+
/// Returns the name of the type without the generic arity.
252+
/// <example>
253+
/// <c>typeof(List&lt;int&gt;).Name</c> is <c>List`1</c>.
254+
/// <br/>
255+
/// <c>typeof(List&lt;int&gt;).GetNameWithoutGenericArity()</c> is <c>List</c>.
256+
/// </example>
257+
/// </summary>
258+
/// <param name="type">Type</param>
259+
/// <returns>Type name without the generic arity</returns>
260+
public static string GetNameWithoutGenericArity(this Type type)
261+
{
262+
var arityIndex = type.Name.IndexOf('`');
263+
return arityIndex == -1
264+
? type.Name
265+
: type.Name.Substring(0, arityIndex);
266+
}
267+
244268
private static string GetArrayTypeName(string typeName, bool isNullable)
245269
{
246270
return "ArrayOf" + (isNullable ? "Nullable" : null) + (ClrTypeResolver.ResolveOrDefault(typeName) ?? typeName).FirstCharToUpperOrDefault();
@@ -266,5 +290,23 @@ private static string FirstCharToUpperOrDefault(this string input)
266290

267291
return input.First().ToString().ToUpper() + input.Substring(1);
268292
}
293+
294+
private static string GetGenericTypeName(this Type type)
295+
{
296+
var clearName = type.GetNameWithoutGenericArity();
297+
298+
var genericArguments = type.GetGenericArguments();
299+
300+
var sb = new StringBuilder(clearName);
301+
302+
sb.Append("Of");
303+
304+
foreach (var arg in genericArguments)
305+
{
306+
sb.Append(arg.GetNameWithoutGenericArity());
307+
}
308+
309+
return sb.ToString();
310+
}
269311
}
270312
}

0 commit comments

Comments
 (0)