C# 如何通过 WCF 实现继承的字典
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/267113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement an inherited Dictionary over WCF
提问by chilltemp
I'm trying to implement a dictionary for use with WCF. My requirements are:
我正在尝试实现一个用于 WCF 的字典。我的要求是:
- actual (private variable or base class) type equivalent to Dictionary
- Comparer
=
System.StringComparer.InvariantCultureIgnoreCase
- Custom (override/new) Add(key, value) method (to include validations).
- Override ToString()
- Use of the same type on both the client and host
- 与 Dictionary 等效的实际(私有变量或基类)类型
- 比较器 =
System.StringComparer.InvariantCultureIgnoreCase
- 自定义(覆盖/新建)Add(key, value) 方法(包括验证)。
- 覆盖 ToString()
- 在客户端和主机上使用相同的类型
I've attempted using this class in a common project shared by the WCF host and client projects:
我尝试在 WCF 主机和客户端项目共享的公共项目中使用此类:
[Serializable]
public class MyDictionary : Dictionary<string, object>
{
public MyDictionary()
: base(System.StringComparer.InvariantCultureIgnoreCase)
{ }
public new void Add(string key, object value)
{ /* blah */ }
public override string ToString()
{ /* blah */ }
}
[DataContract]
[KnownType(typeof(MyDictionary))]
[KnownType(typeof(object[]))]
[KnownType(typeof(double[]))]
[KnownType(typeof(string[]))]
[KnownType(typeof(DateTime[]))]
public class ResultClass
{
public object Value{ get; set; }
/* More properties */
}
public class ParmData
{
public object Value{ get; set; }
/* More properties */
}
[DataContract]
[KnownType(typeof(MyDictionary))]
[KnownType(typeof(object[]))]
[KnownType(typeof(double[]))]
[KnownType(typeof(string[]))]
[KnownType(typeof(DateTime[]))]
public class ParameterClass
{
public List<ParmData> Data{ get; set; }
/* More properties */
}
[OperationContract]
ResultClass DoSomething(ParameterClass args);
Results:
结果:
- When I pass MyDictionary as one of the ParameterClass.Data.Value elements, I get a missing KnownType exception.
- I can safely return MyDictionary in the ResultClass, but it is no longer my type. It is just a Dictionary, and is not castable to
MyDictionary
. Also comparer =System.Collections.Generic.GenericEqualityComparer<string>
, not the case insensitive comparer I'm looking for.
- 当我将 MyDictionary 作为 ParameterClass.Data.Value 元素之一传递时,我得到一个缺失的 KnownType 异常。
- 我可以安全地在 ResultClass 中返回 MyDictionary,但它不再是我的类型。它只是一个字典,不能投射到
MyDictionary
. 还有 comparer =System.Collections.Generic.GenericEqualityComparer<string>
,而不是我正在寻找的不区分大小写的比较器。
The help I'm asking for is to either fix my failed attempt, or a completely different way to achieve my stated requirements. Any solution should not involve copying one dictionary to another.
我要求的帮助要么是修复我失败的尝试,要么是一种完全不同的方式来实现我的既定要求。任何解决方案都不应涉及将一本字典复制到另一本字典。
Thanks
谢谢
采纳答案by chilltemp
- Use the
CollectionDataContract
attribute as jezell suggested - Manually generate the reference (proxy) code with SvcUtil, using the /collectionType parameter. This parameter is not supported by the vs2008 service reference GUI.
- 使用
CollectionDataContract
jezell 建议的属性 - 使用 /collectionType 参数通过 SvcUtil 手动生成引用(代理)代码。vs2008 服务参考 GUI 不支持此参数。
Source: WCF Collection Type Sharing
来源:WCF馆藏类型分享
回答by Marc Gravell
Preamble: note that adding a "new" Add
doesn't stop people calling the old Add
simply by casting. Also, in terms of "mex", that is a very vague data-contract - does it need to be so open-ended? (lots of object
etc...)
序言:请注意,添加“新”Add
并不能阻止人们Add
简单地通过转换来调用旧的。此外,就“mex”而言,这是一个非常模糊的数据合同——它需要如此开放吗?(很多object
等等...)
First: haven't you missed a few [DataContract]
/[DataMember]
markers there? In particular:
第一:你是不是错过了一些[DataContract]
/[DataMember]
标记?特别是:
- ResultClass.Value
- ParamData
- ParamData.Value
- ParameterClass.Data
- 结果类.值
- 参数数据
- 参数数据.值
- 参数类.Data
Can you clarify exactlywhich version of .NET you are using? DataContractSerializer
etc have been tweaked via service packs. With 3.5 SP1 installed (the only thing I have to hand) it does at least serialize and deserialize via DataContractSerializer
(no WCF stack), and the correct Add
method is called.
您能否准确说明您使用的是哪个版本的 .NET?DataContractSerializer
等已经通过服务包进行了调整。安装 3.5 SP1 后(我唯一需要做的事情)它至少会通过DataContractSerializer
(无 WCF 堆栈)进行序列化和反序列化,并Add
调用正确的方法。
Can you check whether the following works with your local version? (it works for me with 3.5 SP1 and with the missing attributes) [output first]:
您可以检查以下是否适用于您的本地版本吗?(它适用于 3.5 SP1 和缺少的属性)[输出优先]:
1
MyDictionary
abc=123
def=ghi
Code:
代码:
// or long-hand in C# 2.0
ParameterClass pc = new ParameterClass {
Data = new List<ParmData> { new ParmData {
Value = new MyDictionary {
{"abc",123},
{"def","ghi"}
}}}};
DataContractSerializer dcs = new DataContractSerializer(pc.GetType());
string xml;
using(StringWriter sw = new StringWriter())
using(XmlWriter xw = XmlWriter.Create(sw)) {
dcs.WriteObject(xw, pc);
xw.Close();
xml = sw.ToString();
}
using(StringReader sr = new StringReader(xml)) {
ParameterClass clone = (ParameterClass)dcs.ReadObject(XmlReader.Create(sr));
Console.WriteLine(clone.Data.Count);
Console.WriteLine(clone.Data[0].Value.GetType().Name);
MyDictionary d = (MyDictionary)clone.Data[0].Value;
foreach (KeyValuePair<string, object> pair in d)
{
Console.WriteLine("{0}={1}", pair.Key, pair.Value);
}
}
Obviously this just tests DataContractSerializer
(without the entire WCF stack), but it seems to work... so: does the same code work with your local version of .NET? If not, is installing the latest 3.0 service pack an option? (ideally via installing 3.5 SP1).
显然这只是测试DataContractSerializer
(没有整个 WCF 堆栈),但它似乎工作......所以:相同的代码是否适用于您的本地版本的 .NET?如果没有,是否可以选择安装最新的 3.0 服务包?(理想情况下通过安装 3.5 SP1)。
For info, I get xml:
有关信息,我得到 xml:
<?xml version="1.0" encoding="utf-16"?><ParameterClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/"><Data><ParmData><Value xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:type="d4p1:ArrayOfKeyValueOfstringanyType"><d4p1:KeyValueOfstringanyType><d4p1:Key>abc</d4p1:Key><d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">123</d4p1:Value></d4p1:KeyValueOfstringanyType><d4p1:KeyValueOfstringanyType><d4p1:Key>def</d4p1:Key><d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">ghi</d4p1:Value></d4p1:KeyValueOfstringanyType></Value></ParmData></Data></ParameterClass>
回答by jezell
Add CollectionDataContract to the Dictionary class:
将 CollectionDataContract 添加到 Dictionary 类:
For more information on using collection data contracts to implement dictionaries, check this link:
有关使用集合数据契约实现字典的更多信息,请查看此链接:
回答by Shaun Bowe
I finally found a way to do this. I found this linkthat pointed in the right direction but I will try to summarize.
我终于找到了一种方法来做到这一点。我发现这个链接指向了正确的方向,但我会尝试总结一下。
- Make sure you add
[CollectionDataContract]
to your custom collection - Add Service Reference through VS like you normally do
- Expand the service reference and look for the Reference.svcmap file
- Under the client options node you will see
- 确保您添加
[CollectionDataContract]
到您的自定义集合 - 像往常一样通过 VS 添加服务引用
- 展开服务引用并查找 Reference.svcmap 文件
- 在客户端选项节点下,您将看到
<CollectionMappings/>
<集合映射/>
Replace it with the following xml.
将其替换为以下 xml。
<CollectionMappings>
<CollectionMapping TypeName="Full.Namespace.Here" Category="List" />
</CollectionMappings>
<CollectionMappings>
<CollectionMapping TypeName="Full.Namespace.Here" Category="List" />
</CollectionMappings>
- Right click on the Service Reference and click update. It should no longer generate that "proxy" class and will let you use your shared class.
- 右键单击服务引用并单击更新。它不应再生成该“代理”类,而是让您使用共享类。