diff --git a/src/SoapCore.Tests/Wsdl/Services/IGenericDataContractService.cs b/src/SoapCore.Tests/Wsdl/Services/IGenericDataContractService.cs new file mode 100644 index 00000000..cb975484 --- /dev/null +++ b/src/SoapCore.Tests/Wsdl/Services/IGenericDataContractService.cs @@ -0,0 +1,35 @@ +using System; +using System.Runtime.Serialization; +using System.ServiceModel; + +namespace SoapCore.Tests.Wsdl.Services +{ + [ServiceContract] + public interface IGenericDataContractService + { + [OperationContract] + GenericDataContractService.MyType TestString(); + + [OperationContract] + GenericDataContractService.MyType TestMyArg(); + } + + public class GenericDataContractService : IGenericDataContractService + { + public MyType TestString() => throw new NotImplementedException(); + + public MyType TestMyArg() => throw new NotImplementedException(); + + [DataContract(Name = "My{0}Type", Namespace = "http://testnamespace.org")] + public class MyType + { + [DataMember] + public T Value { get; set; } + } + + public class MyArg + { + public string Value { get; set; } + } + } +} diff --git a/src/SoapCore.Tests/Wsdl/WsdlTests.cs b/src/SoapCore.Tests/Wsdl/WsdlTests.cs index 7017baa7..c0ac4010 100644 --- a/src/SoapCore.Tests/Wsdl/WsdlTests.cs +++ b/src/SoapCore.Tests/Wsdl/WsdlTests.cs @@ -426,6 +426,26 @@ public void CheckCollectionDataContract() Assert.IsNotNull(myMyTypeElement); } + [TestMethod] + public void CheckGenericDataContract() + { + StartService(typeof(GenericDataContractService)); + var wsdl = GetWsdl(); + StopServer(); + + var root = XElement.Parse(wsdl); + + var stringResult = GetElements(root, _xmlSchema + "element").SingleOrDefault(a => a.Attribute("name")?.Value.Equals("TestStringResult") == true); + Assert.IsNotNull(stringResult); + Assert.AreEqual("http://testnamespace.org", stringResult.Attribute(XNamespace.Xmlns + "q1").Value); + Assert.AreEqual("q1:MystringType", stringResult.Attribute("type").Value); + + var myTypeResult = GetElements(root, _xmlSchema + "element").SingleOrDefault(a => a.Attribute("name")?.Value.Equals("TestMyArgResult") == true); + Assert.IsNotNull(myTypeResult); + Assert.AreEqual("http://testnamespace.org", myTypeResult.Attribute(XNamespace.Xmlns + "q2").Value); + Assert.AreEqual("q2:MyMyArgType", myTypeResult.Attribute("type").Value); + } + [TestMethod] public void CheckDictionaryTypeDataContract() { diff --git a/src/SoapCore/Meta/MetaWCFBodyWriter.cs b/src/SoapCore/Meta/MetaWCFBodyWriter.cs index abc7821d..d34e5264 100644 --- a/src/SoapCore/Meta/MetaWCFBodyWriter.cs +++ b/src/SoapCore/Meta/MetaWCFBodyWriter.cs @@ -1554,14 +1554,34 @@ private void WriteComplexElementType(XmlDictionaryWriter writer, string typeName private string GetTypeName(Type type) { + var dataContractAttribute = type.GetCustomAttribute(); + if (type.IsGenericType && !type.IsArray && !typeof(IEnumerable).IsAssignableFrom(type)) { - var genericTypes = GetGenericTypes(type); - var genericTypeNames = genericTypes.Select(a => GetTypeName(a)); + if (dataContractAttribute != null && dataContractAttribute.IsNameSetExplicitly) + { + var typeName = dataContractAttribute.Name; + var genericTypes = GetGenericTypes(type); + var genericTypeNames = genericTypes + .Select(genericType => + { + var (name, _) = ResolveSystemType(genericType); + return string.IsNullOrEmpty(name) ? GetTypeName(genericType) : name; + }) + .ToArray(); + + typeName = string.Format(typeName, genericTypeNames); + return typeName; + } + else + { + var genericTypes = GetGenericTypes(type); + var genericTypeNames = genericTypes.Select(a => GetTypeName(a)); - var typeName = ReplaceGenericNames(type.Name); - typeName = typeName + "Of" + string.Concat(genericTypeNames); - return typeName; + var typeName = ReplaceGenericNames(type.Name); + typeName = typeName + "Of" + string.Concat(genericTypeNames); + return typeName; + } } if (type.IsArray) @@ -1598,7 +1618,6 @@ private string GetTypeName(Type type) } // Make use of DataContract attribute, if set, as it may contain a Name override - var dataContractAttribute = type.GetCustomAttribute(); if (dataContractAttribute != null && dataContractAttribute.IsNameSetExplicitly) { return dataContractAttribute.Name;