C# 从.ASMX Web服务返回XElement

C# 从.ASMX Web服务返回XElement,c#,asp.net,web-services,C#,Asp.net,Web Services,我最近更新了一个.ASMX Web服务,其中返回了一个XElement,并遇到以下错误消息: 现在这个错误是由以下代码产生的: public class FooBarService : System.Web.Services.WebService { [WebMethod] public XElement Foo(string Bar) { return null; } } 但是,如果我将代码更改为接受XElem

我最近更新了一个.ASMX Web服务,其中返回了一个
XElement
,并遇到以下错误消息:

现在这个错误是由以下代码产生的:

public class FooBarService : System.Web.Services.WebService
{            
    [WebMethod]
    public XElement Foo(string Bar)
    {
        return null;
    }    
}
但是,如果我将代码更改为接受
XElement
而不是
字符串

public class FooBarService : System.Web.Services.WebService
{        
    [WebMethod]
    public XElement Foo(XElement Bar)
    {
        return null;
    }
}
然后Web服务不会抛出错误


那么,为什么一个接受XElement并返回XElement的方法有效,而另一个方法无效呢?

从堆栈跟踪开始,它指示异常发生的位置:

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()
通过使用,我们可以观察触发异常的条件:

// 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
成员不是空的。因此引发异常的条件不会发生。

此处的相关问题;-似乎这可能是个bug?@ChrisMcAtackney是的,我已经看完了这个问题,其中一个答案的链接断了,其余的都没有说明问题。为什么不返回一个字符串呢?因为我不想:P我想知道这为什么不起作用。这是一个很好的答案,谢谢!也感谢您对这个问题进行调查!当我尝试使用VS2010中使用Web引用接受并返回MyXElement的服务时,它会创建数据集类型的参数和返回类型。你如何让它使用XElement?