jump to navigation

Prototyping With AnonymousTypes, CS-Script and JSON.Net – DataBuilder Part 3 November 14, 2010

Posted by ActiveEngine Sensei in .Net, ASP.Net, C#, CS-Script, DataBuilder, JSON.Net, New Techniques, Open Source.
Tags: , , , ,
trackback

Sensei hit his head in the shower this morning and instead of the flux-capacitor he saw the following code that could be used for prototyping:

var jsonDataSet = AnonFactory.CreateList(10, new { FirstName = "",
                                 LastName = "",
                                 Age = 0,
                                 Salary = 45000})
                              .WhereAll()
                              .Have("FirstName", "Jim")
                              .BuildList()
                              .ToJSON();

If you have been following the series on DataBuilder, a utility that dynamically creates test data as JSON, you’ll recall one of the highlights was avoiding the need to create an additional Visual Studio project just so you could create test data.  DataBuilder can import your assemblies and with the use of NBuilder it creates test data for you.  You may wish to read those posts for some background.

But consider the scenarios where you do not have an application domain or a .Net assembly to test.  Should you stop?  For prototyping do you really need to compile, change, compile, change, show-to-your-user, repeat ad-nauseum?

Here’s a new concept:  Build data sets that you use in prototyping with Javascript before you break out Visual Studio.  If you can quickly build a tool set to communicate with your business users you’ll be much further ahead by avoiding the back-end client side impedance mismatch.  After all, many times the business user has the concept already hidden upstairs in their heads, why not help get that vision out in the open earlier and save yourself.

So, to be able to write the statement that Sensei saw in his vision we need to achieve to following goals:

  • Create an anonymous type as template for building a list
  • Create a fluent interface for chaining clauses similar to NBuilder
  • Serialize the list of anonymous types to JSON
  • Run this process in DataBuilder – in other words, go dynamic!

You may want to download the source and follow along.

AnonymousType as a Template

It turns out that Sensei has a tool in his bag of tricks, namely the Persistent Anonymous type.  As you are aware, anonymous types in C# have a limited scope, but the Persistent Anonymous type that Sensei discussed allows you to create a structure that mimics a standard anonymous type while being persist that structure beyond the scope of its creation.  The AnonymousType creator, Hugo Benocci created something really great.  Here’s what you can do from the get-go:

var anonType = AnonymousType(new {FirstName = "James",
                                         Middle = "T",
                                         LastName="Kirk"
                                   });

If you recall the examples used in the prior posts on data generation with DataBuilder, NBuilder supplied default values for you when you built an object. You then had to alter those values should you want something different.

With an AnonymousType we use a factory to create a list of AnonymousTypes like so:

var anonTypeList = AnonFactory.CreateListSizeOf(10,
                                  new {FirstName = "James",
                                         Middle = "T",
                                         LastName="Kirk"
                                   });

Nice and simple. If we didn’t have more goals to achieve, we could go home. As it is, on to the next step.

Creating a Fluent Interface for Chaining Clauses

We still need to provide variation in our data set.  NBuilder does a nice job of letting us use clauses like .WhereTheNext(5).Have() or WhereAll.Have() to introduce more structured variation in our data.  We want to achieve the same thing with the AnonymousTypes and can do the following:

var anonTypeList = AnonFactory.CreateListSizeOf(10,
                                  new {FirstName ="",
                                         Middle = "",
                                         LastName=""
                                   })
                                   .WhereAll()
                                       .Have("FirstName", "William")
                                       .Have("LastName", "Riker")
                                   .BuildList();

Like NBuilder we want to specify that different segments get different values. Here’s how that is accomplished:

var anonTypeList = AnonFactory.CreateListSizeOf(10,
                                  new {FirstName = "",
                                         Middle = "",
                                         LastName=""
                                   })
                                   .WhereTheFirst(5)
                                       .Have("FirstName", "William")
                                       .Have("LastName", "Riker")
                                   .AndTheNext(5)
                                       .Have("FirstName", "Jean-Luc")
                                       .Have("LastName","Picard")
                                   .BuildList();

There is also a WhereTheLast() clause for working with data at the end of a list.  All of these extension methods are contained in Extensions.cs.

Now let’s talk about how this works. For our purposes a fluent interface allows us to chain methods together yielding a more readable syntax. This is achieved with methods that return a reference to it’s class as in:

class RetangleCreator
{
    private decimal width;
    private decimal height;
    private string color;

    public RectangleCreator SetWidth(decimal width)
    {
        this.width = width;
        return this;
    }

    public RectangleCreator SetHeight(decimal height)
    {
        this.height = height ;
        return this;
    }

    public RectangleCreator SetColor(string color)
    {
        this.color= color;
        return this;
    }
}

var rectangleCreator = new RectangleCreator()
                                         .SetHeight(4.5)
                                         .SetWidth(5.75)
                                         .SetColor("red");

With a collection or list you might be tempted to create code that simply passes on the list after performing some action. This is fine until you need to perform actions on specific segments of that list. In our case we need to know where an action has left of in order to achieve syntax like WhereTheNext(5).Have(…).AndTheNext(5).

The class AnonTypeRange accomplishes this and allows us to perform actions on a list of AnonymousTypes in the manner we desire. Here is the code:

public void SetRange(int start, int amount)
{
    Enforce.ArgumentGreaterThanZero(amount, "AnonTypeRange.Next - amount must be greater than start");
    Enforce.That((start >= 0), "AnonTypeRange.Next - start must be greater than or equal to 0");
    Enforce.That((amount + start <= this.limit), "AnonTypeRange.Next - amount can not be greater than limit");     this.Start = start;     this.End = (start + amount - 1) > limit ? limit : start + amount - 1;
        }

The ranges themselves are set in the extension methods that comprise our syntax. Examine WhereTheNext() and AndTheNext() methods:

public static AnonTypeRange WhereTheFirst(this List anonTypes, int amount)
{
    Enforce.ArgumentGreaterThanZero(amount, "AnonTypeRange.WhereTheFirst - amount can not be less that 0");

    var anonTypeRange = new AnonTypeRange(anonTypes);
    anonTypeRange.SetRange(0, amount);

    return anonTypeRange;
}

public static AnonTypeRange AndTheNext(this AnonTypeRange anonTypeRange, int amount)
{
    Enforce.ArgumentGreaterThanZero(amount, "AnonTypeRange.AndTheNext - amount can not be less that 0");

    anonTypeRange.SetRange(anonTypeRange.End + 1, amount);

    return anonTypeRange;
}

The only drawback is that the actions are processed serially. In other words you do a group of 5, then another group of 5. If you need to go back you could add a WhereTheFirst() to reset the position of operations.

Before we move on take note of the WhereAll() method. This takes in a List and returns a AnonTypeRange with the range set to 0 spanning to the end:

public static AnonTypeRange WhereAll(this ListanonTypes)
{
    var anonTypeRange = new AnonTypeRange(anonTypes);
    anonTypeRange.SetRange(0, anonTypes.Count);

    return anonTypeRange;
}

Our values are set with the Have clause. Again we try to mimic the great functionality of NBuilder, so you have two options.  You can set a single value on a property over a range:

//  Have
public static AnonTypeRange Have(this AnonTypeRange anonTypeRange, string property, object value)
{
    anonTypeRange.Apply(property, value);
    return anonTypeRange;
}

//  Have calls AnonTypeRange.Apply to save the properties
public void Apply(string property, object value)
{
    Enforce.ArgumentNotNull(property, "AnonTypeRange.Apply - property can not be null");
    Enforce.ArgumentNotNull<object>(value, "AnonTypeRange.Apply - value can not be null");

    int count = (this.End - Start) + 1;
    var range = this.internalAnonList.GetRange(this.Start, count);
    range.ForEach(x => x.Set(property, value));                    }

Or you can create a list of values that will be selected at random and distributed across the range.  This takes advantage of the Pick functionality provided by NBuilder and is quite useful.

public void Apply(string property, List<T>pickList)
{
    Enforce.ArgumentNotNull(property, "AnonTypeRange.Apply - property can not be null");

    int count = (this.End - Start) + 1;
    var range = this.internalAnonList.GetRange(this.Start, count);

    range.ForEach(x => x.Set(property, Pick.RandomItemFrom(pickList)));
}

Serializing the List of AnonymousTypes

AnonymousType has a method that will serialize the properties that it contains.  Since AnonymousType stores the properties and respective values in a Dictionary it’s fairly easy to searlize the Dictionary.  The method uses the JObject from JSON.Net, but you can come up with your own mechanisms if you like:

//  From AnonymousType
public string ToJSON(Func , string, string> function,
                                                string jsonObjectName)
    {
        return function(_Values, jsonObjectName);
    }
//  Delegate method for serializing
public static string SerializeWithJObject(Dictionary values, string name)
{
    var jsonObject = new JObject();

    foreach (KeyValuePair property in values)
    {
        jsonObject.Add(new JProperty(property.Key, property.Value));
    }

    return jsonObject.ToString();
}

Serializing a list of AnonymousTypes is as equally straight forward to accomplish.  You only need to traverse the list and call the ToJSON methods on each AnonymousType object.  So easy it almost makes you feel guilty!

Dynamically Generate Data Sets with DataBuilder

If you’ve made it this far, congratulations, it’s been a bit of a marathon.   What is striking is how very straight forward much of this has been.  And the icing on the cake is that you can use the Snippet section of DataBuilder to run the code.  This required a slight alteration to the ScriptHostBase file, as it was expecting a path to an assembly.  Since the goal is to generate data sets without assemblies it would be pretty silly if you had supply something in the Assembly Path section.  All you need to do is supply something like the code below in the Code Snippet and hit “Build Data”:

var namesPickList = new List();
namesPickList.Add("Geordi");
namesPickList.Add("Que");
namesPickList.Add("Data");
namesPickList.Add("Jean-Luc");

string json = AnonFactory.CreateListOfSize(10,
                     new { LastName = "Kirk",
                              FirstName = "James",
                              MiddleInitial = "T." })
                      .WhereAll()
                            .Have("FirstName", namesPickList)
                      .BuildList()
                      .ToJSON();

parameters["JsonDataSet"] = json;

Faster than a photon torpedo you get back JSON. Now you’re set to start your HTML / Javascript prototypes. Need to alter the data, update the snippet and run it again.  Here’s the new source code, and prototype away!

Comments»

1. Dynamically Create Test Data with NBuilder, JSON and .Net « ActiveEngine - November 14, 2010

[…] 1 of a 3 part series.  For the latest DataBuilder capabilities, read this post or download the new source code from […]

2. How Embedded Scripting Makes Dynamically Generated Test Data Possible in ASP.Net – DataBuilder Part 2 « ActiveEngine - November 14, 2010

[…] 1 of a 3 part series.  For the latest DataBuilder capabilities, read this post or download the new source code […]

3. tech blog - November 17, 2010

i have been saving about Prototyping With Anonymous Types, CS-Script and JSON.Net – Data Builder thanks for the info

4. Prototyping With AnonymousTypes, CS-Script and JSON.Net – DataBuilder Part 3 - December 21, 2010

[…] = AnonFactory.CreateList(10, new { FirstName = "", LastName = "", Age = 0,… [full post] ActiveEngine Sensei ActiveEngine c#.netnew techniquesopen source 0 0 […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: