Showing posts with label podcast. Show all posts
Showing posts with label podcast. Show all posts

May 17, 2013

Generating Exception Classes in C# with T4

Being inspired by Marten Range's talk about T4 (Text Template Transformation Toolkit) on dotnetrocks, I decided to try it out for a problem that Marten mentioned in the beginning of the talk and that I have recently encountered at work - generating exception classes in C#. According to MSDN documentation, "derived exception classes should define four constructors". If you have more than one custom exception in your class, coding them manually is a boring task. So, I tried to figure out how much time will it take me to learn how to solve this small problem with T4.

Let's assume we have a program that requires to input string between 1 and 3 characters long, and throws two different exceptions if input is shorter or longer:

static void Main(string[] args)
{
    Console.Write("Input a string longer than 1 chars but shorter than 3 chars: ");
    string input = Console.ReadLine();
    if (input.Length < 2) throw new InputStringTooShortException();
    else if (input.Length > 2) throw new InputStringTooLongException();
    else Console.WriteLine("Thank you!");
}

The first solution that came to my mind was to have a master template file which would use a token instead of exception type name and then specify value for this token by consuming template files.

Let's create the template class that will use provided name of the exception type and generate all the constructors.
ExceptionTemplate.tt:

<#@ output extension=".cs" #>
using System;

[Serializable()]
public class <#= ExceptionTypeName #>Exception : ApplicationException
{
    public <#= ExceptionTypeName #>Exception() : base() { }
    public <#= ExceptionTypeName #>Exception(string message) : base(message) { }
    public <#= ExceptionTypeName #>Exception(string message, Exception inner) : base(message, inner) { }
    protected <#= ExceptionTypeName #>Exception(
        System.Runtime.Serialization.SerializationInfo info,
        System.Runtime.Serialization.StreamingContext context) { }
}

<#+ string ExceptionTypeName = string.Empty; #>

Within this template we used expression block within markers <#= and #> to denote exception type name that is evaluated, converted to a string, and written as an output. We also used class feature syntax within markers <#+ and #> to provide class member ExceptionTypeName that consuming templates will provide as follows:

InputStringTooShortException.tt:

<#@ template language="C#" #>
<# this.ExceptionTypeName = "InputStringTooShort"; #>
<#@include File="ExceptionTemplate.tt" #>

InputStringTooLongException.tt:

<#@ template language="C#" #>
<# this.ExceptionTypeName = "InputStringTooLong"; #>
<#@include File="ExceptionTemplate.tt" #>

Above solution looks straightforward, but the problem with it is that we need one additional template per exception. We can avoid this by making modification to our ExceptionTemplate.tt to have a method that will accept exception type name as a parameter: 

<#@ output extension=".cs" #>
using System;

<#+ void GenerateException(string exceptionTypeName) { #>

    [Serializable()]
    public class <#= exceptionTypeName #>Exception : ApplicationException
    {
        public <#= exceptionTypeName #>Exception() : base() { }
        public <#= exceptionTypeName #>Exception(string message) : base(message) { }
        public <#= exceptionTypeName #>Exception(string message, Exception inner) : base(message, inner) { }
        protected <#= exceptionTypeName #>Exception(
            System.Runtime.Serialization.SerializationInfo info,
            System.Runtime.Serialization.StreamingContext context) { }
    }

<#+ } #>
Now, we need only one template for both exceptions that we want to generate:
GeneratedExceptions.tt:

<#@ template language="C#" #>
<#@include File="ExceptionTemplate.tt" #>

<# GenerateException("InputStringTooLong"); #>
<# GenerateException("InputStringTooShort"); #>

With this solution, we store all exception classes within one file, but if you need to store them in separate files, you can use a trick described in Oleg Sych's blog. By the way, his blog contains lots of information about using T4 ;)


http://www.linkedin.com/in/oldbam

October 15, 2008

Software Engineering Radio - Ebay Architecture Principles

Recently I have discovered a site with fabulous podcasts dedicated to various questions in software engineering, Software Engineering Radio (http://se-radio.net/)

There was an episode on Ebay architecture principles, some of the items from which I decided to rewrite here.

  • Partition everything. "If you can't split it - you can't scale it"

  • Functional segmentation. The selling system is distinct from the bidding system and from the buying system. Each system is supported by separate DBs.

  • Horizontal splitting. Each functional segment is chopped into smaller pieces. (e.g. if key ends in 1 - the first database is employed, if key ends in 2 - the second database is used, and so on.) On Ebay it is done in a way similar to Hibernate Shards.

  • No distributed transactions are used.
    The Details table is updated before the Master table, if the first fails, the second won't be updated; if the second fails, the asynchronous event will later recover the database from the inconsistent state.

    If the Item DB and the User DB should be updated, the importance of having the first one in consistent state is more urgent, so only the Item DB is updated and then asynchronous event is generated to update the User DB later.

  • No session state is stored on the server. For multi-pages functionality the following approaches are used: URL rewriting, cookies (all the state information is put in the cookie), writing current session data to the scratch database (for multi-pages flows)

  • Application features can be switched on and off without code changes
    The code deployment is different from feature deployment.
    Features can be checked for the availability by the code.
The whole podcast is available at this link



http://www.linkedin.com/in/oldbam