20 December 2006

First Bulgarian .NET Book is here

Second volume from the first Bulgarian book about .NET is out. You can download free copy from here. Printed version will be available after a month.

17 November 2006

Windows Forms data binding and notification of changed properties

Yesterday a college of mine asked me a question: "How to refresh TextBox control in Windows forms application binded to a property of object, when the property change its value?". The solution is very simple, but according to me not very well documented (at least in books I read).


Solution: Provide event named PropertyNameChanged, where PropertyName is the name of property binded to the TextBox. During the binding process, the text box inspects binded object for event with the mentioned signature and binds to it. The sample code looks like this:


public class Customer
{
    private string mName;
 
    public string Name
    {
        get { return mName; }
        set
        {
            mName = value;
            if (NameChanged != null)
            {
                NameChanged(this, EventArgs.Empty);
            }
        }
    }
 
    public event EventHandler NameChanged;
}
 
Customer cust = new Customer();
textBox1.DataBindings.Add("Text", cust, "Name");
 
Another possible solution is to remove and add binding of the text box to the object. You can write general routine to loop through each control for a given form and remove-add binding. This is nasty solution of course.

11 September 2006

Cool conference in Bulgaria

DevReach - one of the most exiting conferences about Microsoft technologies in Bulgaria is coming. According to the program, some of the world leading industry speakers will present quite interesting lectures. Hope we will meet there.

Google toolbar 4

This morning I was amazed! A few minutes after turning on my PC a small balloon appeared. The message in the balloon was something about Google toolbar update. Who cares, was my first reaction. But when the update was finished I was surprised to learn that LONG WAITING FEATURES LIKE ACCESSING BOOKMARKS FROM ANY COMPUTER are already present. Believe me - this is like a elixir of life for me. I'm using one PC at work, one PC at home and one laptop. Managing bookmarks in situation like this is almost nightmare. In the past there were some other decision of this problem, but none of them was so elegant as Google toolbar. BTW, Microsoft are developing the same service, but as far as I know this feature is still in beta.
The other features I like are SpellCheck and Translate. If you are inspired, install the toolbar from here for WinXP and IE. Enjoy!

04 September 2006

ADO.NET Entity Framework ContextObject and ASP.NET application

Last month Microsoft published first CTP of ADO.NET Entity Framework. For more info - look here. Although Microsoft is still planning integration between Entity Framework and ASP.NET, I want to show you how to handle ADO.NET Entity Framewrok context object in ASP.NET application. This post is inspired from NHibernate session management.
The idea is simple: Context object will be stored in ASP.NET session and after the request HTTPModule will free it. I'm using ASP.NET session instead of ASP.NET context to further extend this example to support session per application transaction strategy. If you are wondering what is "session per application transaction" take a look at NHibernate session management. Here is the code of the implementation:

public class ContextManager<T>where T: ObjectContext, new()
{
    public static T ObjectContext
    {
        get
        {
            T resultContext;
 
            if (HttpContext.Current.Items.Contains(
                ContextConst.CONTEXT_OBJECT_SESSION_KEY))
            {
                resultContext =
                    (T)HttpContext.Current.Items[
                        ContextConst.CONTEXT_OBJECT_SESSION_KEY];
            }
            else
            {
                resultContext = new T();
                HttpContext.Current.Items[ContextConst.CONTEXT_OBJECT_SESSION_KEY] = 
                    resultContext;
            }
 
            return resultContext;
        }
    }
 
    public static bool isActiveObjectContext
    {
        get
        { 
            return HttpContext.Current.Items.Contains(
                ContextConst.CONTEXT_OBJECT_SESSION_KEY);
        }
    }
 }

public class ContextHttpModule : IHttpModule 
{
    #region IHttpModule Members
 
    public void Init(HttpApplication context)
    {
        context.EndRequest += new EventHandler(OnEndRequest);
    }
 
    public void Dispose()
    {
        //Intentionaly not implemented
    }
 
    public void OnEndRequest(Object sender, EventArgs e)
    {
        if (HttpContext.Current.Items.Contains(ContextConst.CONTEXT_OBJECT_SESSION_KEY))
        {
            ObjectContext contextObject = 
                (ObjectContext)HttpContext.Current.Items[
                    ContextConst.CONTEXT_OBJECT_SESSION_KEY];
 
            contextObject.Dispose();
        }
    }
 
    #endregion
}


internal class ContextConst
{
    public const string CONTEXT_OBJECT_SESSION_KEY =
        "ContextConst.CONTEXT_OBJECT_SESSION_KEY";
}

Now, lets look how the code above can be used. First lets make some corrections to web.config file:

<connectionStrings>
  <add name="Duwamish7Model.Duwamish7" 
       connectionString="metadata=C:\Temp\ContextObject\Model;
          mapping=C:\Temp\ContextObject\Model;
          provider=System.Data.SqlClient;
          provider connection string=&quot;Data Source=ns-server;
          Initial Catalog=Duwamish7;Integrated Security=True&quot;"
    providerName="System.Data.Mapping" />
</connectionStrings>


<httpModules>
  <add name="ContextObjectManager"
       type="ObjectContextManager.ContextHttpModule, ObjectContextManager"/>
</httpModules>
Having all of the above done, we can write somethig like this:

Duwamish7 db = ContextManager<Duwamish7>.ObjectContext;
 
Query<Authors> query = db.GetQuery<Authors>(
    "SELECT VALUE a FROM Authors AS a WHERE a.PKId > 144");
 
Repeater1.DataSource = query;
Repeater1.DataBind();


P.S. The code above is not tested for concurrency problems.

03 September 2006

WCF and WS Eventing

WCF (aka Indigo) is the latest communication technology from Microsoft (still in beta). Although there are a lot of goodies in this technology, something really useful for me is missing - implementation of WS Eventing. If you are wondering why - this article gives the answer. Fortunately there is already non-Microsoft implementation. Read this article if you are interested.

24 August 2006

Finally it is true!

Yesterday, PFC Levski Sofia did it. The team had succeeded to qualify for the UEFA champions league group stage for the first time in Bulgarian football history. Although I'm fan of the CSKA Sofia the success of Levski makes me happy. More info - here.

23 August 2006

Microsoft SQL Server and Ad-Hock queries optimization

Yesterday I was surprised to learn that Microsoft SQL Server 2005 makes behind the scene parameterization of ad-hock queries. For example, lets have the following query:
SELECT ID, Name FROM Article WHERE Price > 100

SQL Server 2005 will replace constant literal values (100 in this example) by variables and this way query plan will be reuses for all queries similar to
SELECT ID, Name FROM Article WHERE Price > @p1

Not all of the ad-hock queries can be parameterized. If you are interested read this article.

Attribute based transaction management and NHibernate

In my previous post about NHibernate session management I presented a session per request strategy for session management in ASP.NET application. I will extend this example to show you how to declaratively manage transactions via attributes. Take a look at the GenericDAO.Save method:

public void Save(T entity)
{
    bool manageTransaction = ! orm.isActiveTransaction;
    if (manageTransaction)
    {
        orm.BeginTransaction(IsolationLevel.ReadCommitted);
    }
    try
    {
        orm.session.SaveOrUpdate(entity);
 
        if (manageTransaction)
        {
            orm.CommitTransaction();
        }
    }catch(Exception e)
    {
        if (manageTransaction)
        {
            orm.RollbackTransaction();
        }
 
        throw e;
    }            
}

Almost 90% of the code is for transaction management. It will be nice if we can write something like:

[Transaction(IsolationLevel.ReadCommitted)]
public void Save(T entity)
{
    mOrm.session.SaveOrUpdate(entity);
    mOrm.session.Flush();
}

To achieve this, I will use Spring.NET to intercept method call of the DAO. Before method marked with TransactionAttribute is executed a transaction will be started and then committed after method is executed. Although .NET provides solution for intercepting method calls via ContextBoundObject, I will use Spring.NET because this way my DAO object must implement just one interface instead of inheriting from ContextBoundObject.
Lets begin with the implementation. First I will declare the attribute used to mark transaction sensitive methods:

[AttributeUsage(AttributeTargets.Method)]
public class TransactionAttribute : Attribute
{
    private IsolationLevel mIsolationLevel;
 
    public TransactionAttribute()
    {
        mIsolationLevel = IsolationLevel.ReadCommitted;
    }
 
    public TransactionAttribute(IsolationLevel aIsolation)
    {
        mIsolationLevel = aIsolation;
    }
 
    public IsolationLevel isolationLevel
    {
        get { return mIsolationLevel; }
        set { mIsolationLevel = value; }
    }
 
}

Now I will decrare the class responsible for starting and committing transactions. There are a lot of specific issues about method interception and Spring.NET so if you are not familiar with them read the documentation about Spring.NET. The class looks like:

public class TransactionAroundAdvice : IMethodInterceptor
{
    OrmManager mOrm;
 
    public TransactionAroundAdvice()
    {
        mOrm = OrmManagerFactory.GetInstance();
    }
 
    private TransactionAttribute GetTransactionAttribute(MethodInfo aMethod)
    {
        object[] attributes = aMethod.GetCustomAttributes(
            typeof(TransactionAttribute), true);
 
        if (attributes.Length != 1)
        {
            //TODO: Throw more meaningfull exception and message
            throw new Exception("Transaction Attribute is missing");
        }
        return (TransactionAttribute)attributes[0];
    }
 
    public object Invoke(IMethodInvocation invocation)
    {
        bool manageTransaction = ! mOrm.isActiveTransaction;
        if (manageTransaction)
        {
            TransactionAttribute transactionAttribute =
                GetTransactionAttribute(invocation.Method);
            mOrm.BeginTransaction(transactionAttribute.isolationLevel);
        }
 
        //TODO: Find way to compare isolation level from TransactionAttribute and
        //current active transaction if manageTransaction == false
 
        object returnValue;
        try
        {
            returnValue = invocation.Proceed();
 
            if (manageTransaction)
            {
                mOrm.CommitTransaction();
            }
        }catch(Exception e)
        {
            if (manageTransaction)
            {
                mOrm.RollbackTransaction();
            }
 
            if ((e is TargetInvocationException) && (e.InnerException != null))
            {
                //Because when AOP is enables, method is invoked via reflection
                //TargetInvocationException is thrown. This exception is most likely
                //to confuse application developer, so it is removed
                throw e.InnerException;
            }
            else
            {
                throw e;
            }
        }            
 
        return returnValue;
    }
}

When a method marked with TransactionAttribute is intercepted then Invoke method from TransactionAroundAdvice class is called. Now lets see how our DAO class looks like when transaction management code is removed:

public class AttributeEnabledDAO<T>: IDAO<T>
{
    public AttributeEnabledDAO()
    {
        mOrm = OrmManagerFactory.GetInstance();
    }
 
    private OrmManager mOrm;
 
    #region IDAO Members
 
    public T Load(object id)
    {
        return (T) mOrm.session.Load(typeof(T), id);
    }
 
    [Transaction(IsolationLevel.ReadCommitted)]
    public void Save(T entity)
    {
        mOrm.session.SaveOrUpdate(entity);
        mOrm.session.Flush();
    }
 
    #endregion
}

Much more simple. Example of using AttributeEnabledDAO is given bellow:

ProxyFactory articleDAOFactory = new ProxyFactory(
    new AttributeEnabledDAO<Article>());
 
articleDAOFactory.AddAdvisor(new DefaultPointcutAdvisor(
    new AttributeMatchMethodPointcut(typeof(TransactionAttribute)),
    new TransactionAroundAdvice()));
 
IDAO<Article> articleDao;
lock (synchObject)
{
    articleDao = (IDAO<Article>) articleDAOFactory.GetProxy();
}
 
Article article = articleDao.Load(1);
article.Name = "Paracetamol";
article.SalePrice = rnd.NextDouble();
articleDao.Save(article);

16 August 2006

ADO.NET vNext CTP is out

Microsoft has just released ADO.NET vNext CTP. This CTP includes the preview build of the long waiting ADO.NET Entity Framework. This Entity Framework is Microsoft's ORM tool. If you are wondering what is ORM tool take a look at my post about
NHibernate session management.
Presentation with features of Entity Data Model can be found here. If somehow Link* technologies looks messy for you, taka a look at this presentation.

06 August 2006

Querying Microsoft SQL Server trace files

Have you ever wanted to be able to query saved SQL Server profiler trace files (*.trc)? Yes! Then you need to use fn_trace_gettable.

05 August 2006

Interview with Anders Hejlsberg

Take a look at this interview with Anders Hejlsberg. It's not about a future technology. It's about himself. Watching this video you will find answers to questions like: Why Anders left Borland and joined Microsoft? What is the secret of his success? Anders talks for the time working on projects like: Turbo Pascal, Delphi, C#. Enjoy!

Mocking static methods

Yes, the title is correct. Mocking static methods in .NET is possible with TypeMock library. There is no need to redesign you classes just to test them. In fact there is no need to write additional code to your classes. This is possible because TypeMock uses profiler's API to handle execution of methods and creation of classes. For a list of features look here.
Using TypeMock is pretty easy. In my previous post about NHibernate session management I'm using a static method to create appropriate session manager (take a look at GenericDAO constructor). The test of the constructor may be something like:


[TestFixture]
public class GenericDAOTest
{
    [SetUp]
    public void InitTest()
    {
        MockManager.Init();
        //ormManagerMock = MockManager.Mock(typeof(PerRequestWebManager));
        ormManagerFactory = MockManager.Mock(typeof(OrmManagerFactory));
    }
 
    //private Mock ormManagerMock;
    private Mock ormManagerFactory;
    private GenericDAO<Article> articleDAO;
 
    [TearDown]
    public void FinalizeTest()
    {
        MockManager.ClearAll();
    }
 
    [Test]
    public void TestDAOConstructor()
    {
        ormManagerFactory.ExpectAndReturn("GetInstance",
            new PerRequestWebManager());
 
        articleDAO = new GenericDAO<Article>();
 
        MockManager.Verify();
    }
}
 

Although TypeMock is powerful and easy to use library, there are some disadvantages. For example in the free version, when the test is started for first time, a popup dialog appears and invites you to buy the product. Also not all of the .NET types can be mocked (for more information take a look at this thread).

25 July 2006

NHibernate Session Management

I'm big fan of NHibernate since early beta. Unfortunately this tool is not very popular among .NET developers, so I'm planning to blog a lot about this framework. For those of you who don't know, NHibernate is ORM (Object-Relational-Mapping) tool. Basically ORM tools are used to "persist" C# objects into RDBMS system. More detail explanation of ORM tools is available here.
NHibernate handles loading/saving objects to RDBMS via it's own implementation of session object. Until now, I'm familiar with 3 ways for handling NHibernate sessions:
  • create session per each database operation - session is created before and destroyed after each operation with database. This is very ineffective way, because some features like lazy loading are unavailable. Also including several database operations in transaction is impossible.
  • create session per each request - session is created before and destroyed after each HTTP request. This is my favorite strategy, because it is effective and very easy for implementation. I'll give example for possible implementation in this post.
  • create session per each application transaction - session is created before and destroyed after each application transaction. Example for application transaction is adding invoice with invoice items.

So, lets begin with the implementation of session per request strategy. If you are reading this post you are most likely a developer and probably as most developers prefer to read source code instead of boring documentation. So I'll explain all of the classes in brief and will post full source code. First I'll declare a base abstract class for all of the session strategies.



public abstract class OrmManager
{
    public OrmManager()
    {
    }
 
    static NHibernate.Cfg.Configuration mConfiguration = null;
    static volatile ISessionFactory mSessionFactory = null;
    static object mFactorySyncObject = new object();
 
    public abstract ISession session
    {
        get;
    }
 
    public IDbConnection sessionConnection
    {
        get { return session.Connection; }
    }
 
    public ISession NewSession()
    {
        ISessionFactory sessionFactory = GetSessionFactory();
 
        return sessionFactory.OpenSession();
    }
 
    public abstract bool isActiveSession
    {
        get;
    }
 
    public abstract void closeSession();
 
    private const string HBM_ASSEMBLY_NAME_SECTION = "HbmAssemblyName";
 
    private ISessionFactory GetSessionFactory()
    {
        if (mSessionFactory == null)
        {
            lock (mFactorySyncObject)
            {
                if (mSessionFactory == null)
                {
                    string hbmAssemblyName =
                        ConfigurationManager.AppSettings[HBM_ASSEMBLY_NAME_SECTION];
 
                    mConfiguration = new NHibernate.Cfg.Configuration();
                    mConfiguration.AddAssembly(hbmAssemblyName);
 
                    mSessionFactory = mConfiguration.BuildSessionFactory();
                }
            }
        }
 
        return mSessionFactory;
    }
 
    public void BeginTransaction(IsolationLevel isolation)
    {
        session.BeginTransaction(isolation);
    }
 
    public void CommitTransaction()
    {
        session.Transaction.Commit();
    }
 
    public void RollbackTransaction()
    {
        session.Transaction.Rollback();
    }
 
    public bool isActiveTransaction
    {
        get
        {
            return ((session.Transaction != null) &&
                (!session.Transaction.WasCommitted) &&
                (!session.Transaction.WasRolledBack));
        }
    }
}

Next, I'll implement the class responsible for session per request management. The following class implements IHttpModule so, we can handle end of the request and close any open sessions.


public class PerRequestWebManager : OrmManager, IHttpModule
{
    public PerRequestWebManager()
    {
    }
 
    private const string NHIBERNATE_SESSION_KEY = "NHIBERNATE_SESSION";
 
    public override ISession session
    {
        get
        {
            ISession resultSession;
 
            if (HttpContext.Current.Items.Contains(NHIBERNATE_SESSION_KEY))
            {
                resultSession =
                    (ISession)HttpContext.Current.Items[NHIBERNATE_SESSION_KEY];
            }
            else
            {
                resultSession = NewSession();
                HttpContext.Current.Items[NHIBERNATE_SESSION_KEY] = resultSession;
            }
 
            return resultSession;
        }
    }
 
    public override bool isActiveSession
    {
        get { return HttpContext.Current.Items.Contains(NHIBERNATE_SESSION_KEY); }
    }
 
    public override void closeSession()
    {
        if (isActiveSession == true)
        {
            if (isActiveTransaction == true)
            {
                RollbackTransaction();
            }
 
            session.Close();
            HttpContext.Current.Items.Remove(NHIBERNATE_SESSION_KEY);
        }
    }
 
    #region IHttpModule
 
    public void Init(HttpApplication context)
    {
        context.EndRequest += new EventHandler(OnEndRequest);
    }
 
    public void Dispose()
    {
        //Intentionaly not implemented
    }
 
    public void OnEndRequest(Object sender, EventArgs e)
    {
        closeSession();
    }
 
    #endregion
}

Now I'll make one generic DAO class with the help of previos PerRequestWebManager.


public class GenericDAO<T>
{
    public GenericDAO()
    {
        orm = OrmManagerFactory.GetInstance();
    }
 
    private OrmManager orm;
 
    public T Load(object id)
    {
        return (T) orm.session.Load(typeof(T), id);
    }
 
    public void Save(T entity)
    {
        bool manageTransaction = ! orm.isActiveTransaction;
        if (manageTransaction)
        {
            orm.BeginTransaction(IsolationLevel.ReadCommitted);
        }
        try
        {
            orm.session.SaveOrUpdate(entity);
 
            if (manageTransaction)
            {
                orm.CommitTransaction();
            }
        }catch(Exception e)
        {
            if (manageTransaction)
            {
                orm.RollbackTransaction();
            }
 
            throw e;
        }            
    }
}

public class OrmManagerFactory
{
    private OrmManagerFactory()
    {
    }
 
    private const string ORM_MANAGER_TYPE_SECTION = "OrmManager";
 
    public static OrmManager GetInstance()
    {
        string ormType = ConfigurationManager.AppSettings[ORM_MANAGER_TYPE_SECTION];
        if (ormType == typeof(PerRequestWebManager).Name)
        {
            return new PerRequestWebManager();
        }
        else
        {
            throw new Exception("Unknown ORM manager type");
        }
    }
}

And here's how all of the above can be used in ASP.NET application:


GenericDAO<Article> articleDao = new GenericDAO<Article>();
 
Article article = articleDao.Load(1);
article.Name = "Paracetamol";
article.SalePrice = rnd.NextDouble();
articleDao.Save(article);

If you are interested I can mail you full source of this post. Enjoy!

18 July 2006

Free Microsoft Office SharePoint Server 2007 Book

If you are interested in SharePoint Products and Technologies don't miss to read
7 Development Projects for Microsoft Office SharePoint Server 2007 and Windows SharePoint Services 3.0. The book is free for download and is based on Beta 1 version of upcoming new version of SharePoint products.

17 July 2006

Formatting source code posted in blog

Today I found a very useful tool for formatting a source code represented in HTML format. The tool is named CSAH (Copy Source As Html) and is actually a plug-in for Visual Studio 2003/2005. If you are interested, download it from here. Below is a screenshot from the plug-in in action.





BTW, the source code in my previos post about GridView is formatted with this tool.

14 July 2006

GridView’s header and empty DataSource

The successor of DataGrid in ASP.NET 2.0 – GridView behaves unusually sometimes. For example if binded ObjectDataSource is empty, then GridView’s header is not rendered. This is not the required behavior in most of the cases. If you want to show the header of the GridView when binded data source is empty, there are several solutions, but I will describe the one I like most.

Solution in brief: Subclass GridView control, override CreateChildControls method and manualy create header if binded DataSource is empty. The implementation of CreateChildControls method may look like:



protected override int CreateChildControls(IEnumerable dataSource,
    bool dataBinding)
{
    int numRows = base.CreateChildControls(dataSource, dataBinding);
 
    if (numRows == 0)
    {
        Table table = new Table();
        table.ID = this.ID;
 
        GridViewRow row = base.CreateRow(-1, -1,
                DataControlRowType.Header, DataControlRowState.Normal);
 
        DataControlField[] fields = new
                DataControlField[this.Columns.Count];
        this.Columns.CopyTo(fields, 0);
        this.InitializeRow(row, fields);
        table.Rows.Add(row);
        this.Controls.Add(table);
    }
 
    return numRows;
}


The code above adds only a header to the grid. If you need you can add another empty row, where appropriate message may be shown.

Adding footer is a little bit tricky. GridView exposes a public property for managing the footer. So the footer added by you, must be accessible via this property. The solution to the problem is to override the virtual property FooterRow (To Microsoft ASP.NET 2 Team: Thank you for making this property virtual. Unfortunately some methods in ASP.NET 2 are not virtual and extending the framework sometimes is not so easy). According to the explanations above the implementation may look like:



private GridViewRow mFooterRow = null;
 
public override GridViewRow FooterRow
{
    get
    {
        if (mFooterRow != null)
        {
            return mFooterRow;
        }
        else
        {
            return base.FooterRow;
        }
    }
}
 
protected override int CreateChildControls(IEnumerable dataSource,
    bool dataBinding)
{
    this.mFooterRow = null;
 
    int numRows = base.CreateChildControls(dataSource, dataBinding);
 
    if (numRows == 0)
    {
        Table table = new Table();
        table.ID = this.ID;
 
        GridViewRow row = base.CreateRow(-1, -1,
            DataControlRowType.Header, DataControlRowState.Normal);
 
        DataControlField[] fields = new
            DataControlField[this.Columns.Count];
        this.Columns.CopyTo(fields, 0);
        this.InitializeRow(row, fields);
        table.Rows.Add(row);
 
        this.mFooterRow = base.CreateRow(-1, -1,
            DataControlRowType.Footer, DataControlRowState.Normal);
        fields = new DataControlField[this.Columns.Count];
        this.Columns.CopyTo(fields, 0);
        this.InitializeRow(mFooterRow, fields);
        table.Rows.Add(mFooterRow);
        this.Controls.Add(table);
    }
 
    return numRows;
}

During the creation of the component I remembered the old Delphi days. Creating new .NET control is almost as easy and funny as it was in Delphi.

WSS2 SP2 and .NET 2 Bug

A few weeks ago I was surprised by a very annoying bug in Windows SharePoint Services SP2 running under .NET Framework 2.0. When a page is customized with FrontPage (in this case the layout of the page is stored in SQL Server) and web part compiled with .NET 2.0 is imported to this page, the following exception is thrown:

Invalid postback or callback argument. Event validation is enabled using
<pages enableEventValidation="true"/> in configuration or
<%@ Page EnableEventValidation="true" %> in a page. For security
purposes, this feature verifies that arguments to postback or callback events
originate from the server control that originally rendered them. If the data is
valid and expected, use the ClientScriptManager.RegisterForEventValidation
method in order to register the postback or callback data for validation.


After some quick and unsuccessful attempts to resolve the exception, rapid search in google proved that this is really a bug.

Fortunately this bug is not present in SharePoint 2007 Beta 2 (I have tested it).