Posts Tagged ‘C#’

JsonToDynamic: Consuming Json Data as Dynamic Objects in C# 4.0

About a month ago I was reading the early access edition of C# in Depth, Second Edition from Jon Skeet. In this book the auto demonstrates using dynamic objects and the dynamic keyword in C# using a wrapper around an xml document. Suppose you have a xml document containing a number of books

<book>
	<autor>The Autor</autor>
</boo>

Now you can access the auto properties of each book in the following way:

dynamic book = GetBookAsDynamic();
string autoName = book.autor

Having been using Json intensively  the last few weeks and seeing how easy it is to consume Json in JavaScript, I thought dynamic object would be a fantastic way to make Json more natural in the .Net world. My favorite Json library is the Json.Net. Since, I started to code a wrapper about it.

Suppose now you have such an object, that you have Json serialized:

var obj = new
{
    Name = "mouk",
    FavoriteNames = new[] { "mouk", "dermouk", "mouk9000" },
    NestedValues = new { First = 1, Second = 3, Nums = new[] { 1, 2, 3 } },
    NestedArray = new object[]{ 1, 3, new[] { 100, 2, 3 } },
    Age = 25,
    Height = 180
};

var serializedObject = JsonConvert.SerializeObject(obj);

After deserializing it back to a dynamic object you can access as easy as:

dynamic _deserializedObject = JsonDeserilizer.GetObjectFromString(serializedObject);

string name= _deserializedObject.Name;
int age = _deserializedObject.Age;

int nested = _deserializedObject.NestedArray[1];

Source Code

The source code of this wrapper can be downloaded from http://github.com/mouk/JsonToDynamic/tree/master:

Using IronPython to configure Castle Windsor III

Pysor Series

In the first two articles I introduced Pysor, the Castle Windsor configuration tool using IronPython. Now I have added some exciting functions to exploit the nice hash table and list syntax feature in IronPython.

Since the second part of this series is possible to add (named) parameters to component registration. It accepted only both literal and referential scalars. In the current revision you can exploit the nice list syntax of Python using the square brackets to add arrays and list parameters.

A parameter is a string literal or a reference to an already registered service. This value is supplied either to a constructor parameter with the same name or a property.

A example used in the last part was to provide AdditionalMessage property like this:

add( "retriverWithParam", HtmlTitleRetriever, HtmlTitleRetriever,
	{'AdditionalMessage': "Test"})

Now suppose that we have a class that accepts an array of strings in the constructor.  We could provide them using the Python list syntax

add( "MessageStorage" , MessageStorage, MessageStorage,
	{'messages':['first message', 'second message' ]})

This syntax works not only for array but also for ILists.

Things get more interesting when you want to add an array of registered services. The method add returns a hook to the service. You can use this hook to reference the service in the parameters :

ftp = add( "ftp", FtpFileDownloader, FtpFileDownloader)

add( "MultipleDowloaderStorage", MultipleDowloaderStorage,
	MultipleDowloaderStorage, {'dowloaders' : [ ftp] })

 

Comparison

In this section I will compare the same configuration using traditional xml syntax and the Pysor syntax. I am sure not every body would prefer Pysor. I am pretty comfortable with xml, yet I don’t like it. I will choose Pysor anyway. In the next section I will make a small project and use both configuration mechanisms and let you find by yourself, which solution is more elegant and appropriate for you.

Not breaking the tradition of almost all IoC tutorials, we will need a logging service to be located dynamically. Additionally we have two implementations: ConsoleLog  and FileLog. FileLog expect a file name in its constructor..

public interface ILog
{
    void Log(string message);
}

public class FileLog : ILog
{
    private readonly string _fileName;
    public FileLog(string fileName)
    {
        _fileName = fileName;
    }

    public void Log(string message)
    {
        Console.WriteLine(_fileName+ " -> " + message);
    }
}

public class ConsoleLog : ILog
{
    public void Log(string message)
    {
        Console.WriteLine(message);
    }
}

In additional we have an IAlgorithm interface with following members:

public interface IAlgorithm
{
    event EventHandler OnOperationDone;
    void Run();
}

Algorithm is a class implementing this interface. AlglorithmRunnner is a class that takes an algorithm with an array of loggers, starts the algorithm and notify all loggers when an event is fired.

Configuring this setup of dependencies in App.config would look much like:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type=
"Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>

  <castle>
    <components>
      <component id="fileLog"
                 type="CastleComparison.FileLog, CastleComparison"
                 service="CastleComparison.ILog, CastleComparison">
        <parameters>
          <fileName>log.txt</fileName>
        </parameters>
      </component>

      <component id="consoleLog"
                 type="CastleComparison.ConsoleLog, CastleComparison"
                 service="CastleComparison.ILog, CastleComparison">
      </component>

      <component id="algorithm"
                 type="CastleComparison.Algorithm, CastleComparison"
                 service="CastleComparison.IAlgorithm, CastleComparison">
      </component>

      <component id="runner"
                 type="CastleComparison.AlgorithmRunner, CastleComparison">
        <parameters>
          <loggers>
            <array>
              <item>${consoleLog}</item>
              <item>${fileLog}</item>
            </array>
          </loggers>
        </parameters>
      </component>

    </components>
  </castle>
</configuration>

On the other hand, configuring it with Pysor is as simple as

clr.AddReference("CastleComparison")
from CastleComparison import *

fileLog = add("fileLog", ILog, FileLog,
	{"fileName":"log.txt"})
consoleLog = add("consoleLog", ILog, ConsoleLog)

add("algorithm ", IAlgorithm , Algorithm )

add("runner", AlgorithmRunner, AlgorithmRunner,
	{"loggers": [consoleLog, fileLog]})

Clearly, I will always choose the second configuration.

To-do’s

The updated to-do list is now

  • Adding a nicer API for referencing assemblies and importing namespaces (I have now idea how to do it).
  • Adding parameters to be passed to the constructor.
  • Passing parameters as lists or arrays.
  • Dictionary based parameters
  • Referencing already registered implementation inside the same configuration script.
  • Documenting and signing the assembly
  • Lifestyle management
  • Considering turning Pysor into an Interpreter to be used as the built-in XmlInterpreter

Source Code

Please don’t forget to download the code from GitHub and try it yourself.

All remarks , ideas, bug reports, etc. will be appreciated.

Using IronPython to configure Castle Windsor II

Pysor Series

In the last article I introduced a small Castle Windsor configuration tool using IronPython. This tool enabled us to add service implementation in an easer to read way. On the other hand advanced usages like optional and constructer parameters were not possible.

In this article I will continue developing Pysor (As I called it!) to accept parameters. Before introducing the new functionality I will  show what are parameters and when and how would you want to use them. For the sake of demonstration I will borrow the demo application from the very good article series from Simone Busoli about Castle Windsor. If you didn’t read it then go read it all and come back.

The developed application is an html title retriever. It downloads an html string and then extract the title tag from it.  For downloading the the html document it uses an I Downloader service  that accepts an Uri object and downloads it if it can handle the scheme. For Example we have an HtmlDownloader, FileDownloader, etc. The other needed service is ITitleScraper which extract the <title> tag contents.

public interface IFileDownloader
{
    string Download(Uri file);
    bool SupportsUriScheme(Uri file);
}

public interface ITitleScraper
{
    string Scrape(string fileContents);
}

For the purpose of accelerating the unit tests I changed the downloader to not really download the files but return a fake text instead.

Having the constructor :

public HtmlTitleRetriever(IFileDownloader downloader, ITitleScraper scraper)
{
    AdditionalMessage = "";
    Downloader = downloader;
    Scraper = scraper;
}

with AdditionalMessage as a property indicates a short message, that will be concatenated with retrieved tile, we can now configure the container:

add( "parsingScraper" , ITitleScraper, StringParsingTitleScraper)

add( "HttpFileDownloader", IFileDownloader, HttpFileDownloader)

add( "retriver", HtmlTitleRetriever, HtmlTitleRetriever)

And everything works like expected. Now suppose we want to set the AdditionalMessage for each initiated object. Using xml configuration this could be achieved using a parameters tag  containing all parameters in a dictionary-like fashion.

The most appropriate data structure for this purpose in Python would be a hash which is equivalent to a Dictionary in the .Net  world.

Because C# in the current version doesn’t support optional or named parameters and because I don’t  know whether Python supports method overloading I added a Python method with supply the C# method with default value for missing arguments.

def add(name, service, impl, params={}):
	addComponent(name, service, impl, params)

Using this new method you can now set the AdditionalMessage value for each object:

add( "retriverWithParam", HtmlTitleRetriever, HtmlTitleRetriever,
	{'AdditionalMessage': "Test"})

We test it with

[Test]
public void CanProvideOptionalParameters()
{
    var obj = container.Resolve<HtmlTitleRetriever>("retriverWithParam");
    Assert.AreNotEqual("", obj.AdditionalMessage);
}

And of course it works.

Notice that in line 4 we specified the name of the configuration node to use because have added the service HtmlTitleRetriever twice.

The other use of parameters is to specify an implementation for some service to be used.  If you have for example another IDownloader implementation, that retrieves files sing the ftp protocol and we want to use this implementation for the constructor.  In xml we could do it using ${name} to reference the name of an already registered service. In Pysor we can use this notation as well. But to make it more like a usual program I modified the add function to return a string to be used whenever you need to reference this implementation.

Func<string, Type, Type, IDictionary<object, object> , string> action =
     (name, service, impl, parameters) =>
         {
             var pairs = parameters.ToList();
             var reg = Component
                 .For(service)
                 .ImplementedBy(impl)
                 .Named(name);

             if (pairs.Count > 0)
             {
                 var param = (from pair in pairs
                              select Parameter
                                 .ForKey(pair.Key.ToString())
                                 .Eq(pair.Value.ToString())
                             ).ToArray();
                 reg = reg.Parameters(param);
             }

             container.Register(reg);
             return "${" + name + "}";
         };

 //Inject this function into IronPython runtime
scope.SetVariable("addComponent", action);

And the Python wrapper function looks now like:

def add(name, service, impl, params={}):
	return addComponent(name, service, impl, params)

We are now ready to register a retriever that uses a concrete implementation:

ftp = add( "ftp", FtpFileDownloader, FtpFileDownloader)

add( "ftpRetriver", HtmlTitleRetriever, HtmlTitleRetriever,
	{'downloader': ftp})
[Test]
public void CanProvideSpecificImplimentationParameters()
{
    var obj = container.Resolve<HtmlTitleRetriever>("ftpRetriver");
    Assert.IsInstanceOf<FtpFileDownloader>(obj.Downloader);
}

We are finished for now.

 

To-do’s

The updated to-do list is now

  • Adding a nicer API for referencing assemblies and importing namespaces.
  • Adding parameters to be passed to the constructor.
  • Referencing already registered implementation inside the same configuration script.
  • Lifestyle management

Source Code

The source code of Pysor is available to download from GitHub

https://github.com/mouk/Pysor/