首先是代码:
[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的最佳方法是什么?我已经开始编写自定义序列化程序,但我更愿意看看是否有更简单的方法。
感谢。
答案 0 :(得分:4)
我不认为你可以在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中的关键字
答案 1 :(得分:0)
序列化是在对象数据和可以通过线路传输的字节之间进行转换的过程。接口定义行为,因此默认情况下WCF无法序列化此类数据。但是,如果在客户端和服务器上具有完全相同的程序集,则可以使用NetDataContractSerializer
,它基本上序列化(并能够序列化)要序列化的对象的所有类型信息,因此它可以在另一边重建。
下面的代码显示了如何在服务中使用NetDataContractSerializer(基于此主要示例,来自http://www.pluralsight-training.net/community/blogs/aaron/archive/2006/04/21/22284.aspx的Aaron Skonnard的帖子)
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();
}
}