WCF中带有接口类型参数的通用返回类型 [英] Generic return types with interface type params in WCF
问题描述
如何从我的WCF REST服务中的 OperationContracts
返回泛型类型参数中的接口类型?更具体地说,它适用于一个操作,但不是当我使用一个通用接口 T
添加第二个操作时。
我使用JSON作为请求和响应格式,提供一个非WCF客户端来解析数据的JSON响应需要。我没有使用SOAP或由服务生成的WSDL。
我的服务界面:
[ServiceContract]
[ServiceKnownType(GetServiceKnownTypes,typeof(ServiceKnownTypesHelper))]
public interface IMyService
{
[WebGet(UriTemplate =count)]
[OperationContract]
IServiceResult< INT> getCount将();
[WebGet(UriTemplate =desc)]
[OperationContract]
IServiceResult< string> GetDescription();
[WebGet(UriTemplate =foo)]
[OperationContract]
IServiceResult< IFooData> GetFooData();
//如果我取消注释该操作,则在调用任一方法时失败。
// [WebGet(UriTemplate =bar)]
// [OperationContract]
// IServiceResult< IBarData> GetBarData();
}
我离开了 返回类型 你可以想象我已经将实现简化为骨架,因为我不认为执行是问题的核心: 当我调用<$ 其余的错误信息是关于碰撞集合类型的红鲱鱼 显然, 那为什么要做 我错过了什么,或者没有办法解决这个问题? 在经过多次试验和错误之后,我终于通过最小的改变来完成这项工作: GetCount()$ c $在这个例子中,c>和
GetDescription()
指出这两个通用结果工作正常,但显然它们是具体类型。甚至 GetFooData()
都可以正常工作,直到我添加第二个方法 IServiceResult< T>
,其中 T
是一个接口。 $ b GetFooData()
和 GetBarData()
不一样,实现它们的具体类也是不一样的。
#region我的服务实现
public class MyService:IMyService
{
public IServiceResult< int> GetCount()
{
返回新的ServiceResult< int>(42);
}
public IServiceResult< string> GetDescription()
{
返回新的ServiceResult< string>(Muffins);
}
public IServiceResult< IFooData> GetFooData()
{
返回新的ServiceResult< IFooData>(new FooData(){Foo = 99});
}
public IServiceResult< IBarData> GetBarData()
{
返回新的ServiceResult< IBarData>(new BarData(){Bar =Elvis was here));
#endregion
#region ServiceKnownTypesHelper.GetServiceKnownTypes():
public static class ServiceKnownTypesHelper
{
private静态IList< Type> serviceKnownTypes = new List< Type>()
{
typeof(FooData),
typeof(BarData),
typeof(ServiceResult< int>),
typeof ServiceResult< string>),
typeof(ServiceResult< IFooData>),
typeof(ServiceResult< IBarData>),
};
public static IEnumerable< Type> GetServiceKnownTypes(ICustomAttributeProvider paramIgnored)
{
return serviceKnownTypes;
}
}
#endregion
#region IServiceResult< T>及其具体实现:
public interface IServiceResult< T>
{
IList< string>错误{get; }
T值{get;组; }
}
[DataContract]
public class ServiceResult< T> :IServiceResult< T>
{
public ServiceResult(T value)
{
this.Value = value;
}
私有IList< string> errors = new List< string>();
[DataMember]
public IList< string>错误
{
得到
{
return this.errors;
}
}
[DataMember]
public T Value {get;组; }
}
#endregion
#region IFooData及其具体实现:
public interface IFooData
{
int Foo {get;组; }
$ b $ [DataContract]
public class FooData:IFooData
{
[DataMember]
public int Foo {get;组; }
}
#endregion
#region IBarData及其具体实现:
public interface IBarData
{
string Bar {get;组; }
$ b $ [DataContract]
public class BarData:IBarData
{
[DataMember]
public string Bar {get;组; }
}
#endregion
类型'ServiceResult`1 [IBarData]'can not被添加到已知类型的列表中,因为
具有相同数据协定名称
'http://schemas.datacontract.org/2004/07/ServiceResultOfanyType'的另一个类型'ServiceResult`1 [IFooData]'是
已经存在。
List< Test>
和 Test []
,这里不是这种情况。
IFooData
和 IBarData
不是同样的,也不是实现它们的类。
ServiceResult< IFooData>
和 ServiceResult< IBarData>
都解析为 ServiceResultOfanyType
?
ServiceResult
而不是 IServiceResult< T> code>。实际上,
IServiceResult< T>
现在完全消失了。 code>不再返回 ServiceResult< T>
的所有变体。我只返回用作 T
的 DataContract
。
<$ (ServiceKnownTypes,typeof(ServiceKnownTypesHelper))]
public interface IMyService
[ServiceContract]
[ServiceKnownTypes] {
[WebGet(UriTemplate =count)]
[OperationContract]
ServiceResult< int> getCount将();
[WebGet(UriTemplate =desc)]
[OperationContract]
ServiceResult< string> GetDescription();
[WebGet(UriTemplate =foo)]
[OperationContract]
ServiceResult< IFooData> GetFooData();
[WebGet(UriTemplate =bar)]
[OperationContract]
ServiceResult< IBarData> GetBarData();
}
#endregion
#region我的服务实现(减体)
public class MyService:IMyService
{
public ServiceResult< int> GetCount(){}
public ServiceResult< string> GetDescription(){}
public ServiceResult< IFooData> GetFooData(){}
public ServiceResult< IBarData> GetBarData(){}
}
#endregion
#region ServiceKnownTypes
//我的ServiceKnownTypes列表现在更短更简单。我给这个服务提供了太多的信息
public static class ServiceKnownTypesHelper
{
private static IList< Type> serviceKnownTypes = new List< Type>()
{
typeof(FooData),
typeof(BarData),
// typeof(ServiceResult< int>),
// typeof(ServiceResult< string>),
// typeof(ServiceResult< IFooData>),
// typeof(ServiceResult< IBarData>),
};
//剩余的实现与之前相同
}
#endregion
#region ServiceResult< T> (没有使用或不需要)
[DataContract]
public class ServiceResult< T> //:IServiceResult< T>
{
//实现与之前相同
}
#endregion
$ b现在我可以调用所有这些方法并获取 ServiceContract 中由它们的接口引用的泛型类型列表。 code>。
How can I return interface types in generic type parameters from the OperationContracts
in my WCF REST service? More specifically, it works for one operation but not when I add a second operation with a generic T
that is an interface.
I'm using JSON as the request and response format, feeding a non-WCF client that parses the JSON responses for the data it needs. I am not using SOAP, or the WSDL generated by the service.
My service interface:
[ServiceContract]
[ServiceKnownType("GetServiceKnownTypes", typeof(ServiceKnownTypesHelper))]
public interface IMyService
{
[WebGet(UriTemplate="count")]
[OperationContract]
IServiceResult<int> GetCount();
[WebGet(UriTemplate="desc")]
[OperationContract]
IServiceResult<string> GetDescription();
[WebGet(UriTemplate="foo")]
[OperationContract]
IServiceResult<IFooData> GetFooData();
// Fails when I invoke either method if I uncomment this operation.
//[WebGet(UriTemplate="bar")]
//[OperationContract]
//IServiceResult<IBarData> GetBarData();
}
I left GetCount()
and GetDescription()
in the example to point out that those two generic results work fine, but obviously they are concrete types. And even GetFooData()
works fine until I add a second method of IServiceResult<T>
where T
is an interface.
The return types of GetFooData()
and GetBarData()
are not the same, nor are the concrete classes that implement them.
You may imagine that I've reduced the implementation to a skeleton as I don't think the implementation is the heart of the problem:
#region My service implementation
public class MyService : IMyService
{
public IServiceResult<int> GetCount()
{
return new ServiceResult<int>(42);
}
public IServiceResult<string> GetDescription()
{
return new ServiceResult<string>("Muffins");
}
public IServiceResult<IFooData> GetFooData()
{
return new ServiceResult<IFooData>(new FooData() { Foo = 99 });
}
public IServiceResult<IBarData> GetBarData()
{
return new ServiceResult<IBarData>(new BarData() { Bar = "Elvis was here" });
}
}
#endregion
#region ServiceKnownTypesHelper.GetServiceKnownTypes():
public static class ServiceKnownTypesHelper
{
private static IList<Type> serviceKnownTypes = new List<Type>()
{
typeof(FooData),
typeof(BarData),
typeof(ServiceResult<int>),
typeof(ServiceResult<string>),
typeof(ServiceResult<IFooData>),
typeof(ServiceResult<IBarData>),
};
public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider paramIgnored)
{
return serviceKnownTypes;
}
}
#endregion
#region IServiceResult<T> and its concrete implementation:
public interface IServiceResult<T>
{
IList<string> Errors { get; }
T Value { get; set; }
}
[DataContract]
public class ServiceResult<T> : IServiceResult<T>
{
public ServiceResult(T value)
{
this.Value = value;
}
private IList<string> errors = new List<string>();
[DataMember]
public IList<string> Errors
{
get
{
return this.errors;
}
}
[DataMember]
public T Value { get; set; }
}
#endregion
#region IFooData and its concrete implementation:
public interface IFooData
{
int Foo { get; set; }
}
[DataContract]
public class FooData: IFooData
{
[DataMember]
public int Foo { get; set; }
}
#endregion
#region IBarData and its concrete implementation:
public interface IBarData
{
string Bar { get; set; }
}
[DataContract]
public class BarData: IBarData
{
[DataMember]
public string Bar { get; set; }
}
#endregion
And the error message when I invoke GetBarData()
from the browser:
Type 'ServiceResult`1[IBarData]' cannot be added to list of known types since another type 'ServiceResult`1[IFooData]' with the same data contract name 'http://schemas.datacontract.org/2004/07/ServiceResultOfanyType' is already present.
The rest of the error message is a red herring about colliding collection types List<Test>
and Test[]
, which isn't the case here.
Clearly, IFooData
and IBarData
aren't the same, nor are the classes that implement them.
So why do ServiceResult<IFooData>
and ServiceResult<IBarData>
both resolve to ServiceResultOfanyType
?
Am I missing something, or is there no way to fix this?
After much trial and error, I've finally got this working with minimal changes:
- My service operations now return
ServiceResult<T>
instead ofIServiceResult<T>
. In fact,IServiceResult<T>
is now gone entirely. GetServiceKnownTypes()
no longer returns all the variants ofServiceResult<T>
. I only return theDataContract
s used asT
.#region My service interface [ServiceContract] [ServiceKnownType("GetServiceKnownTypes", typeof(ServiceKnownTypesHelper))] public interface IMyService { [WebGet(UriTemplate="count")] [OperationContract] ServiceResult<int> GetCount(); [WebGet(UriTemplate="desc")] [OperationContract] ServiceResult<string> GetDescription(); [WebGet(UriTemplate="foo")] [OperationContract] ServiceResult<IFooData> GetFooData(); [WebGet(UriTemplate="bar")] [OperationContract] ServiceResult<IBarData> GetBarData(); } #endregion #region My service implementation (minus bodies) public class MyService : IMyService { public ServiceResult<int> GetCount() {} public ServiceResult<string> GetDescription() {} public ServiceResult<IFooData> GetFooData() {} public ServiceResult<IBarData> GetBarData() {} } #endregion #region ServiceKnownTypes // My list of ServiceKnownTypes is now much shorter and simpler. I was feeding the service too much information public static class ServiceKnownTypesHelper { private static IList<Type> serviceKnownTypes = new List<Type>() { typeof(FooData), typeof(BarData), //typeof(ServiceResult<int>), //typeof(ServiceResult<string>), //typeof(ServiceResult<IFooData>), //typeof(ServiceResult<IBarData>), }; // Remaining implementation is the same as before } #endregion #region ServiceResult<T> with no interface (it's not used or needed) [DataContract] public class ServiceResult<T> //: IServiceResult<T> { // implementation is the same as before } #endregion
I can now invoke all of those methods and get back lists of generic types referred to by their interfaces in the ServiceContract
.
这篇关于WCF中带有接口类型参数的通用返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!