Реализация DSL в C # для генерации специфичного для домена XML - PullRequest
6 голосов
/ 05 сентября 2011

У меня есть устаревшая служба HTTP / XML, с которой мне нужно взаимодействовать для различных функций моего приложения.

Мне нужно создать широкий спектр сообщений-запросов для службы, поэтому, чтобы избежать большого количества магических строк, разбросанных по коду, я решил создать xml XElement фрагменты для создания элементарного DSL.

Например.

Вместо ...

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);
}

Это дает мне псевдо-функциональный стиль композиции, который мне нравится для такого рода задач.

Мой главный вопрос на самом деле касается здравомыслия / лучших практик, так что, возможно, он слишком субъективен, однако я был бы признателен за возможность получить некоторую обратную связь независимо от этого.

  1. Я собираюсь переместить эти частные методы в открытый статический класс, чтобы они были легко доступны для любого класса, который хочет составить сообщение для службы.

  2. Я также намерен, чтобы различные функции службы создавали свои сообщения с помощью определенных классов построения сообщений для повышения удобства сопровождения.

Это хороший способ реализовать этот простой DSL, или мне не хватает какого-то специального соуса, который позволит мне сделать это лучше?

То, что заставляет меня усомниться в том, что, как только я перемещаю эти методы в другой класс, я увеличиваю длину этих вызовов методов (конечно, я все еще сохраняю первоначальную цель удаления магических строк большого объема .) Должен ли я больше беспокоиться о размере (loc) языкового класса DSL, чем о краткости синтаксиса?

Предостережения

Обратите внимание, что в этом случае удаленная служба плохо реализована и не соответствует каким-либо общим стандартам обмена сообщениями, например, WSDL, SOAP, XML / RPC, WCF и т. Д.

В этих случаях было бы неразумно создавать сообщения, созданные вручную.

В тех редких случаях, когда вам приходится иметь дело со службой, подобной той, о которой идет речь, здесь, и она не может быть реконструирована по какой-либо причине, ответы ниже предоставляют некоторые возможные способы разрешения ситуации.

Ответы [ 4 ]

2 голосов
/ 05 сентября 2011

Вы заметили, что все 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 голос
/ 26 октября 2011

Я заметил эту статью для создания произвольного XML с C # 4.0, что здорово .

Источник для библиотеки здесь - https://github.com/mmonteleone/DynamicBuilder/tree/master/src/DynamicBuilder

На этомвремя, есть заметный недостаток, нет поддержки пространства имен XML.Надеюсь, это будет исправлено.

В качестве быстрого примера, вот как это делается.

dynamic x = new Xml();
x.hello("world");

Что приводит к:

<hello>world</hello>

Вот еще один быстрый пример, полученный отthe article.

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 аналогично лаконичен до такой степени, что он граничит с "fun "!

Я пометил это как ответ, потому что, хотя он и не говорит непосредственно об" использовании DSL для создания произвольного XML ", он имеет тенденцию устранять необходимость из-за чрезвычайно краткого идинамическая природа синтаксиса.

Лично я считаю, что это лучший способ создания произвольного XML в C #, если у вас есть компилятор v4.0 и вам нужно запустить его вручную, есть, конечно, гораздо лучшие способыгенерировать XML автоматически с сериализацией.Зарезервируйте это для XML, который должен быть в определенной форме только для устаревших систем.

1 голос
/ 05 сентября 2011

Ручной запуск xml - это одна из вещей, которую следует автоматизировать, если это возможно.

Один из способов сделать это - извлечь определения XSD обмена сообщениями из конечной точки и использовать их для генерации типов C # синструмент xsd.exe.

Затем вы можете создать тип и сериализовать его, используя XmlSerializer, который выкачает ваше xml-сообщение для вас.

0 голосов
/ 05 сентября 2011

Написание этого на C # кажется ужасной работой.Создайте свой DSL как словарь XML, а затем скомпилируйте его в XSLT, написав компилятор (переводчик) в XSLT.Я делал это много раз.

...