Каков наилучший способ сериализации массива на основе интерфейса в WCF? - PullRequest
5 голосов
/ 03 августа 2011

Сначала код:

[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 / data.

Какой лучший способ сериализации Rule.Actions?Я начал писать собственный сериализатор, но я бы предпочел посмотреть, есть ли более простой способ.

Спасибо.

Ответы [ 2 ]

4 голосов
/ 04 августа 2011

Я не думаю, что вы можете использовать интерфейсы в 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, и он будет правильно сериализовать все соответствующие им свойства класса (при условии, что объект указан как тип Knowntype).

* Я использовал имя «Action» в качестве примера, чтобы связать его с вашим, очевидно, Action - это ключевое слово в .NET

0 голосов
/ 04 августа 2011

Сериализация - это процесс преобразования между объектом данными и байтами, которые можно передавать по проводам.Интерфейсы определяют поведение , поэтому по умолчанию WCF не может сериализовать такие данные.Однако если у вас точно такие же сборки на клиенте и на сервере, вы можете использовать NetDataContractSerializer, который по существу сериализует (и сможет сериализовать) всю информацию о типах для сериализуемых объектов, поэтому она может быть воссоздана заново.на другой стороне.

В приведенном ниже коде показано, как использовать NetDataContractSerializer в службе для этого (на основе основного примера для этого, сообщение от Аарона Сконнарда в 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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...