Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
kotov.a committed Jun 15, 2020
2 parents 05d539d + 650e5fa commit 52eb146
Show file tree
Hide file tree
Showing 10 changed files with 533 additions and 161 deletions.
19 changes: 19 additions & 0 deletions src/SoapCore.Tests/Wsdl/Services/IStringListService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;

namespace SoapCore.Tests.Wsdl.Services
{
[ServiceContract]
public interface IStringListService
{
[OperationContract]
List<string> Test();
}

public class StringListService : IStringListService
{
public List<string> Test() => throw new NotImplementedException();
}
}
86 changes: 86 additions & 0 deletions src/SoapCore.Tests/Wsdl/Services/XmlModelsService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Xml.Serialization;

namespace SoapCore.Tests.Wsdl.Services
{
#pragma warning disable SA1649 // File name should match first type name
#pragma warning disable SA1402 // File may only contain a single type
[ServiceContract(Namespace = "http://bagov.net/")]
public interface IXmlModelsService
{
[OperationContract]
TestResponseType GetResponse(TestRequestType request);
}

public class XmlModelsService : IXmlModelsService
{
public TestResponseType GetResponse(TestRequestType request)
{
return new TestResponseType();
}
}

[SerializableAttribute]
[XmlRoot("RequestRoot", Namespace = "http://bagov.net/", IsNullable = false)]
public class TestRequestType
{
[XmlAttributeAttribute]
public string PropRoot { get; set; }

[XmlIgnore]
public string PropIgnore { get; set; }
}

[SerializableAttribute]
[XmlRoot("ResponseRoot", Namespace = "http://bagov.net/", IsNullable = false)]
public class TestResponseType
{
public TestResponseType()
{
DataList = new List<TestDataTypeData>();
}

[System.Xml.Serialization.XmlArrayItemAttribute("Data", IsNullable = false)]
public List<TestDataTypeData> DataList { get; set; }

[System.Xml.Serialization.XmlArrayItemAttribute("Data2")]
public List<TestDataTypeData> DataList2 { get; set; }

[System.Xml.Serialization.XmlArrayItemAttribute("Data")]
public List<TestDataTypeData> DataList3 { get; set; }

[System.Xml.Serialization.XmlElementAttribute("Data3")]
[DataMember]
public List<TestDataTypeData2> Data { get; set; }

[XmlAttributeAttribute]
public string PropRoot { get; set; }

[XmlIgnore]
public string PropIgnore { get; set; }
}

[Serializable]
[XmlType(AnonymousType=true)]
public class TestDataTypeData
{
[XmlAttributeAttribute]
public string PropAnonymous { get; set; }
}

[Serializable]
[XmlType(AnonymousType=true)]
[DataContract]
public class TestDataTypeData2
{
[XmlAttributeAttribute]
[DataMember]
public string PropAnonymous { get; set; }
}
}

#pragma warning restore SA1649 // File name should match first type name
#pragma warning restore SA1402 // File may only contain a single type
83 changes: 69 additions & 14 deletions src/SoapCore.Tests/Wsdl/WsdlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -205,6 +206,42 @@ public void CheckCollectionDataContract()
Assert.IsNotNull(myMyTypeElement);
}

[TestMethod]
public async Task CheckStringArrayNameWsdl()
{
//StartService(typeof(StringListService));
//var wsdl = GetWsdl();
//StopServer();
var wsdl = await GetWsdlFromMetaBodyWriter<StringListService>();
Trace.TraceInformation(wsdl);
Assert.IsNotNull(wsdl);

var root = XElement.Parse(wsdl);

// Check complexType exists for xmlserializer meta
var testResultElement = GetElements(root, _xmlSchema + "element").SingleOrDefault(a => a.Attribute("type") != null && a.Attribute("name")?.Value.Equals("TestResult") == true);
Assert.IsNotNull(testResultElement);

// Now check if we can match the array type up with it's decleration
var split = testResultElement.Attribute("type").Value.Split(':');
var typeNamespace = testResultElement.GetNamespaceOfPrefix(split[0]);

var matchingSchema = GetElements(root, _xmlSchema + "schema").Where(schema => schema.Attribute("targetNamespace")?.Value.Equals(typeNamespace.NamespaceName) == true);
Assert.IsTrue(matchingSchema.Count() > 0);

var matched = false;
foreach (var schema in matchingSchema)
{
var matchingElement = GetElements(schema, _xmlSchema + "element").SingleOrDefault(a => a.Attribute("name")?.Value.Equals(split[1]) == true);
if (matchingElement != null)
{
matched = true;
}
}

Assert.IsTrue(matched);
}

[TestMethod]
public async Task CheckDateTimeOffsetServiceWsdl()
{
Expand All @@ -230,25 +267,43 @@ public async Task CheckTestMultipleTypesServiceWsdl()
}

[TestMethod]
public void CheckSchemaObjectWithArrayService()
public async Task CheckXmlAnnotatedTypeServiceWsdl()
{
StartService(typeof(ObjectWithArrayService));
var wsdl = GetWsdl();
StopServer();
var wsdl = await GetWsdlFromMetaBodyWriter<XmlModelsService>();
Trace.TraceInformation(wsdl);
Assert.IsNotNull(wsdl);

Assert.IsFalse(wsdl.Contains("name=\"\""));

var root = XElement.Parse(wsdl);
var elementsWithEmptyName = GetElements(root, _xmlSchema + "element").Where(x => x.Attribute("name")?.Value == string.Empty);
elementsWithEmptyName.ShouldBeEmpty();
var nm = Namespaces.CreateDefaultXmlNamespaceManager();

var elementsWithEmptyType = GetElements(root, _xmlSchema + "element").Where(x => x.Attribute("type")?.Value == "xs:");
elementsWithEmptyType.ShouldBeEmpty();
var requestTypeElement = root.XPathSelectElement("//xsd:element[@name='RequestRoot']", nm);
Assert.IsNotNull(requestTypeElement);

var reponseTypeElement = root.XPathSelectElement("//xsd:element[@name='ResponseRoot']", nm);
Assert.IsNotNull(reponseTypeElement);

var referenceToExistingDynamicType = root.XPathSelectElement("//xsd:complexType[@name='TestResponseType']/xsd:sequence/xsd:element[@name='DataList3' and @type='tns:ArrayOfTestDataTypeData']", nm);
Assert.IsNotNull(referenceToExistingDynamicType);

var selfContainedType = root.XPathSelectElement("//xsd:complexType[@name='TestResponseType']/xsd:sequence/xsd:element[@name='Data' and @minOccurs='0'and @maxOccurs='unbounded' and not(@type)]", nm);
Assert.IsNotNull(selfContainedType);

var dynamicTypeElement = root.XPathSelectElement("//xsd:complexType[@name='ArrayOfTestDataTypeData']/xsd:sequence/xsd:element[@name='Data']", nm);
Assert.IsNotNull(dynamicTypeElement);

var dynamicTypeElement2 = root.XPathSelectElement("//xsd:complexType[@name='ArrayOfTestDataTypeData1']/xsd:sequence/xsd:element[@name='Data2']", nm);
Assert.IsNotNull(dynamicTypeElement2);

var propRootAttribute = root.XPathSelectElement("//xsd:attribute[@name='PropRoot']", nm);
Assert.IsNotNull(propRootAttribute);

var elementsWithEmptyComplexType = GetElements(root, _xmlSchema + "element").Where(x => x.Attribute("type")?.Value == "tns:");
elementsWithEmptyComplexType.ShouldBeEmpty();
var propIgnoreAttribute = root.XPathSelectElement("//xsd:attribute[@name='PropIgnore']", nm);
Assert.IsNull(propIgnoreAttribute);

var typeWithArrayElement = GetElements(root, _xmlSchema + "complexType").Single(x => x.Attribute("name")?.Value == "ArrayOfMyClass");
var typeDescriptionElements = GetElements(root, _xmlSchema + "element").Where(x => x.Attribute("name")?.Value == "MyClass");
Assert.IsNotNull(typeWithArrayElement);
Assert.AreEqual(typeDescriptionElements.Count(), 2);
var propAnonAttribute = root.XPathSelectElement("//xsd:attribute[@name='PropAnonymous']", nm);
Assert.IsNotNull(propAnonAttribute);
}

[TestCleanup]
Expand Down
76 changes: 74 additions & 2 deletions src/SoapCore/Meta/BodyWriterExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
Expand Down Expand Up @@ -117,6 +118,77 @@ public static bool TryAddSchemaTypeFromXmlSchemaProviderAttribute(this XmlDictio
return false;
}

public static bool IsAttribute(this PropertyInfo property)
{
var attributeItem = property.GetCustomAttribute<XmlAttributeAttribute>();
return attributeItem != null;
}

public static bool IsIgnored(this PropertyInfo property)
{
return property
.CustomAttributes
.Any(attr =>
attr.AttributeType == typeof(IgnoreDataMemberAttribute) ||
attr.AttributeType == typeof(XmlIgnoreAttribute));
}

public static bool IsEnumerableType(this Type collectionType)
{
if (collectionType.IsArray)
{
return true;
}

return typeof(IEnumerable).IsAssignableFrom(collectionType);
}

public static Type GetGenericType(this Type collectionType)
{
// Recursively look through the base class to find the Generic Type of the Enumerable
var baseType = collectionType;
var baseTypeInfo = collectionType.GetTypeInfo();
while (!baseTypeInfo.IsGenericType && baseTypeInfo.BaseType != null)
{
baseType = baseTypeInfo.BaseType;
baseTypeInfo = baseType.GetTypeInfo();
}

return baseType.GetTypeInfo().GetGenericArguments().DefaultIfEmpty(typeof(object)).FirstOrDefault();
}

public static string GetSerializedTypeName(this Type type)
{
var namedType = type;
if (type.IsArray)
{
namedType = type.GetElementType();
}
else if (typeof(IEnumerable).IsAssignableFrom(type) && type.IsGenericType)
{
namedType = GetGenericType(type);
}

string typeName = namedType.Name;
var xmlTypeAttribute = namedType.GetCustomAttribute<XmlTypeAttribute>(true);
if (xmlTypeAttribute != null && !string.IsNullOrWhiteSpace(xmlTypeAttribute.TypeName))
{
typeName = xmlTypeAttribute.TypeName;
}

if (type.IsArray)
{
typeName = "ArrayOf" + typeName.Replace("[]", string.Empty);
}

if (typeof(IEnumerable).IsAssignableFrom(type) && type.IsGenericType)
{
typeName = "ArrayOf" + typeName;
}

return typeName;
}

private static XmlSerializerNamespaces Convert(this XmlNamespaceManager xmlNamespaceManager)
{
XmlSerializerNamespaces xmlSerializerNamespaces = new XmlSerializerNamespaces();
Expand Down
Loading

0 comments on commit 52eb146

Please sign in to comment.