April 2008 - Posts

You may have noticed that the Page has an items collection.  This items collection can store any information, as it's a local dictionary.  I could not find anywhere where the dictionary is serialized and stored, so the dictionary is only temporary and has to be reloaded on every page load.  If you've dug around the .NET framework, you may have seen that the web parts manager and AJAX script manager utilize this, as it's a great way to get a reference to a component.  I've even done this in my code, so in a class I may do on initialization:

this.Page.Items[typeof(MyManager)] = this;

This code exists within the web control (of type MyManager above).  Any components that use MyManager can reference it via the Items collection, or it's possible to create a static method that returns:

public static MyManager GetManager(Page page)
{
    return (MyManager)page.Items[typeof(MyManager)];
}

And an instance of the manager is returned to any caller.  I really like this approach for certain things, but I ran into a jam; in a component I had, I tried this approach and it didn't work.  I had a faulty assumption.  See, the page class exposes properties named the same that exist on the System.Web.HttpContext class; in the page class, it simply returns the current context's instance of the property.  I thought it was the same with the Items property in this case.

But no, it isn't; HttpContext has it's own separate Items dictionary, which you can use at a more globular level.  I got myself out of a jam in a component this way; I was able to do:

if (HttpContext.Current != null)
    SomeComponent comp = (SomeComponent)HttpContext.Current.Items[typeof(SomeComponent)];

And make it available in a class that isn't generally web accessible (doesn't inherit from Control and have any references to the page class, viewstate, etc).

Posted by bmains | 3 comment(s)
Filed under: ,

One of the problems you may experience is the issue of postbacks with the "staleness" of queried data.  Because ASP.NET is stateless, when after unloading resources, all previously known resources are gone.  A common way to keep data around is to store it in the cache.  So if there is a commonly referenced LINQ business object in an ASP.NET site, it can be cached in the system.

The problem you may experience with this is that you can't use the object in certain situations.  You may get an error stating that the object isn't new and wasn't queried with the current instance of the data context class; this is because an object originally queried on the first page load is cached, the data context is destroyed, and on the next load, the cached object is retrieved.

This object can be used to reference it's child data, especially if you've loaded the related data in an immediate fashion.  What I experienced is an issue with updating data using this object or its related data as a reference.  If you assign the object reference to a recently queried object, you may get an error stating that the object isn't new and isn't known by the current data context.

A solution could be to cache the data context; I personally don't like to do that because that's a lot of data to store in the cache (depending on the size of the application).

Posted by bmains | with no comments
Filed under: ,

I've mentioned before (probably several times) about using LINQ business object references instead of key (or other) values in your BAL or DAL code.  Though I have mentioned it before, I decided to come up with a few scenarios.  The first scenario is this:

//BAL method
public string GetCustomerFormattedAddress(int customerKey) { }

This is assuming we have a Customer object, and this object has a foreign key relationship to the Address object collection.  A customer can more, therefore a history of addresses can be built.  However, the method passes in the key value.  Using this approach, this often lead to something like this as its body:

var address = from a in this.Context.Addresses
                    join ca in this.Context.CustomerAddresses
                    on a.AddressKey equals ca.AddressKey
                    where ca.CustomerKey == customerKey
                    && ca.EndDate == null
                    select a;

if (address.Count() == 0)
    return string.Empty;
else
    return "<formatted address>";

This depicts a many-to-many table in between the addresses and customers tables, in case more than one people at the same address exist.  In addition, to get the most current address, look for the EndDate equal to null.  So, using this approach, the latest address is retrieved, which works.  However, often this is called by:

lblShipToAddress.Text = bal.GetCustomerFormattedAddress(this.SelectedCustomer.CustomerKey);

Again, this all works.  But it defeats a purpose of LINQ, which is to provide a drill-down mechanism through a database hierarchy.  I believe a better approach would be to do this:

public string GetCustomerFormattedAddress(Customer customer)
{
    var addressJoin = from ca in customer.CustomerAddresses.Where(ca => ca.EndDate == null);
    if (addressJoin.Count() == 0)
        return string.Empty;
    else
    {
        Address address = addressJoin.Address;
       //FOrmat address
    }
}

I believe this is a better approach because:

  • You aren't querying against the data context directly.
  • The customer addresses and addresses in the second approach are lazy loaded.
  • If something changes, you aren't passing a key in directly.  For instance, if the address is dependent on a setting for the customer, it's easy to add that for the second approach, but for the first approach, you would have to add another parameter [such as: string GetCustomerFormattedAddress(int, CustomerType)].  You have to "break the interface" on the first one, requiring code changes to other portions of your application.  The second approach minimizes future risk.
  • The drill-through approach is nicer because it can be "cleaner" in many situations.

I hope to add on this with a few more examples in the future.

Posted by bmains | with no comments
Filed under:

If you are familiar with LINQ, you know that your objects have hierarchies, that can be a challenge when binding to ASP.NET tabular controls such as the GridView.  So how can you do this?  Anonymous types can come to the rescue.  For instance, if you want to show the customer who participated in a collection of orders, to show the relation, the following approach can be used:

var orders = this.GetAllOrders(); //Gets all orders from the data context
var orderDisplay = from order in orders
                           orderby order.Customer.LastName, order.OrderDate
                           select new
                           {
                                   order.Customer.LastName,
                                   order.Customer.FirstName,
                                   FullName = order.Customer.LastName + " " + order.Customer.FirstName,
                                   order.OrderDate,
                                   order.OrderAmount
                           };

this.gvwOrders.DataSource = orderDisplay;
this.gvwOrders.DataBind();

Because of anonymous types, LINQ can safely show hierarchical data in a tabular control.

Posted by bmains | with no comments
Filed under: ,
The leading UI suite for ASP.NET - Telerik radControls
Outstanding performance. Full ASP.NET AJAX support. Nearly codeless development.