我最近更新了一个返回XElement
的.ASMX Web服务,但遇到了以下错误消息:
现在,此错误由以下代码生成;
public class FooBarService : System.Web.Services.WebService
{
[WebMethod]
public XElement Foo(string Bar)
{
return null;
}
}
但是,如果我将代码更改为接受XElement
而不是String
;
public class FooBarService : System.Web.Services.WebService
{
[WebMethod]
public XElement Foo(XElement Bar)
{
return null;
}
}
然后Web服务不会抛出错误。
那么为什么接受XElement并返回XElement的方法工作,而不是其他方法?
答案 0 :(得分:3)
开始的地方是堆栈跟踪,它指示发生异常的地方:
at System.Xml.Serialization.XmlSchemaExporter.ExportElement(ElementAccessor accessor)
at System.Xml.Serialization.XmlSchemaExporter.ExportTypeMapping(XmlTypeMapping xmlTypeMapping)
at System.Web.Services.Description.MimeXmlReflector.ReflectReturn()
at System.Web.Services.Description.HttpProtocolReflector.ReflectMimeReturn()
at System.Web.Services.Description.HttpPostProtocolReflector.ReflectMethod()
通过使用ILSpy,我们可以观察触发异常的条件:
// System.Xml.Serialization.XmlSchemaExporter
private XmlSchemaElement ExportElement(ElementAccessor accessor)
{
if (!accessor.Mapping.IncludeInSchema && !accessor.Mapping.TypeDesc.IsRoot)
{
return null;
}
if (accessor.Any && accessor.Name.Length == 0)
{
throw new InvalidOperationException(Res.GetString("XmlIllegalWildcard"));
}
// truncated method body
}
进一步浏览代码:
// System.Web.Services.Description.MimeXmlReflector
internal override bool ReflectReturn()
// System.Xml.Serialization.XmlReflectionImporter
private ElementAccessor
ImportElement(TypeModel model,
XmlRootAttribute root,
string defaultNamespace,
RecursionLimiter limiter)
等等,我们采用这种方法:
// System.Xml.Serialization.XmlReflectionImporter
private static ElementAccessor
CreateElementAccessor(TypeMapping mapping, string ns)
{
ElementAccessor elementAccessor = new ElementAccessor();
bool flag = mapping.TypeDesc.Kind == TypeKind.Node;
if (!flag && mapping is SerializableMapping)
{
flag = ((SerializableMapping)mapping).IsAny;
}
if (flag)
{
elementAccessor.Any = true;
}
else
{
elementAccessor.Name = mapping.DefaultElementName;
elementAccessor.Namespace = ns;
}
// truncated
}
XElement
类型映射似乎将Any
属性值设置为true
,但未获得DefaultElementName
。
该问题的一个简单解决方法是创建派生类:
public class FooBarService : System.Web.Services.WebService
{
[WebMethod]
public MyXElement Foo(string bar)
{
return null;
}
}
public class MyXElement : XElement
{
public MyXElement()
: base(XName.Get("default")) { }
}
将在堆栈中调用:
System.Web.Services.Description.SoapProtocolReflector.ReflectMethod()
代替HttpPostProtocolReflector.ReflectMethod()
方法,并正确分配名称:
messagePart.Name = members[0].MemberName;
要回答您的问题,在将XElement
指定为参数时,方法调用的工作原因是因为类型映射是通过其他方法创建的,而name
成员不为空。因此,不会发生引发异常的条件。