我有一个遗留的HTTP / XML服务,我需要与我的应用程序中的各种功能进行交互。
我必须为服务创建各种请求消息,因此为了避免代码中散布着大量魔法字符串,我决定创建xml XElement
片段来创建一个基本的DSL。 / p>
例如。
而不是......
new XElement("root",
new XElement("request",
new XElement("messageData", ...)));
我打算使用:
Root( Request( MessageData(...) ) );
使用Root,Request和MessageData(当然,这些都是为了说明目的)定义为静态方法,它们都做类似的事情:
private static XElement Root(params object[] content)
{
return new XElement("root", content);
}
这给了我一种伪功能组合风格,我喜欢这种任务。
我的终极问题实际上是一种理智/最佳实践,所以它可能过于主观,但我很高兴有机会得到一些反馈。
我打算将这些私有方法移动到公共静态类,以便任何想要为服务撰写消息的类都可以轻松访问它们。
我还打算让服务的不同功能通过特定的消息构建类创建消息,以提高可维护性。
这是实现这个简单DSL的好方法,还是我错过了一些能让我做得更好的特殊酱?
让我怀疑的是,事实上,只要我将这些方法移动到另一个类,我就会增加这些方法调用的长度(当然我仍然保留了删除大量魔术字符串的初始目标) 。)我是否应该更关注DSL语言类的大小(loc),而不是语法简洁?
注意,在这种情况下,远程服务实现不当,并且不符合任何通用消息传递标准,例如, WSDL,SOAP,XML / RPC,WCF等。
在这些情况下,创建手工构建的消息显然不明智。
在极少数情况下,您必须处理此类服务,并且无论出于何种原因无法重新设计,下面的答案提供了一些处理此情况的可能方法。
答案 0 :(得分:2)
您是否注意到所有System.Linq.Xml
类都不密封?
public class Root : XElement
{
public Request Request { get { return this.Element("Request") as Request; } }
public Response Response { get { return this.Element("Response") as Response; } }
public bool IsRequest { get { return Request != null; } }
/// <summary>
/// Initializes a new instance of the <see cref="Root"/> class.
/// </summary>
public Root(RootChild child) : base("Root", child) { }
}
public abstract class RootChild : XElement { }
public class Request : RootChild { }
public class Response : RootChild { }
var doc = new Root(new Request());
请记住,这对于“阅读”方案不起作用,您只能使用应用程序通过代码创建的XML中的强类型图表。
答案 1 :(得分:1)
手动启动xml是应尽可能自动化的事情之一。
执行此操作的方法之一是从端点获取消息传递XSD定义,并使用它们使用xsd.exe工具生成C#类型。
然后你可以创建一个类型并使用XmlSerializer序列化它,它会为你输出你的xml消息。
答案 2 :(得分:1)
我注意到了article for constructing arbitrary XML with C#4.0 which is great。
图书馆的来源是 - https://github.com/mmonteleone/DynamicBuilder/tree/master/src/DynamicBuilder
此时,有一个值得注意的缺陷,没有xml命名空间支持。希望这会得到修复。
作为一个简单的例子,这就是它的完成方式。
dynamic x = new Xml();
x.hello("world");
哪个收益率:
<hello>world</hello>
这是另一个从文章中拉出来的快速例子。
dynamic x = new Xml();
// passing an anonymous delegate creates a nested context
x.user(Xml.Fragment(u => {
u.firstname("John");
u.lastname("Doe");
u.email("jdoe@example.org");
u.phone(new { type="cell" }, "(985) 555-1234");
}));
哪个收益率:
<user>
<firstname>John</firstname>
<lastname>Doe</lastname>
<email>jdoe@example.org</email>
<phone type="cell">(985) 555-1234</phone>
</user>
使用Ruby库Builder
这种创建任意XML的方法同样简洁,以至于它接近“有趣”!
我已将此标记为答案,因为即使它没有直接说“使用DSL创建任意XML”,但由于语法的极其简洁和动态性质,它往往会消除这种需求。
我个人认为这是在C#中创建任意XML的最佳方法,如果你有v4.0编译器并且必须手动编写它,当然有更好的方法可以自动生成序列化XML。为XML保留此选项,XML必须以旧系统的特定形式保留。
答案 3 :(得分:0)
在C#中写这个似乎是一项非常多的工作。将您的DSL设计为XML词汇表,然后将其编译为XSLT,在XSLT中编写编译器(转换器)。我已经多次这样做了。