Community & Support
Home / Community & Support / Knowledge Base / Telerik OpenAccess ORM / General / Best Practices in web development with OpenAccess - Part Two

Best Practices in web development with OpenAccess - Part Two

Article Info

Rating: 4

Article information

Article relates to

 Telerik OpenAccess ORM

Created by

 Zoran Kostov

Last modified

 April 26, 2010

Last modified by

 Serge Ovanesyan


This article discusses one of the most-common concerns of ORM users – the management of the DataContext objects in a real-case web scenario. Here we will add to the Master-Page and HttpModule approaches observed in the first part of this series. The final goal of this article is to successfully manage the scope lifetime by taking advantage of the Items collection of the HttpContext. 

This way we are obtaining the context on a per-request basis. This approach of managing the context lifecycle is especially powerful in web projects where web pages are built from multiple web user controls.  That means, a context will be obtained once on every request on a web-page and then shared among all web user controls composing the page as well as the page itself. That way we have consistency between the data that multiple parts of the web page use with different logic. Another advantage is the ability to share data between different user controls because the data all controls operate come from the same Context instance. To be able to obtain the context in such generic manner we need a class that we will use as a factory for our object scope instances.

Bellow is a basic implementation for such class:

public class ContextFactory
{
    public static NorthwindEntityDiagrams GetContextPerRequest(HttpContext context)
    {
        if (context == null)
        {
            return new NorthwindEntityDiagrams();
        }
        else
        {
            string key = context.GetHashCode().ToString("x") + System.Threading.Thread.CurrentContext.ContextID.ToString();
            NorthwindEntityDiagrams ctx = null;
            if (context == null)
            {
                ctx = new NorthwindEntityDiagrams();
            }
            else
            {
                ctx = (NorthwindEntityDiagrams)context.Items[key];
                if (ctx == null)
                {
                    ctx = new NorthwindEntityDiagrams();
                    context.Items[key] = ctx;
                }
            }
            return ctx;
        }
    }
}

The ContextFactory class has only one method - GetContextPerRequest. Then we create a key based on the ContextID of the context of the current thread where the request is processed. That key is a unique for every HttpRequest on a page. Then there is a sample logic that returns the context from the Items collection of the HttpContext and if it is not yet in that collection we just initialize it and place it in the collection.

Example:

We have a sample web page containing of two web user control. The first one is called ComboBoxUserControl.ascxthat has just a RadComboBox on it  and the other one is GridUserControl.ascx that holds a RadGrid.

Default.aspx:

<telerikSample:ComboBoxControl ID="ComboBoxControl1" runat="server" />        
<telerikSample:GridUserControl ID="GridUserControl1" runat="server"/>

The code for the user controls is the following:

ComboBoxUserControl.ascx:

<telerik:RadComboBox ID="RadComboBox1" Height="200px" AutoPostBack="true" EnableVirtualScrolling="true" runat="server">
</telerik:RadComboBox>

ComboBoxUserControl.cs:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        var ctx = ContextFactory.GetContextPerRequest(this.Context);
        var result = from cust in ctx.Customers
                     select cust;
        RadComboBox1.DataTextField = "ContactName";
        RadComboBox1.DataValueField = "CustomerId";
        RadComboBox1.DataSource = result;
        RadComboBox1.DataBind();
    }
}

GridUserControl.ascx:

<telerik:RadGrid ID="RadGrid1" runat="server"
    onneeddatasource="RadGrid1_NeedDataSource" AllowPaging="True"
    GridLines="None">
</telerik:RadGrid>

GridUserControl.cs:

protected void RadGrid1_NeedDataSource(object source, Telerik.Web.UI.GridNeedDataSourceEventArgs e)
{
    NorthwindEntityDiagrams ctx = ContextFactory.GetContextPerRequest(this.Context);
    var result = from ord in ctx.Orders
                 select ord;
    RadGrid1.DataSource = result;
}

Both controls are doing similar operations. They get an context, fetch some result set from the database and bind to that result set. First the Page_Load of the combo-box control is called and there we initialize the context and place in the HttpContext.Items collection. The grid then uses the same context that was used by the combo-box from the other web user control and does a separate call to the database to load some data on its own.

In the code behind of the page there is additional logic that filters the grid with the selected value from the Combo-Box.

private RadComboBox comboFromUserControl;
private RadGrid gridFromUserControl;
protected void Page_Init(object sender, EventArgs e)
{
    comboFromUserControl = this.ComboBoxControl1.ComboBox;
    gridFromUserControl = this.GridUserControl1.Grid;
    comboFromUserControl.SelectedIndexChanged += new RadComboBoxSelectedIndexChangedEventHandler(comboFromUserControl_SelectedIndexChanged);
}
 
 
void comboFromUserControl_SelectedIndexChanged(object o, RadComboBoxSelectedIndexChangedEventArgs e)
{
    var ctx = ContextFactory.GetContextPerRequest(this.Context);
    string selectedId = e.Value;
    Customer customerFromCombo = ctx.Customers.Where(cust => cust.CustomerID.Equals(selectedId)).First();
    var result = from ord in ctx.Orders
                 where ord.Customer == customerFromCombo
                 select ord;
    gridFromUserControl.DataSource = result;
    gridFromUserControl.DataBind();
}

The final step that should never be overlooked is the disposal of the context as well as un-wiring from the combo-box event in the Page_Unload method.
protected void Page_Unload(object sender, EventArgs e)
{
    var ctx = ContextFactory.GetContextPerRequest(this.Context);
    ctx.Dispose();
    comboFromUserControl.SelectedIndexChanged -= new RadComboBoxSelectedIndexChangedEventHandler(comboFromUserControl_SelectedIndexChanged);
}

One of the greatest things about using the HttpContext way of handling the context is that with little modifications basically the same workflow can be followed with web parts in Component Management Systems like Sitefinity, SharePoint and DotNetNuke, expect more on that in the future.
The full code of this example can be found in the Telerik OpenAccess code library.

Comments

If you'd like to comment on this KB article, please, send us a Support Ticket.
Thank you!

Please Sign In to rate this article.