Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a DSL in C# for generating domain specific XML

Tags:

c#

xml

dsl

legacy

I have a legacy HTTP/XML service that I need to interact with for various features in my application.

I have to create a wide range of request messages for the service, so to avoid a lot of magic strings littered around the code, I've decided to create xml XElement fragments to create a rudimentary DSL.

For example.

Instead of...

new XElement("root", 
  new XElement("request",
    new XElement("messageData", ...)));

I'm intended to use:

Root( Request( MessageData(...) ) );

With Root, Request and MessageData (of course, these are for illustrative purposes) defined as static methods which all do something similar to:

private static XElement Root(params object[] content) 
{
    return new XElement("root", content);
}

This gives me a pseudo functional composition style, which I like for this sort of task.

My ultimate question is really one of sanity / best practices, so it's probably too subjective, however I'd appreciate the opportunity to get some feedback regardless.

  1. I'm intending to move these private methods over to public static class, so that they are easily accessible for any class that wants to compose a message for the service.

  2. I'm also intending to have different features of the service have their messages created by specific message building classes, for improved maintainability.

Is this a good way to implement this simple DSL, or am I missing some special sauce that will let me do this better?

The thing that leads me to doubt, is the fact that as soon as I move these methods to another class I increase the length of these method calls (of course I do still retain the initial goal of removing the large volume magic strings.) Should I be more concerned about the size (loc) of the DSL language class, than I am about syntax brevity?

Caveats

Note that in this instance the remote service poorly implemented, and doesn't conform to any general messaging standards, e.g. WSDL, SOAP, XML/RPC, WCF etc.

In those cases, it would obviously not be wise to create hand built messages.

In the rare cases where you do have to deal with a service like the one in question here, and it cannot be re-engineered for whatever reason, the answers below provide some possible ways of dealing with the situation.

like image 260
ocodo Avatar asked Sep 05 '11 05:09

ocodo


1 Answers

Have you noticed that all the System.Linq.Xml classes are not sealed?

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

Remember this won't work for 'reading' scenarios, you will only have the strong-typed graph from the XML that your application creates via code.

like image 104
Jonathan Dickinson Avatar answered Sep 29 '22 11:09

Jonathan Dickinson