如何返回具有通用属性的 C# Web 服务?

Posted

技术标签:

【中文标题】如何返回具有通用属性的 C# Web 服务?【英文标题】:How do I return a C# web service that has a generic property? 【发布时间】:2013-04-08 23:55:02 【问题描述】:

我正在创建一个 Web 服务,并且希望在返回数据方面更加优雅,而不是让消费者需要检查大量属性。

根据幕后生成的数据,我需要能够返回错误数据,或者消费者期望的数据。

我不想拥有一个大的平面对象,并在需要时填充属性并让用户检查“成功”标志,而是希望单个属性 Data 成为错误类的实例,或者一个成功类的实例。

这就是我想做的事情:

class ItemResponse

    public bool Success  get; set; 
    public T Data get; set; 


if( /*acceptance criteria*/ )

    ItemResponse<SuccessData> resp = new ItemResponse<SuccessData>();
    resp.Data = new SuccessData();

else

    ItemResponse<ErrorData> resp = new ItemResponse<ErrorData>();
    resp.Data = new ErrorData();


return resp;


public class SuccessData




public class ErrorData



然后让 web 方法返回具有通用属性的对象。

这可能吗?如果可以,鉴于必须正确输入 webmethod 返回类型,我该怎么做?

【问题讨论】:

您是否可以控制使用此服务的代码?你能流式传输结果吗?使用 JSON? 我不会成为消费者,不。结果需要保留为 xml。 Web 服务基本上是一个公开为 XML 的函数。由于一个函数不能有不同的类型,我不认为这是可以的。有一个具有一个属性的超类并有两个子类但不确定是否允许这样做会很有趣 我很确定我以前见过这种做法,但我没有任何代码可以参考或验证它是否符合我的想法。本质上,消费者检查了成功标志,然后根据值是什么来转换 Data 属性。 【参考方案1】:

泛型是在编译时添加类型安全的工具。因此,类的使用者使用的具体类型必须在编译时知道。如果你创建一个函数

List<T> myFunction<T>() ...

...那么你需要在调用时指定T,例如

var myResult = myFunction<int>();

...这使得在编译时知道具体类型。 (即使你没有指定T,因为它可以被推断出来,具体类型在编译时也是知道的。)

但是,您希望在run-time 确定Data 的泛型类型:如果发生错误,则返回ItemResponse&lt;SuccessData&gt;,否则返回ItemResponse&lt;ErrorData&gt;。泛型不是这样工作的。

【讨论】:

谢谢。当我试图通过它的逻辑工作时,感觉有些不对劲。这里的所有答案都证实了这一点。【参考方案2】:

短版,你不能按照你的建议去做。

加长版 A部分

可以将 Web 服务视为类的方法,实际上 Web 服务类的方法。我建议阅读一些 Web 服务教程,以便更好地掌握设置 Web 服务背后的机制。 MSDN 有许多特定于 Microsoft 堆栈的教程,可通过您最喜欢的搜索引擎轻松找到。

方法的返回对象不允许具有多态行为,这本质上是您所要求的。

此伪代码等同于您尝试创建的代码,这就是编译器不允许它的原因。它不知道哪个您正在尝试呼叫DoSomething()

class myFoo

     public SuccessResponse DoSomething() ....  
     public ErrorResponse DoSomething() ....

或者,您可以设想这样的事情:public [SuccessResponse | ErrorResponse] DoSomething() 但这也因显而易见的原因而失败。 C# 根本不支持多态返回。

B 部分 即使我们只关注resp.Data,该对象仍然必须声明为某种类型。

class Response

     public Collection<someType> Data;

如果您的SuccessDataErrorData 实现相同的接口,那么someType 可能只是IyourInterface,但这会引发另一个问题。也就是说,最终用户如何知道他们是否在Data 中获得了良好的数据,或者那里是否存在错误响应。

我相信,只要您将其声明为 WCF 服务对象的公共部分,WCF 就足以为您序列化 IyourInterface。但这仍然不能解决您的最终用户如何知道该做什么。


如果您愿意在响应中不那么优雅,经典模式是将成功数据和错误对象简单地捆绑到另一个响应类中,如下所示:

class myResponse

    public SuccessResponse myRespData;
    public ErrorResponse myError

现在,最终用户会检查是否存在错误,如果他们关心的话。假设没有错误,然后他们去查看响应数据。


根据您的评论,是的,您也可以执行以下操作:

class Response

    public List<IYourData> Data;
    public YourEnum ReturnType;


public class ResponseData : IYourData  ...   
public class ErrorData : IYourData  ...   

然后在客户端,你可以像这样执行一个简单的检查:

if( ReturnType == YourEnum.Success )  ...   
else if( ReturnType == YourEnum.Error )  ...   
else ... 

WCF 将为您处理List 的序列化。它将转换为数组或直接传递集合,具体取决于您的设置。有一些 SO Q&A 可以处理该特定方面。

【讨论】:

“基本上,消费者检查了成功标志,然后根据值是什么来转换 Data 属性。” - 这就是我认为我看到的例子所做的。我认为为简单起见,最好有两个对象,消费者可以先检查是否存在错误响应。使用它就不需要解释了。也许我之前看到的(它必须使用实现相同的接口用法)是矫枉过正和过度工程。出于兴趣,你能展示一下它是如何工作的吗?感谢您写得很好。 @GlenH7 - 我进行了编辑以修复您遇到的格式问题。您可以通过缩进四个空格来显示代码,然后所有像&lt;&gt;这样的特殊符号都会显示出来,并尝试语法着色。 @Bobson 谢谢!我仍然在这方面挣扎...... 我觉得你也可以用&lt;code&gt;标签代替&lt;pre&gt;标签,不过我不肯定。 @Bobson - 在我对 P.SE 的编辑中(在迁移中死亡)我试图使用 &lt;code&gt; 标签,它允许 &lt;&gt; 正确显示,但它尽管使用了&lt;!-- language: c# --&gt;&lt;!-- language: lang-cs --&gt; 标签,但没有显示代码格式。显然我需要更多练习在 StackExchange 上编写代码...

以上是关于如何返回具有通用属性的 C# Web 服务?的主要内容,如果未能解决你的问题,请参考以下文章

C#返回具有匹配属性的对象列表[重复]

从 C# .NET Core(特别是 Workday)调用 Java Web 服务。如何在soap请求中获取xml属性

如何从轴 Web 服务返回复杂对象

制作通用属性

如何通过 AutoMapper 实现具有通用 Queue 类型属性的对象映射

Exchange Web 服务 - 如何使用 Account 扩展属性检索联系人