0

我们的 WCF 服务只有一种方法:

[ServiceContract(Name = "Service", Namespace = "http://myservice/")]
[ServiceKnownType("GetServiceKnownTypes", typeof(Service))]
public interface IService {
     Response Execute(Request request);
}

public class Service : IService {
     public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider) {
        return KnownTypesResolver.GetKnownTypes();
     }

     public Response Execute(Request request) { 
         return new MyResponse { Result = MyEnumHere.FirstValue }; 
     }
}

Request和类都Response包含一个ParameterCollection成员。

[Serializable]
[CollectionDataContract(Name = "ParameterCollection", Namespace = "http://myservice/")]
[KnownType("GetKnownTypes")]
public class ParameterCollection : Dictionary<string, object> {
        private static IEnumerable<Type> GetKnownTypes()
        {
            return KnownTypesResolver.GetKnownTypes();
        }
}

的子类Request并将Response它们的值存储到 ParameterCollection 值包中。

我正在使用 KnownTypesResolver 类来提供所有服务对象的类型信息。

public static class KnownTypesResolver {
     public static IEnumerable<Type> GetKnownTypes()
     {
         var asm = typeof(IService).Assembly;
         return asm
             .GetAllDerivedTypesOf<Response>() // an extension method
             .Concat(new Type[] {
                 typeof(MyEnumHere),
                 typeof(MyEnumHere?),
                 typeof(MyClassHere),
                 typeof(MyClassListHere),
             });
     }
}

如果我没记错的话,一切都应该有适当的类型信息,以便代理类生成工具在客户端生成定义明确的类。但是,只要其中一个Response子类(即MyResponse)包含诸如 的枚举值MyEnumHere,WCF 就会开始抱怨反序列化程序不知道 MyEnumHere 值。它应该有。KnownTypeAttribute正是出于这个原因,我提供了一个。

客户端代理类MyEnumHere在 Reference.cs 文件中确实有一个枚举;问题是ParameterCollection该类没有KnownTypeAttribute为它生成 s 。

我求助于手动编辑,并在生成的 Reference.cs 文件中包含以下几行:

//>
[KnownTypeAttribute(typeof(MyEnumHere))]
[KnownTypeAttribute(typeof(MyEnumHere?))]
[KnownTypeAttribute(typeof(MyClassHere))]
[KnownTypeAttribute(typeof(MyClassListHere))]
//<
public class ParameterCollection : Dictionary<string, object> { /* ... */ }

手工编辑生成的文件是可怕的。但这使客户工作。我究竟做错了什么?如何定义我的服务对象,以便生成的 VS 代理类从一开始就正确?

谢谢你的时间。

4

2 回答 2

1

WCF 不能很好地工作,Dictionary因为它不可互操作。您可以使用Array,List或自定义集合来确保您的数据被正确序列化。

下面的代码使用List<ParamCollectionElement>而不是Dictionary. 我还删除了一些多余的属性。

[DataContract]
public class Request
{
    [DataMember]
    public ParameterCollection ParameterCollection { get; set; }
}

[DataContract]
public class Response
{
    [DataMember]
    public ParameterCollection ParameterCollection { get; set; }
}

[DataContract]
public class MyResponse : Response
{
    [DataMember]
    public MyEnumHere Result { get; set; }
}

public class ParamCollectionElement
{
    public string Key { get; set; }
    public object Value { get; set; } 
}


[CollectionDataContract(Name = "ParameterCollection")]
public class ParameterCollection : List<ParamCollectionElement> 
{

}

public static class KnownTypesResolver
{
    public static IEnumerable<Type> GetKnownTypes()
    {
        return
            new Type[] {
                typeof(MyEnumHere),
                typeof(MyEnumHere?),
                typeof(Request),
                typeof(Response),
                typeof(MyResponse)
            };
    }
}

[DataContract]
public enum MyEnumHere
{
    [EnumMember]
    FirstValue,
    [EnumMember]
    SecondValue
}

[ServiceKnownType("GetServiceKnownTypes", typeof(Service))]
[ServiceContract(Name = "Service")]
public interface IService
{
    [OperationContract]
    Response Execute(Request request);
}

public class Service : IService
{
    public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider)
    {
        return KnownTypesResolver.GetKnownTypes();
    }

    public Response Execute(Request request)
    {
        var result = new MyResponse
        {
            Result = MyEnumHere.FirstValue,
            ParameterCollection = new ParameterCollection()
        };

        result.ParameterCollection.Add(new ParamCollectionElement {Key = "one", Value = MyEnumHere.FirstValue});
        result.ParameterCollection.Add(new ParamCollectionElement { Key = "two", Value = new Response() });
        return result;
    }
} 
于 2012-06-19T20:10:53.917 回答
0

确保你[DataContract]的枚举和[EnumMember]每个枚举成员都有:

[DataContract]
public enum MyEnumHere
{
    [EnumMember]
    SomeValue,
    [EnumMember]
    OtherValue,
    [EnumMember]
    OneMoreValue
}

这应该会导致在您的客户端中构建代理枚举(及其成员值),而无需手动更改 Reference.cs 文件。

于 2012-06-19T20:20:00.573 回答