2013-07-05 273 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