Skip to content

Commit

Permalink
try fix #195
Browse files Browse the repository at this point in the history
  • Loading branch information
kotov.a committed Mar 22, 2019
1 parent b64ab00 commit 344325a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 46 deletions.
117 changes: 73 additions & 44 deletions src/SoapCore/MetaWCFBodyWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class MetaWCFBodyWriter : BodyWriter
private const string TRANSPORT_SCHEMA = "http://schemas.xmlsoap.org/soap/http";
private const string ARRAYS_NS = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
private const string SYSTEM_NS = "http://schemas.datacontract.org/2004/07/System";
private const string DataContraceNamespace = "http://schemas.datacontract.org/2004/07/";
private const string DataContractNamespace = "http://schemas.datacontract.org/2004/07/";
private const string SERIALIZATION_NS = "http://schemas.microsoft.com/2003/10/Serialization/";
#pragma warning restore SA1310 // Field names must not contain underscore

Expand Down Expand Up @@ -108,24 +108,54 @@ protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
AddService(writer);
}

private string GetModelNamespace(Type type)
private static string GetModelNamespace(string @namespace)
{
if (type != null && type.Namespace != _service.ServiceType.Namespace)
if (@namespace.StartsWith("http"))
{
return $"{DataContraceNamespace}{type.Namespace}";
return @namespace;
}

return $"{DataContraceNamespace}{_service.ServiceType.Namespace}";
return $"{DataContractNamespace}{@namespace}";
}

private string GetModelNamespace(string @namespace)
private static string GetDataContractNamespace(Type type)
{
if (@namespace.StartsWith("http"))
if (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type))
{
return @namespace;
type = type.IsArray ? type.GetElementType() : GetGenericType(type);
}

var dataContractAttribute = type.GetCustomAttribute<DataContractAttribute>();
if (dataContractAttribute != null && !string.IsNullOrEmpty(dataContractAttribute.Namespace))
{
return dataContractAttribute.Namespace;
}

return $"{DataContraceNamespace}{@namespace}";
return GetModelNamespace(type.Namespace);
}

private static Type GetGenericType(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();
}

private string GetModelNamespace(Type type)
{
if (type != null && type.Namespace != _service.ServiceType.Namespace)
{
return $"{DataContractNamespace}{type.Namespace}";
}

return $"{DataContractNamespace}{_service.ServiceType.Namespace}";
}

private void WriteParameters(XmlDictionaryWriter writer, SoapMethodParameterInfo[] parameterInfos)
Expand All @@ -151,12 +181,41 @@ private void AddOperations(XmlDictionaryWriter writer)
_namespaceCounter = 1;

//discovery all parameters types which namespaceses diff with service namespace
var namespaces = _service.Operations.SelectMany(x => x.AllParameters.Where(parameter => parameter.Parameter.ParameterType.Namespace != _service.ServiceType.Namespace && parameter.Parameter.ParameterType.Namespace != "System")).Select(x => x.Parameter.ParameterType.Namespace);
foreach (var operation in _service.Operations)
{
foreach (var parameter in operation.AllParameters)
{
var type = parameter.Parameter.ParameterType;
var typeInfo = type.GetTypeInfo();
if (typeInfo.IsByRef)
{
type = typeInfo.GetElementType();
}

_complexTypeToBuild[type] = GetDataContractNamespace(type);

foreach (var @namespace in namespaces.Distinct())
DiscoveryTypesByProperties(type, true);
}

if (operation.DispatchMethod.ReturnType != typeof(void))
{
var returnType = operation.DispatchMethod.ReturnType;
if (returnType.IsConstructedGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
{
returnType = returnType.GetGenericArguments().First();
}

_complexTypeToBuild[returnType] = GetDataContractNamespace(returnType);
DiscoveryTypesByProperties(returnType, true);
}
}

var groupedByNamespace = _complexTypeToBuild.GroupBy(x => x.Value).ToDictionary(x => x.Key, x => x.Select(k => k.Key));

foreach (var @namespace in groupedByNamespace.Keys.Where(x => x != null && x != _service.ServiceType.Namespace).Distinct())
{
writer.WriteStartElement("xs:import");
writer.WriteAttributeString("namespace", DataContraceNamespace + @namespace);
writer.WriteAttributeString("namespace", @namespace);
writer.WriteEndElement();
}

Expand Down Expand Up @@ -510,22 +569,6 @@ private void DiscoveryTypesByProperties(Type type, bool isRootType)
}
}

private string GetDataContractNamespace(Type type)
{
if (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type))
{
type = type.IsArray ? type.GetElementType() : GetGenericType(type);
}

var dataContractAttribute = type.GetCustomAttribute<DataContractAttribute>();
if (dataContractAttribute != null && !string.IsNullOrEmpty(dataContractAttribute.Namespace))
{
return dataContractAttribute.Namespace;
}

return GetModelNamespace(type.Namespace);
}

private void WriteEnum(XmlDictionaryWriter writer, Type type)
{
if (type.IsByRef)
Expand Down Expand Up @@ -962,7 +1005,7 @@ private void WriteComplexElementType(XmlDictionaryWriter writer, string typeName
{
var ns = $"q{_namespaceCounter++}";
writer.WriteAttributeString("type", $"{ns}:{typeName}");
writer.WriteAttributeString($"xmlns:{ns}", GetModelNamespace(type));
writer.WriteAttributeString($"xmlns:{ns}", GetDataContractNamespace(type));
}
else
{
Expand Down Expand Up @@ -990,27 +1033,13 @@ private string GetTypeName(Type type)
#pragma warning restore SA1008 // Opening parenthesis must be spaced correctly
#pragma warning restore SA1009 // Closing parenthesis must be spaced correctly

private Type GetGenericType(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();
}

private bool HasBaseType(Type type)
{
var isArrayType = type.IsArray || typeof(IEnumerable).IsAssignableFrom(type);

var baseType = type.GetTypeInfo().BaseType;

return !isArrayType && !type.IsEnum && !type.IsPrimitive && baseType != null && !baseType.Name.Equals("Object") && baseType.FullName != typeof(ValueType).FullName;
return !isArrayType && !type.IsEnum && !type.IsPrimitive && !type.IsValueType && baseType != null && !baseType.Name.Equals("Object");
}
}
}
9 changes: 8 additions & 1 deletion src/SoapCore/OperationDescription.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Threading.Tasks;
using System.Xml.Serialization;
Expand Down Expand Up @@ -75,7 +76,13 @@ private static SoapMethodParameterInfo CreateParameterInfo(ParameterInfo info, i
info.GetCustomAttribute<MessageParameterAttribute>()?.Name ??
info.ParameterType.GetCustomAttribute<MessageContractAttribute>()?.WrapperName ??
info.Name;
var parameterNs = elementAttribute?.Namespace ?? contract.Namespace;
var parameterNs = elementAttribute?.Namespace;
var dataContractAttribute = info.ParameterType.GetCustomAttribute<DataContractAttribute>();
if (dataContractAttribute != null && dataContractAttribute.IsNamespaceSetExplicitly)
{
parameterNs = dataContractAttribute.Namespace;
}

return new SoapMethodParameterInfo(info, index, parameterName, parameterNs);
}

Expand Down
3 changes: 2 additions & 1 deletion src/SoapCore/SoapEndpointMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ private object[] GetRequestArguments(Message requestMessage, System.Xml.XmlDicti
foreach (var parameterInfo in operation.InParameters)
{
var parameterName = parameterInfo.Name;
var parameterNs = parameterInfo.Namespace;

var parameterNs = parameterInfo.Namespace ?? operation.Contract.Namespace;

if (xmlReader.IsStartElement(parameterName, parameterNs))
{
Expand Down

1 comment on commit 344325a

@bhenden
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something in this commit broke my service. My method accepts a model without namespace as parameter, and this is always null after this commit. Not sure exactly why yet, but I will try to investigate further.

Please sign in to comment.