2013-07-05 224 views
2

我最近更新.ASMX Web服务在其被返回一个XElement和跨越此错误消息来返回一个的XElement:从.ASMX Web服务

Cannot use wildcards at the top level of a schema

,如今更是产生这个错误下面的代码;

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

相关问题在这里; http://stackoverflow.com/questions/349769/returning-an-xelement-from-a-web-service - 似乎它可能是一个错误? –

+0

@ChrisMcAtackney是的,我已经读过这个问题,这个链接是从其中一个答案中断开的,其余的并没有解决问题。 –

+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) 

a第二等等,我们得到这个方法:

// 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类型映射获取设置为trueAny属性值,但没有得到一个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成员不为空。所以引发异常的情况不会发生。

+0

这是一个很好的答案,谢谢!也感谢您对这个问题的调查! –

+0

当我尝试使用在VS2010中使用Web引用接受&返回MyXElement的服务时,它会创建DataSet类型化参数和返回类型。你如何使用XElement? – xr280xr