简体   繁体   English

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

[英]How do I return a C# web service that has a generic property?

I am creating a web service, and want to be a bit more elegant with the return data, instead of having lots of properties that the consumer needs to check. 我正在创建一个Web服务,并希望使用返回数据更优雅,而不是拥有消费者需要检查的许多属性。

Depending on what data is generated behind the scenes, I need to be able to return error data, or the data the consumer was expecting. 根据幕后生成的数据,我需要能够返回错误数据或消费者期望的数据。

Instead of having a large flat object, and filling the properties when needed, and letting the user check a 'success' flag, I'd like a single property, Data, to be either an instance of an error class, or an instance of a success class. 我不想拥有一个大的扁平对象,并在需要时填充属性,并让用户检查“成功”标志,我希望单个属性Data可以是错误类的实例,也可以是一个成功的班级。

This is kind of what I want to do: 这就是我想要做的事情:

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
{

}

Then have the web method return the object, with the generic property. 然后让web方法返回带有generic属性的对象。

Is this possible, and if so, how would I do it, given that the webmethod return type has to be typed correctly? 这是可能的,如果是这样,我将如何做,因为必须正确输入webmethod返回类型?

Generics are a tool for adding type safety during compile time . 泛型是在编译期间添加类型安全性的工具。 Consequently, the concrete type used by the consumer of the class must be known at compile time. 因此,必须在编译时知道类的使用者使用的具体类型。 If you create a function 如果您创建一个功能

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

...then you need to specify T when calling it, eg ...然后你需要在调用时指定T ,例如

var myResult = myFunction<int>();

...which makes the concrete type known at compile time. ...使编译时知道具体类型。 (Even if you don't specify T because it can be infered, the concrete type is also known at compile time.) (即使您没有指定T因为它可以被推测,具体类型在编译时也是已知的。)

You, however, want the generic type of Data to be determined at run-time : If an error occured, you return an ItemResponse<SuccessData> , otherwise an ItemResponse<ErrorData> . 但是,您希望在run-time确定通用类型的Data :如果发生错误,则返回ItemResponse<SuccessData> ,否则返回ItemResponse<ErrorData> That's just not how generics work. 这不是泛型如何工作。

Short version , you can't do what you're suggesting as you've laid it out. 简短的版本 ,你不能做你所建议的,因为你已经奠定了它。

Long(er) version Part A : 长(呃)版本 A部分

A web service can be considered like a class' method, and actually is a method off of your web service class. Web服务可以被视为类的方法,实际上 Web服务类的一种方法。 I would recommend going over some web service tutorials in order to get a better grasp of the mechanics behind setting up a web service. 我建议阅读一些Web服务教程,以便更好地掌握设置Web服务背后的机制。 MSDN has a number of Microsoft stack specific tutorials that are easily found with your favorite search engine. MSDN有许多Microsoft堆栈特定教程,可以使用您最喜欢的搜索引擎轻松找到它们。

The return object off of a method is not allowed to have polymorphic behavior, which is essentially what your asking for. 方法的返回对象不允许具有多态行为,这基本上就是您的要求。

This pseudo code is equivalent to what you're trying to create and that's why the compiler isn't allowing it. 这个伪代码等同于您尝试创建的代码,这就是编译器不允许的原因。 It doesn't know which DoSomething() you're attempting to call. 它不知道你试图打电话给哪个 DoSomething()

class myFoo
{
     public SuccessResponse DoSomething() {....}  
     public ErrorResponse DoSomething() {....}
}

Alternatively, you could envisage something like this: 或者,您可以设想这样的事情:
public [SuccessResponse | ErrorResponse] DoSomething()
but that fails for what should be obvious reasons as well. 但那也应该是明显的原因。 C# simply doesn't support polymorphic returns. C#根本不支持多态返回。

Part B Even if we focus on just resp.Data , that object still has to be declared as some sort of type. B部分即使我们只关注resp.Data ,该对象仍然必须被声明为某种类型。

class Response
{
     public Collection<someType> Data;
}

If your SuccessData and ErrorData implement the same interface then someType could simply be IyourInterface but that raises another issue. 如果您的SuccessDataErrorData实现相同的接口,那么someType可能只是IyourInterface但这引发了另一个问题。 Namely, how will the end user know whether they were given good data in Data or whether there is an error response tucked in there instead. 也就是说,最终用户将如何知道他们是否在Data中获得了良好的数据,或者是否存在隐藏在其中的错误响应。

WCF, I believe, will be nice enough to serialize IyourInterface for you so long as you declare it as a public part of the WCF service object. 我相信,只要您将它声明为WCF服务对象的公共部分,WCF就足以为您序列化IyourInterface But that still doesn't resolve how your end user will know what to do. 但这仍然无法解决最终用户如何知道该怎么做。


If you're willing for a little less elegance in the response, a classic pattern is to simply bundle your success data and error objects together into another response class like this: 如果你愿意在响应中稍微优雅一点,那么经典模式就是将你的成功数据和错误对象一起捆绑到另一个响应类中,如下所示:

class myResponse
{
    public SuccessResponse myRespData;
    public ErrorResponse myError
}

Now, the end user checks to see if there's an error if they care. 现在,最终用户检查他们是否关心是否有错误。 Presuming no error, then they go and look into the response data. 假设没有错误,那么他们会去查看响应数据。


Based upon your comment, yes, you can do the following too: 根据您的评论,是的,您也可以执行以下操作:

class Response
{
    public List<IYourData> Data;
    public YourEnum ReturnType;
}

public class ResponseData : IYourData { ... }  
public class ErrorData : IYourData { ... }  

And then on the client, you can perform a simple check like this: 然后在客户端上,您可以执行以下简单检查:

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

WCF will handle the serialization of List for you. WCF将为您处理List的序列化。 It'll either convert to an array or pass the collection directly depending upon what settings you have in place. 它将转换为数组或直接传递集合,具体取决于您具有的设置。 There are some SO Q&A's that handle that particular aspect. 有一些SO Q&A可以处理这个特定的方面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM