基于 WCF 中的接口序列化数组的最佳方法是什么?



首先代码:

[ServiceContract]
public interface IWorker
{
    [OperationContract]
    void Process(XmlElement data);
    [OperationContract]
    void Update(Rule rule);
}
[DataContract]
public class Rule
{
    [OperationContract]
    public string Expression { get; set; }
    [OperationContract]
    public List<IAction> Actions { get; set; }
}
public interface IAction
{
    void Execute(XmlElement data);
}

调度程序将数据编码为xml并将其发送到IWorker实例,其中每个表达式都被计算。当IWorker实例计算一个表达式为true时,IAction。调用Execute并传递xml/数据。

序列化Rule.Actions的最好方法是什么?我已经开始编写自定义序列化器,但我更愿意看看是否有更简单的方法。

谢谢。

我不认为你可以在DataContracts中使用接口(有人纠正我,如果我错了,但我认为这就像尝试使用泛型一样)。我做的是,有一个父类,然后添加KnownType属性。例如

[DataContract]
public class Action
{
    //members and properties
}

[DataContract]
public class SomeOtherAction:Action
{
    //more implimentation
}
[DataContract]
[KnownType(typeof(SomeOtherAction))]
public class Rule
{
    [DataMember]
    List<Action> Actions{get;set;}
}

现在你可以把任何继承自父Action对象的对象塞到Actions列表中,并且它将正确地序列化它们各自的类属性(只要该对象被列为已知类型)。

*我使用了"Action"Action是。net中的一个关键字

序列化是在对象数据和可以通过网络传输的字节之间进行转换的过程。接口定义了行为,所以默认情况下WCF不能序列化这样的数据。但是,如果您在客户端和服务器上拥有完全相同的程序集,则可以使用NetDataContractSerializer,它将基本上序列化(并且能够序列化)正在序列化的对象的所有类型信息,因此可以在另一端重新创建它。

下面的代码显示了如何在服务中使用NetDataContractSerializer(基于此的主要示例,来自Aaron Skonnard在http://www.pluralsight-training.net/community/blogs/aaron/archive/2006/04/21/22284.aspx上的文章)

public class StackOverflow_6932356
{
    [ServiceContract]
    public interface IWorker
    {
        [OperationContract]
        void Process(XmlElement data);
        [OperationContract]
        void Update(Rule rule);
    }
    [DataContract]
    public class Rule
    {
        [DataMember]
        public string Expression { get; set; }
        [DataMember]
        public List<IAction> Actions { get; set; }
    }
    public interface IAction
    {
        void Execute(XmlElement data);
    }
    public class Service : IWorker
    {
        static List<IAction> AllActions = new List<IAction>();
        public void Process(XmlElement data)
        {
            foreach (var action in AllActions)
            {
                action.Execute(data);
            }
        }
        public void Update(Rule rule)
        {
            AllActions = rule.Actions;
        }
    }
    public class Action1 : IAction
    {
        public void Execute(XmlElement data)
        {
            Console.WriteLine("Executing {0} for data: {1}", this.GetType().Name, data.OuterXml);
        }
    }
    public class Action2 : IAction
    {
        public void Execute(XmlElement data)
        {
            Console.WriteLine("Executing {0} for data: {1}", this.GetType().Name, data.OuterXml);
        }
    }
    class NetDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
    {
        public NetDataContractSerializerOperationBehavior(OperationDescription operationDescription)
            : base(operationDescription) { }
        public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
        {
            return new NetDataContractSerializer(name, ns);
        }
        public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
        {
            return new NetDataContractSerializer(name, ns);
        }
    }
    static void ReplaceDCSOB(ServiceEndpoint endpoint)
    {
        foreach (var operation in endpoint.Contract.Operations)
        {
            for (int i = 0; i < operation.Behaviors.Count; i++)
            {
                if (operation.Behaviors[i] is DataContractSerializerOperationBehavior)
                {
                    operation.Behaviors[i] = new NetDataContractSerializerOperationBehavior(operation);
                    break;
                }
            }
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IWorker), new BasicHttpBinding(), "");
        ReplaceDCSOB(endpoint);
        host.Open();
        Console.WriteLine("Host opened");
        var factory = new ChannelFactory<IWorker>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
        ReplaceDCSOB(factory.Endpoint);
        var proxy = factory.CreateChannel();
        proxy.Update(new Rule
        {
            Expression = "Expr",
            Actions = new List<IAction> { new Action1(), new Action2() }
        });
        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<root><foo>bar</foo></root>");
        proxy.Process(doc.DocumentElement);
        ((IClientChannel)proxy).Close();
        factory.Close();
        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}

最新更新