Performing ASP .NET Submits with Coolite Form Panel Events

As with anything in programming there are a number of ways to do any operation, sending data to server side code in Coolite is no exception.  One of the ways that I have found very useful is via the OnEvent configuration for an AjaxEvent.

To begin with one needs to understand that a FormPanel is not a representation of the tag from HTML, but rather similar to the UpdatePanel control from ASP .NET Ajax.  AjaxEvents are then like triggers.  However, since this trigger could reside anywhere on the page we need a way to “link” the panel viewstate to the trigger so the ViewState is transmitted and we get the desired information that we need.  This is done via the FormID attribute on both the AjaxEvent and the FormPanel.  In addition, fields that are to be transmitted seem to require a Layout, meaning they cannot simply be placed adhoc on the page.  Thus the initial HTML fragment looks something like this:

<ext:FormPanel ID="fpMain" runat="server" FormID="mainForm"
    ButtonAlign="Right" Title="My Form">
    <Body>
    </Body>
</ext:FormPanel>.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }

I am only defining a few of the essential properties here.  As I said earlier, FormID helps Coolite identify which ViewState set to submit as part of the AjaxEvent.  All Panels in Coolite have a section dedicated for buttons, we can use the ButtonAlign property align those buttons as we wish.

For the next segment I will define a could fields using the FormLayout control. Understand that this Layout in particular has a lot of extra functionality and uses, I am not going to show case all of them here.  I will talk about it later on, for now I would advise visiting http://examples.coolite.com and looking under the ‘Layouts’ section.

<ext:FormPanel ID="fpMain" runat="server" FormID="mainForm"
    ButtonAlign="Right" Title="My Form">
    <Body>
        <ext:FormLayout runat="server" LabelSeparator=":"
            LabelAlign="Left">
            <ext:Anchor Horizontal="95%">
                 <ext:TextField ID="txtName" runat="server"
                     FieldLabel="Name" />
            </ext:Anchor>
            <ext:Anchor Horizontal="95%">
                 <ext:NumberField ID="nbrAge" runat="server"
                    FieldLabel="Age" MaxLength="3" />
            </ext:Anchor>
        </ext:FormLayout>
    </Body>
    <Buttons>
        <ext:Button ID="btnSubmit" runat="server" Text="Submit"
            Icon="Accept">
            <AjaxEvents>
                <Click OnEvent="btnSubmit_Click" FormID="mainForm">
                    <EventMask ShowMask="true" Msg="Submitting Data"
                        CustomTarget="fpMain" Target="CustomTarget" />
                </Click>
            </AjaxEvents>
        </ext:Button>
    </Buttons>
</ext:FormPanel>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

So I have defined here two form fields within FormLayout one holds a normal textfield and the other a numbers only field.  To finish this implementation we need to define the btnSubmit_Click event handler in the code behind file.  The implementation I will use is:

protected void btnSubmit_Click(object sender, AjaxEventArgs ev)
{
    Ext.Msg.Alert("Alert",
        string.Format("Welcome {0} (Age {1}). Today is {2:d}",
            txtName.Text, nbrAge.Text, DateTime.Now))
    .Show();
}

Admitting, this is a very simple concept of what a server side event could do; it simply shows a Coolite style modal that is designed to substitute the standard JavaScript alert window.  Here we are basically telling the user the information they entered as well as attaching a server side piece of data (the current date).  You can image business logic being here for adding this data to a persistent store, such as a database. I will save another blog entry to talk about validating this data since Coolite can take care of a great deal of that for you.

One other interesting thing to note, and is something that I have observed. When you start getting into these sorts of scenarios where you are using these events, you will want to be conscious of the fact that even though Coolite states the tag is not needed in the little docs they have, this is false.  You will find this very true when you start trying to submit changes to a grid or pick up what rows of a grid where selected. I will have an example of this next.

The key thing here is to understand the connection between FormPanel and how to send data from the client to the server is a way that is more familiar to ASP .NET web programmers.  Remember to mindful of the view state you are including and you can always validate things are working by checking the state of form fields on the server, I still do this at the onset, just to be sure I know what I am submitting.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Using .NET Extension Methods for Type Conversion Libraries

One of my favorite features in Microsoft .NET is extension methods, primarily because of the clean syntax they provide for formatting and perform special operations against types.  I never really never did like static helper methods like this:

DecimalHelper.FormatAsMoney(decimalValue);

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

I just felt that this was not clean and felt more procedural then it should in an object oriented language like .NET.  Nonetheless, it satisfied the need of being able to centralize logic for dealing with certain common conditions, least of all Type conversion (ala the Convert class).  With the advent of the LINQ syntax in .NET 3.5 Microsoft provided support for using extension methods.  These superficially attached methods are my favorite feature in .NET as they are able to achieve the same result as the helper methods above, except with a much cleaner syntax in my opinion:

decimalVaue.AsMoney();

So I started thinking, this would be very useful for creating “smart parsers” for converting types, in particular strings to various data types, a common and often tedious exercise in web applications.  Smart parsers encapsulate the calls to TryParse and allow the method call to return a standard value on fail or, with an overload, return a default value.  This is an example of my AsInt smart parser function:

public static int AsInt(this string s)
{
    int d;
    return !int.TryParse(s, out d)
        ? int.MinValue : d;
}

public static int AsInt(this string s, int defValue)
{
    int d = s.AsInt();
    return d == int.MinValue
        ? defValue : d;
}

I always did hate calls to Convert and TryParse cause I felt the code was dirty and parsing in general sometimes needs to aware of Globalization settings.  As a result of the success I have had using this on many enterprise projects, I have made it a standard that I implement.  I decided recently, at the advisement of a co-worker to publish something. Its not much, but its a few of the standard methods that I work with.  A lot of these sort of methods are born out of a need to create consistency in the application, mostly related to formatting.

Below is the link to download what I currently have developed (along with some unit tests).  I hope to have this grow into a full fledged type conversion and formatting library.

http://cid-18f9d8896416d2fb.skydrive.live.com/embedrowdetail.aspx/BlogFiles/Core.Extensions.zip

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Grouping with Coolite GridPanel

One of the nicest things about Coolite is that you can easily get a very modern looking website in short order, provided you take the time to understand the examples and ExtJS documentation, which maps pretty closely to the controls.  But there are still little niches you need to know to get the controls to work how you want.  One of the most finicky controls, I have found is the GridPanel.

So much interactivity can be achieved these days via JSON and grids it really is breathtaking when you pull it off.  Coolite is no exception, in fact, when configured properly, it has one of the must full featured grids I have seen on the web, once you get there that is. I will talk about the grid a lot in posts to come, primarily about databinding, and updating.  But today we will focus on grouping.

Grouping is an effect where by a top level is rendered based on data groups, these can be expanded to show the children of that group along with aggregation data.  Today I am going to explain how to take a simple array of data and generate a grid panel which supports grouping.  To begin, here is some sample data we will feed our grid:

var aList = new List()
{
    new Order() { OrderId = 100, ProductId = 3,
        ProductName="Product 3", UnitPrice = 5.00m,
        Quantity = 21 },
    new Order() { OrderId = 100, ProductId = 6,
        ProductName="Product 6", UnitPrice = 1.00m,
        Quantity = 22 },
    new Order() { OrderId = 100, ProductId = 7,
        ProductName="Product 7", UnitPrice = 2.00m,
        Quantity = 23 },
    new Order() { OrderId = 200, ProductId = 3,
        ProductName="Product 3", UnitPrice = 3.00m,
        Quantity = 24 },
    new Order() { OrderId = 300, ProductId = 4,
        ProductName="Product 4", UnitPrice = 4.00m,
        Quantity = 25 },
    new Order() { OrderId = 400, ProductId = 5,
        ProductName="Product 5", UnitPrice = 5.00m,
        Quantity = 26 },
    new Order() { OrderId = 500, ProductId = 8,
        ProductName="Product 8", UnitPrice = 6.00m,
        Quantity = 27 },
    new Order() { OrderId = 500, ProductId = 9,
        ProductName="Product 9", UnitPrice = 7.00m,
        Quantity = 28 },
    new Order() { OrderId = 500, ProductId = 1,
        ProductName="Product 1", UnitPrice = 8.00m,
        Quantity = 29 },
    new Order() { OrderId = 200, ProductId = 2,
        ProductName="Product 2", UnitPrice = 9.00m,
        Quantity = 20 },
    new Order() { OrderId = 700, ProductId = 3,
        ProductName="Product 3", UnitPrice = 1.00m,
        Quantity = 21 },
    new Order() { OrderId = 700, ProductId = 4,
        ProductName="Product 4", UnitPrice = 2.00m,
        Quantity = 22 },
    new Order() { OrderId = 800, ProductId = 4,
        ProductName="Product 4", UnitPrice = 3.00m,
        Quantity = 23 }
};

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Ok, maybe that was a bit excessive, but moving on.  Coolite emphasis a UI pattern I like to call “late loading”. The basics of this pattern is that the main frame of the page should come in first and then the data. This gives the user the impression of a page load and lightens the load. This technique is commonly employed with data heavy applications which utilize a single page architecture and simply move data (usually in JSON) to and from the server using asynchronous calls.

My favorite way of getting data with Coolite are ASP .NET Generic Handlers (.ashx), mainly because they are extremely lightweight and have some very nice uses with GridPanels. This is the code for the ASHX, notice the use of the NewtonSoft JSON Library (this is included with the Coolite download) to serialize the List into JSON and pass it back, also notice the content type definition, to text/json.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class DataHandler : IHttpHandler
{
        public void ProcessRequest(HttpContext context)
        {
            List list = Order.GetData();

            context.Response.ContentType = "text/json";
            StoreResponseData data = new StoreResponseData();
            data.Data = JSON.Serialize(list);
            data.Return();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
    }
}

What this will do is return a JSON object to be read by a Coolite ExtJS data store and then bound to a control.  In this case, the data that is being returned can easily be grouped by its OrderId property. We can have Coolite take care of most the heavy lifting for us.  So we will first define our data store:

   1:  <ext:Store ID="store" runat="server" AutoLoad="true"
   2:      AutoDataBind="true" GroupField="OrderId">
   3:      <Proxy>
   4:          <ext:HttpProxy DisableCaching="true" Json="true"
   5:              Method="GET" Url="/DataHandler.ashx" />
   6:      </Proxy>
   7:      <Reader>
   8:          <ext:JsonReader>
   9:              <Fields>
  10:                  <ext:RecordField Name="OrderId" />
  11:                  <ext:RecordField Name="ProductId" />
  12:                  <ext:RecordField Name="ProductName" />
  13:                  <ext:RecordField Name="UnitPrice" />
  14:                  <ext:RecordField Name="Quantity" />
  15:                  <ext:RecordField Name="Total" />
  16:              </Fields>
  17:          </ext:JsonReader>
  18:      </Reader>
  19:  </ext:Store>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Ok there is a lot here so we will go line by line.  First we are defining the Store and saying that we want it to AutoLoad which means a request will be made as the page becomes ready.  The key here is the GroupField definition which is what will format the outgoing result in a way that the GridPanel will use a grouping format to output it.

The connections to the data sources are initiated through Proxies.  The interesting thing here is that you can also define a WriteProxy to handle changes to Store via the Grids inline editing feature.  In this tutorial we are only going to be covering using a ReadProxy:

  • DisableCaching: This prohibits the browser from caching a request.
  • Json: This just ensures that what we get back from the request is JSON, I define this just to be explicit with what is coming back
  • Method: Once again this overloads the default value, and just explicitly states that we wish this request to be carried out over GET
  • Url: The URL of where to make the request to, in this case we are specifying the URL to our custom ASHX

The next part is the Reader definition; this is defining what the JSON object is going to look like on the client side as it is worked with on the client side.  Make sure the values of the Name attributes match their respective property values of on the JSON object coming over.  I mistakenly thought this was the order of serialization, but it is not; they match one to one.  You can optionally define the Type attribute, but for the most part Coolite will infer the types.

With this defined, we are now ready to move onto defining our GridPanel which will actually provide the UI for the user to see.  The definition is rather long, so I will be breaking this apart based on the internal nodes for definition, to start here is the outer structure which has the base property definitions:

<ext:GridPanel ID="gpPanel" runat="server" AutoHeight="true"
    StripeRows="true" StoreID="store" AutoDataBind="true">
</ext:GridPanel>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The important attributes here StoreID (which defines which store this control is associated with), also AutoDataBind which will automatically rebind the grid whenever a change is detected in the associated store.  The other attributes are defined for aesthetic purposes.

The next thing to do is to define how the grid will look without Grouping and what columns will be included, to do this we define a ColumnModel node within the GridPanel:

<ColumnModel runat="server">
    <Columns>
        <ext:Column DataIndex="OrderId" />
        <ext:Column DataIndex="ProductName"
            Header="Product" />
        <ext:Column DataIndex="UnitPrice"
            Header="Price">
            <Renderer Format="UsMoney" />
        </ext:Column>
        <ext:Column DataIndex="Quantity"
            Header="Qty" />
        <ext:Column DataIndex="Total">
            <Renderer Format="UsMoney" />
        </ext:Column>
    </Columns>
</ColumnModel>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

You notice the DataIndex matches the value of the Name attribute from the JsonReader RecordFields.  Understand that the column model defines ONLY what fields from the JSON object you want to display.  The row will STILL contain a reference to the whole JSON object, but this way you can choose to hide fields like PKs (We are doing this with ProductId in this case), but they are still usable when a GridCommand is invoked.

Notice also that we are using the built in Render formatting that is provided by Coolite.  There are quite a few of them that come out of the box, in addition you can define your own.

So if you run this code right now, you will get a simple grid, but you will still not see any groupings, this is because we need to define a GroupingView node for this GridPanel to see the grouping in action.

<View>
    <ext:GroupingView ID="gvGrouping" runat="server"
        ForceFit="true" HideGroupedColumn="true">
    </ext:GroupingView>
</View>

Views are an extremely vital piece to the GridPanel as they can help you define further configuration in terms of function and formatting.  Here we are using the GroupingView which defines how the Grid will look when it is grouping.  We define two attributes for aesthetical purposes: ForceFit and HideGroupedColumn.  ForceFit merely forces the Grid to fit its entire available width, it tends to make the grid look a lot nicer.  HideGroupedColumn hides the column you are grouping on.

Running the code now you will see the GridPanel and your data grouped by the OrderId.  The blocks are expandable and collapsible, and their initial state can be defined on the GroupingView.  The GridPanel offers an immense amount of functionality and can really help you display your data.  It also best demonstrates ExtJs reliance on the “late-load” content loading technique.  Your controls will be rendered and the data will be brought in via Store’s that in most cases will be linked to a web service of some kind.  This data is then placed into either an Array, JSON, or XML, depending on what you define. In our example, we used JSON.  We associated this Store with a Grid via the StoreID attribute of the GridPanel.  In addition, we define the Grouping column for the Store, this is what enables our grouping.

Finally, we use a ColumnModel and View to define how the Grid will look under certain situations.  Remember that you do not have to define a column for all members of your JSON object, only the ones you want to display, sending a row command will still give you access to all the properties defined on the object via the JSON reader.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Creating Modal Windows with Coolite

One of the most popular effects in web development, is the modal dialog.  Using standard CSS we are able to create the appearance of a modal dialog on a webpage that can be used to provide a quick login form, more information, or any of a thousand other things.  Naturally, most UI frameworks have this effect built-in so developers can quickly create this effect without having to worry about cross browser problems; Coolite is no exception.

Generally, the way this is achieved is a

is placed somewhere on the page (usually at the bottom) and is targeted with JavaScript which does some fanciness to give it various look-and-feel properties.  Coolite is slightly different, but in a way that makes more sense.  It leverages the idea of the “viewport” as the main page, that is what the user see’s without the modal.  In Coolite we would define this as such:

<ext:ViewPort ID="vp1" runat="server" AutoHeight="true">
    <Body>
    </Body>
</ext:ViewPort>

The basic idea here is that the viewport serves as a wrapper for your main content.  So we could define our main UI here, for this example we will simple put a button which opens the modal.

<ext:ViewPort ID="vp1" runat="server" AutoHeight="true">
    <Body>
        <ext:Button ID="btnOpen" runat="server" Text="Open"
            Icon="Application">
            <Listeners>
            </Listeners>
        </ext:Button>
    </Body>
</ext:ViewPort>

Next we define the code for our Modal window, for this example, we are going to constrain the width and put some lipsum text

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

<ext:Window ID="Window1" runat="server" AutoHeight="true" Width="400" Constrain="true"
    Modal="true" ShowOnLoad="false" ButtonAlign="Right" Title="Modal Window">
    <Body>
        Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
        has been the industry's standard dummy text ever since the 1500s, when an unknown printer
        took a galley of type and scrambled it to make a type specimen book. It has survived not
        only five centuries, but also the leap into electronic typesetting, remaining essentially
    </Body>
    <Buttons>
        <ext:Button ID="btnClose" runat="server" Text="Close" Icon="Cancel" />
    </Buttons>
</ext:Window>

So this is fairly simple and straightforward.  We have defined our main layout in a ViewPort and then we have defined external layout elements (the modal) in Windows that are defined outside the ViewPort.  I defined only the essential properties of the modal, but there are quite a few properties, such as X and Y to define the starting location of the modal.

However, we are missing one critical element; with this current code there is no way to show the modal to the user.  There are two ways to do this, and your selection of the means to do this will depend on your scenario.  You can open this with both JavaScript and the .NET code behind.  In JavaScript, we simply add a listener node and listen for the “Click” event.  Thus our buttons definition looks like this:

<ext:Button ID="btnOpen" runat="server" Text="Open"
    Icon="Application">
    <Listeners>
        <Click Handler="Window1.show();" />
    </Listeners>
</ext:Button>

This is the approach I like to take for simple calls, just define the Handler property with the JavaScript you want.  Its a “do it once and throw it away’”.  However, if you’re going to duplicate logic and call it throughout the page, I would then define the Fn property and centralize all that logic in a single function.

In addition, the Window component has many events that you can catch, with JavaScript or Server-side code, though client side will be much easier to understand.  I will list out some of the more useful ones that I have used:

  • BeforeShow – fires just before the modal is shown to the user.  Useful as a means of resetting modal content from an pre-existing operation.
  • BeforeHide – fires just before the modal disappears from the users view
  • Hide – fires after the modal is closed via a call to hide() on the Window element
  • Show – fires after the modal is shown to the user

So as I mentioned the same effect can be accomplished using AjaxEvents.  To do this you would simply update the Button definition removing the node with the note, like such:

<ext:Button ID="btnOpen" runat="server" Text="Open"
    Icon="Application">
    <AjaxEvents>
        <Click OnEvent="btnOpen_Click">
            <EventMask ShowMask="true"
                Msg="This is a Loading Mask" />
        </Click>
    </AjaxEvents>
</ext:Button>

This defines that for the button the Click event raises an AjaxEvent which is handled by the btnOpen_Click method in the page code behind.  From this position you have access to related page elements.  What does it mean to be related?  I honestly dont know, this is one of the aspects of Coolite that is largely undocumented.  From what I can gather, it seems to be the parent container, though you can define a specific form to link to the AjaxEvent, via the FormID attribute.

Notice that we are also defining a mask to be visible when this event is occurring.  Remember that we are going back to the server, so it makes sense to give the user some feedback; thus in the event the operation takes time the user is notified and appropriate interactions can be prevented.  To give you an idea what the code behind method looks like in this case, here is what btnOpen_Click looks like:

protected void btnOpen_Click(object sender, EventArgs ev)
{
    Window1.Show();
}

Very simple and straightforward.  You could imagine having checks in here to prevent the modal from showing if certain conditions were not met, or populating modal elements with server data.

To conclude, the big thing to remember about Coolite modals, is that they must be placed outside a ViewPort component with the Modal property set to true.  There a wide variety of properties that you can configure for the window to improve the look and feel of the modal as well as positioning.  Modals provide a great way to display related information or provide a drill down into data, they can be used to simplify interfaces and provide more elegant ways to access commonly used functionality, while continuing to move the web application closer to the goal of behaving like a desktop application.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Understanding AjaxEvents in Coolite ASP .NET

In the first tutorial in this series we created a very basic Hello form that relied on JavaScript for its core.  We also saw how easy it was to build a very clean and modern looking form using Coolite.  But what are there things called AjaxEvents.

Going to the Coolite website we find that, as with most of Coolite, there is a total lack of documentation as to what AjaxEvents are, although there are samples showing how to use them.  Based on these examples I would say they are simple postback requests that can be used to post data to the server.

They are able to “target” a specific form (they default to the form they are in) and send the current state of the items in that form to the ASP .NET code behind where they can be operated on as desired.  These requests are then able to fire the events of other controls that have events defined (ex Grid, Store). In addition, you are able to configure an event mask for while the request is in process. This helps the user know that “something is happening”.

So to begin here is a screenshot of code from the first tutorial, but I have cut the JavaScript out and removed the Listeners node from the Button
image

The first step is to update the Button markup as such:

<Buttons>
  <ext:Button ID="btnSubmit" runat="server"
   Text="Submit" Icon="Accept">
    <AjaxEvents>
      <Click OnEvent="btnSubmit_Click">
      </Click>
    </AjaxEvents>
  </ext:Button>
</Buttons>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Very similar to the node (and in fact these can be combined with a listener, return false, will stop the request), we are saying that “when the Click event occurs, create an AjaxEvent which is handled by the handler btnSubmit_Click in the code behind”.  This what our handler could look like:

protected void btnSubmit_Click(object sender,
     AjaxEventArgs ev)
{
     Ext.Msg.Alert("Alert",
         string.Format("Hello {0}", txtName.Text)
     ).Show();
}

Notice that we are using the AjaxEventArgs type for the EventArgs type. This is a special event args that contains a few extra properties that can be of use. Most notably the ExtraParam and ExtraParamnsResponse properties. The former allows you to send this via the Ajax call that may not be contained in controls you can access.

The final piece of this application is the event mask. This is a very simple operation so we dont really need a mask. Masks are very useful to for stopping the user from interacting with the page or parts of the page while an action is in progress. With Coolite these are easily definable and fit well with the application.

First add a call to “Thread.Sleep(1000);” to you handler function so that you will get a chance to see the mask we are doing to define. Return to the Button code and update it as such:

<ext:Button ID="btnSubmit" runat="server"
    Text="Submit" Icon="Accept">
    <AjaxEvents>
        <Click OnEvent="btnSubmit_Click">
            <EventMask Msg="Generating Message" ShowMask="true"
                Target="CustomTarget" CustomTarget="fp1" />
        </Click>
    </AjaxEvents>
</ext:Button>

The two key properties in the tag are ShowMask and Msg.  The former states that when this event is active we do want to show the mask.  The later defines what message the user will see while the event is in progress.  In addition, I have defined the Target as CustomTarget which allows me to specify which section will be grayed out, by default it is the entire page.  In this case I am specifying the control with the ID of “fp1” which is the FormPanel all of this is sitting inside of.  The end result is when you are waiting for the name to come back, your form should look like this:

image

To conclude, this article focused on using AjaxEvents with Buttons and how to control the EventMask.  Remember that you can do a lot more with AjaxEvents as they can be applied to most any control.  You just need to tweak things sometimes and always check your pages that the calls are getting the right state data from the controls.  Most of my testing has been with FormPanels and I have found that things not inside FormLayouts are often not submitted for whatever reason.

AjaxEvents are a big reason why I enjoy using Coolite with webforms over MVC; because I can take advantage of events are server side code in C# as opposed to writing more JavaScript.  But using these two posts you should understand that your code will not be that different in most cases, regardless of which approach you use.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Getting Started with Coolite on ASP .NET

I am currently engaged in an opportunity that has taken me to New York to help a client rewrite one of their existing VB6 applications in ASP .NET as a web application.  To aid us with developing this application and provide a very modern and consistent look and feel we are using the Coolite UI Framework for ASP .NET which leverages the powerful ExtJS JavaScript library inside of WebForm controls.

However, we have found that the the biggest downside to using Coolite is the intense lack of documentation from the creators. This makes it hard to know exactly what we are doing and often leaves us to pull from two or three sites to fully understand what it is capable of.  The biggest help comes from the Examples site, and the ExtJS documentation site, since the controls follow the supported properties for those controls. ExtJS has excellent documentation.  But I wanted to talk about Coolite cause I think it has a lot of potential and can really be very helpful if people learn more about it.  So to start this series I am going to give a very basic example of an application which uses Coolite and JavaScript.  So lets get started.

To begin you will need to download the Coolite binaries from Coolite.com, this will install three binaries (Coolite.Ext.Web.dll, Coolite.Utilities.dll, and Newtonsoft.Json.dll) and reference these in your solution.

The second step is to update your web application web.config file to support Coolite in the application.  So first add this line to your web.config after the last section group.

<configSections ..>
  </sectionGroup>
  <section name="coolite"
       type="Coolite.Ext.Web.GlobalConfig"
       requirePermission="false"/>
</configSections>
<coolite idMode="Explicit"
       theme="Default"
       initScriptMode="Linked"
       scriptMode="Debug" />

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Also included in this screen shot is the next step of what to add, and that is the new section as defined by the section definition we just added.  Here you can specify a number of things, but the two things to take note of here are:

  • idMode:  use Explicit here so that Coolite controls can be referenced in JavaScript without worry about naming containers as with typical ASP .NET controls
  • theme: defines the UI styles that Coolite will reference for all controls. Can be Default, Gray, Slate

The next thing we have to add are some reference to HTTP handlers and modules; so we add the following lines to the web.config:

To httpHandlers:

<httpHandlers>
  <add path="*/coolite.axd" verb="*"
     type="Coolite.Ext.Web.ResourceManager"
     validate="false"/>
</httpHandlers>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

To httpModules:

<httpModules>
    <add name="AjaxRequestModule"
         type="Coolite.Ext.Web.AjaxRequestModule,
                    Coolite.Ext.Web"/>
</httpModules>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Optionally, I like to add the following line to my pages collection in system.web to make referencing the Coolite controls easier:

<pages>
    <controls>
        <add assembly="Coolite.Ext.Web"
            namespace="Coolite.Ext.Web"
            tagPrefix="ext"/>
    </controls>
</pages>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

So lets start with building a simple form that will say “Hello {name}” provided a name in a textbox.  I am going to do this using JavaScript on the client side, another blog post will detail doing it with AjaxEvents.

So lets first show some basic markup that uses Coolite to create a form, this first thing that every page using Coolite controls must have is a ScriptManager to facilitate the inclusion of JavaScript to support the various effects, so:

image

Next, we will want to create a small form, so we will use a FormPanel control, which gives us a very nice look and feel, so:

image

I have defined a lot of properties on the form, here is an explanation for a few of them:

  • FormID: Used in AjaxEvent referencing and to tie controls to certain actions, not really used in this approach, but will be useful when we show AjaxEvents
  • Title: The title displayed for the Form (see next screenshot)
  • ButtonAlign: The alignment of the buttons defined in the FormPanels portion
  • StyleSpec: The style rule to apply to the panel as a whole

Running this should produce the following UI:

image

Not a bad looking UI considering we haven’t had to do any CSS and this is compatible with IE6 even, so lets keep moving forward and add the actual UI.

The FormPanel has quite a few internal sections, for this tutorial we will use two of them and .  Here is the updated code:

   1:  <body>
   2:    <ext:ScriptManager ID="ScriptManager1" runat="server" />
   3:    <ext:FormPanel ID="fp1" runat="server"
   4:      FormID="mainForm" Title="Test Form"
   5:      Height="150" Width="300" ButtonAlign="Right"
   6:      BodyStyle="padding: 10px;" 
   7:      StyleSpec="margin: 10px;">
   8:      <Body>
   9:        <ext:FormLayout ID="frmLayout" runat="server"
  10:          LabelSeparator=" " LabelAlign="Left">
  11:          <ext:Anchor>
  12:            <ext:TextField ID="txtName" runat="server"
  13:              AllowBlank="false"
  14:              MaxLength="15" FieldLabel="Name" />
  15:          </ext:Anchor>
  16:        </ext:FormLayout>
  17:      </Body>
  18:      <Buttons>
  19:        <ext:Button ID="btnSubmit" runat="server" Text="Submit" Icon="Accept" />
  20:      </Buttons>
  21:    </ext:FormPanel>
  22:  </body>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

So what we have done first is the update the body of the FormPanel with a FormLayout.  There are a lot of things that FormLayout does for us, but for new its enough that it will render the elements described in each block vertically with some label text to the left.

In this case we are adding a a Ext Textfield that has a few things defined:

  • AllowBlank – the textbox will validate user input and require input
  • FieldLabel – this is the text of the label that will appear to the left. It can also appear above the control, this controlled by the LabelAlign property (see the FormLayout)

Next we move to the group. This section is placed beneath the Panel body and houses button controls, here I am defining a single button.  If you run this, it should output something like this:

image

The next part of this is to allow the user to click “Submit” and have the program respond with an Ext alert that says “Hello”.  So the first thing we will need is something to listen for this event.  Update the Button definitions as such:

<ext:Button ID="btnSubmit" runat="server"
  Text="Submit" Icon="Accept">
  <Listeners>
    <Click Fn="SayHello" />
  </Listeners>
</ext:Button>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

There are a number of events that we can listen for, obviously the one that makes the most sense in this case is Click.  So when a click happens we want to call the function SayHello. So here is a look at the SayHello function:

<script language="javascript" type="text/javascript">
    var SayHello = function() {
        var name = txtName.getValue();
        Ext.Msg.alert("Alert", "Hello " + name);
      }
    

Notice how we are getting the value of the text field, we are simply calling its name, no ClientID (in this case).  We are then creating an ExtJS alert window to display the message.  The reason we use this here is that it will provide an alert that is linked to our theme, this way all visual elements have the same appearance.  So clicking the button should do this:

image

One thing I do want to point out is that this alert window is NOT an alert window.  It does not block execution, it relies on callbacks to execute code after the “OK” click.  It is nothing more than a modal dialog being shown.

So there you have it, that is a very basic application which uses Coolite to perform a very basic function.  The next time around we will describe how to do this using AjaxEvents, which are a very interesting concept and take much of the problems you encounter with MS Ajax out of the picture.

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Moving from ASP .NET MVC to ASP .NET Webforms

It is very common to hear developers talk about successfully switching to MVC and generating much cleaner applications and there is no doubt that using MVC can certainly generate that.  But as with any technology/framework, misusing it can still result in an application with maintainability issues and the need for the developer to make undesirable decisions.

Such was the case out here in New York where our client had decided to use the MVC framework with the Coolite UI toolset. I am a big believer then when it comes to using the MVC framework one needs to be careful that the toolset you are using also leverages what MVC gives you.  In the case of the project out here, after numerous discussions it was clear that really the way we were approaching the project we were just not going to leverage MVC in a way that would make sense to use it.  In reality, the project would be better off, given the aims, as a Silverlight project, but due to circumstances surrounding the project it was not an option.

In addition, we had decided to use the Coolite control toolkit for UI.  Given the way that Coolite is setup it makes sense to use it with WebForms over MVC.  While you can certainly use MVC with Coolite (as demonstrated by http://mvc.coolite.com) after spending a week developing in MVC with Coolite it became apparent that it didn’t make sense and I felt we were heading for some problems.  I took these problems to the other developers and after some conversation we decided we needed to talk to the client about possibly changing, let me enumerate some of the arguments that were made:

  • MVC’s biggest strength is the decoupling of the view from the controller and the lack of reliance on server controls
    • In our case we are not really using this methodology heavily, instead relying more on web services to talk to the database. This due to the other devices that must be able to tie into this system
  • Coolite is designed to work with ASP .NET webforms.  Using Coolite with MVC means a large reliance on JavaScript to gather values and perform saves.
    • Using Webforms we can use the code behind to leverage .NET in a way that makes sense given the operations we are performing
  • With Webforms we can still use web service method calls to get data from our database.  It also allows use to make WCF calls via code-behind if needed

The big point that was made here was that we are only talking minimal gain using MVC from a structure standpoint vs. potentially difficult choices in saving and persisting data and leaning very heavily on JavaScript.  In addition, if done properly an ASP .NET Webform app can be just as well organized as an MVC application if done correctly.  I have certainly see it done by some of the best in the industry and I have their experience to lean on in doing this.  I really think this is the best decision, as much as I want to use MVC, I think you just don’t gain anything give what we are doing and how we are approaching it.

Repository Pattern (Revisted)

In the previous tutorial set we looked at the Repository pattern and how one might use it to construct a support framework for Fluent NHibernate.  If you looked at closely you likely realized some very serious and obvious design flaws.  The main thing that I didn’t like about it was the use of the derived repositories and the constraints it placed on various user stories.  For example, in order to save related items, or perform read operations, multiple repository instances were needed.  This creates a huge burden on the developer.  What is really needed in this case is a store, that is a single class that provides lazy loaded instances of the other repositories the system supports.

To begin this process, we first need to generate code.  Our types are not known to use at any point until after a database is read.  To do this we will use T4 templates.  I will blog later on about creating these templates for now we are just working to understand the theory.

So the idea behind this reorganization is to create a single class that all other repositories work off.  The repository instances for the specific models will need to provide enough extensibility to let developers take control of the save process, but also provide enough out of the box functionality so that it is useful without modification.

Furthermore, we want to encourage developers to use our single instance so we need to provide a way for their functions to be called in place of our original.  To do this we will use abstract base classes with virtual methods.  By defining a default save method as virtual in the base class we can provide the developer a way to override the function that is automatically called when a Commit is initiated on the store’s objects.

So the Store is generally in charge of initiating the Commit process via reflection and finding appropriately decorated properties that represent the Repositories.  The commit is only called if the list is deemed to be dirty.

Each of the derived repositories can only hold objects of certain type, the type must inherit from EntityBase thereby insuring that the object being operated on is an Entity.  Finally the Entity saving, deleting, and updating operations are all handled in a totally database agnostic way by NHibernate under the hood thanks to the mapping generated via Fluent NHibernate.

So the end result of this process is that using T4 templates we are able to generate the POCO (Plain Old C# Objects) model files, the Fluent Mapping files, the Derived Repository definitions and the generated portion of the Store all automatically.  In addition, we make all classes partial enabling developers to extend them as they see fit.  This gives us a tremendous about of flexibility for developers to customize certain operations.  This model for repository is a little more closer to what the pattern fully intends, though really is more of a Store pattern, similar to what Linq to SQL and Linq to Entities appear to use to great effect.  In coming tutorials I will back track and help you understand how to create a fully functional Repository Store support framework.

Exploring the Repository Pattern (Part 2)

In the first portion of this article we explored what the Repository pattern is and provided a basic implementation for now developers are using it to facilitate data access.  We create a basic class RepositoryBase and showed a basic example of using it.  Now we will explore this class and demonstrate how to take the Repository further and make it more useful.

Now, in what we created there is one major obvious drawback.  If we wanted to write a custom query how do we do so?  Surrounding this matter is a lot of debate on extending the pattern, for the most part I have seen the following schools of thought:

  • Query objects
  • Extension methods
  • Derived Model Repositories

Of these I find query objects to be the most fascinating, I will defer to my friend RossCode to explain them here.  But essentially the idea is to create a new abstract base class called QueryBase and use this to create objects that contain criteria for performing these custom queries.  Using this we can create two methods (one for singles, one for sets) on our RepositoryBase like such:

   1:  protected T GetBy(QueryBase query)
   2:  {
   3:       return query.SatisfyingElementFrom(GetAll());
   4:  }
   5:   
   6:  /// 
   7:  /// Get a listing of records that matches a custom criteria
   8:  /// 
   9:  /// Query object to supply the criteria data
  10:  /// ILIst of T or null
  11:  protected IEnumerable GetAll(QueryBase query)
  12:  {
  13:       return query.SatisfyingElementsFrom(GetAll());
  14:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

What we have done is create a set of methods that take an abstract type as its parameter, thus allowing any class that inherits from QueryBase.  In reality, this method is designed to be used with something like LINQ to NHibernate which would allow these custom queries to benefit from the deferred execution that is found in many data related variants of Linq, in our example however, we will be using standard Linq to Objects; I believe RossCode’s examples use Linq to NHibernate.

So using these query objects we can define separate classes for each custom query we wish to make and then pass then to either GetBy or GetAll.  This has the advantage of allowing us to use only one class for the repository and yields custom results.  But wait there is a slight problem with this method from a maintenance perspective.  Now we are dropping this query objects all over the application, and while this may be ok for a smaller application, in larger application it could quickly turn into a mess.  From a Separation of Concerns perspective we are not defining our queries outside the data access layer.  The caller should not need to know anything about how the query is generated, only that it can call the function and return the result.

Lets stick with the idea of Query Objects and address the root of this problem: we want to be able to make the custom calls as dumb as possible and not have query definition logic in the layer making the call.  One of the ways around this is to use extension methods (.NET 3.5).  Consider the following example:

public static List GetEpisodes(
     this RepositoryBase<Episode, int> repo,
     bool state)
{
     return repo.GetAll(new ActiveEpisodeQuery(state));
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

What this will do is attach a method (GetEpisodes) onto all instances of RepositoryBase thus allowing us to contain the method to a single function.  While this is not a bad approach, I do not like it because it feels so awkward; I would rather the functions be part of the class themselves, I cannot call this method through reflection should I need to later on.

My chosen way is to use derived repository classes, because:

  1. Base classes should always be declared abstract and thus not allowed to be instantiated
  2. Using a derived class allows the ability to hide more from the developer and make their paths less cluttered
  3. It builds on the OO principle of encapsulation and allows us to change things at will
  4. Using inheritance from the gives us the ability to hide things we may not need thus creating a simpler API

The major drawback to this approach is that you end up having to create and maintain more classes, because now every model will need to have a specific Repository class.  A sample one could look like such:

public class EpisodeRepository :
     RepositoryBase<Episode, int>
{
     public List GetActiveEpisodes()
     {
          return GetAll(new ActiveEpisodeQuery(true));
     }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Using this approach you can increase the amount of code that can be encapsulated inside the derived class and thus perform more complex operations on the repository objects, all while providing a simple API to the outside.

To conclude, we talked about the major shortcoming of the basic form of the Repository pattern: customization.  In any data driven application you will need to create custom queries that mutate and translate data in different ways.  The use of query objects can greatly enhance the clarity of the underlying logic, but without an additional layer of abstraction could pose great problems for code maintenance. To mitigate this we analyzed two possible approaches: 1) use extension methods to extend possible instantiations 2) create derived repositories for models to provide these custom data manipulations methods.

It is my personal preference to use approach #2 as it enables you to achieve complex operations with a much simpler interface.  It also helps with code maintenance and readability as the code can describe to the developer what it is doing and what is involved in the operation.

Exploring the Repository Pattern (Part 1)

In the software development world there exists the term “pattern”.  Like its counterparts in other disciplines, a pattern is a tried and true way to do something. Developers are constantly seeking newer and more efficient ways to organize code and reduce the amount of foundation they have to do.  One of the most common problems that developers use patterns to address is data access.

For developers, data access is one of the biggest bottlenecks in any data driven application. There are many popular patterns for this from Dependency Injection to Active Record, to Repository.  Today I am going to explore the Repository pattern by using it to create a simple data access framework using Fluent NHibernate.  Please note that this article will not discuss Fluent NHibernate (FNH) mapping’s.

To start it is necessary to understand how the Repository pattern works both in general and specifically with data access.  First as you might imagine the Repository is a collection of objects that we are going to perform an action on.  This can be a static action or a polymorphic action where the time is abstracted and can vary from object to object.  For data access, this generally involves saving the Entities that exist in the repository.  So from this sense you can think of the Repository as a specialized List.  So to begin we have to define our repository, so lets think about what we will need:

  • Connection to our database (abstracted)
  • Way to add to the Repository
  • Way to remove from the Repository
  • Way to get sets of entities from the underlying connection
  • Way to get single entity instances from the underlying connection
  • Way to perform an operation on the entities within the repository

To make things consistent we will create a RepositoryBase class to serve as the base for our derived repository classes.  There is a lot of discussion on whether to use an abstract class or interface to implement the Repository pattern. For the purposes of this demo I am going to use a base class in my approach, however, an interface would work in a similar fashion.  So the basic definition:

public class RepositoryBase where T : EntityBase, new()
{
}

Some things to point out here.  You will see that we are using a generic base class to provide a base for the inheriting classes.  The generic type must be a subtype of EntityBase, this indicates that it is an entity and has certain required properties that are inherent to all entities.

The next thing I am going to add is a connection to my database, the code is updated as such:

public class RepositoryBase where T : EntityBase, new()
{
     public ISession Session
     {
          get { return SessionProvider.GetSession(); }
     }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

The ISession type is from FNH, and is basically a connection to our database and the mapping configuration for the entities, we will not be discussing how this is done for this post, for now its enough to understand that Session is what allows us to communicate with FNH and our database.

So now we need to provide the ability to Add/Remove entities from our Repository, so we add the following methods:

   1:  // standard generic methods
   2:  /// 
   3:  /// Add an entity to the Repository to be operated on
   4:  /// 
   5:  /// The entity to add
   6:  public void Add(T entity)
   7:  {
   8:       _itemList.Add(entity);
   9:  }
  10:   
  11:  /// 
  12:  /// Remove the provided entity from the repository listing
  13:  /// 
  14:  /// The entity to be removed
  15:  public void Remove(T entity)
  16:  {
  17:       _itemList.Remove(entity);
  18:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This code should be pretty self explanation.  The only thing to note is the _itemList private member variable of type List where T is the specified type for the RepositoryBase.

Next we need to decide how users of our Repository will READ from the database, both to get sets of entities and a single entity based on a condition.  Below are my implementations:

   1:  /// 
   2:  /// Return an entity based on its primary key (int)
   3:  /// 
   4:  /// primary key value
   5:  /// Entity with the provided primary key
   6:  public T GetBy(int id)
   7:  {
   8:       return Session.Get(id);
   9:  }
  10:   
  11:  /// 
  12:  /// Return all records for the given Type table
  13:  /// 
  14:  /// entity of type T or null
  15:  public IEnumerable GetAll()
  16:  {
  17:       return Session.CreateCriteria(typeof(T)).List();
  18:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

One thing I would like to point is this version of the Repository makes an assumption that I have abstracted out in my final version.  If you notice the GetBy generic method, it takes an int as its parameter.  This is doing a lookup based on a primary key, which we are assuming is of type int.  In my final version I have updated the class definition to support a second generic type, which represents the type of the primary key in the database, thus giving the class flexibility to deal with any primary key type.  All the falls that these methods are masking go through the FNH session.

The final thing we need to add is the method to perform the operation. However, before we do this I would like to show you the code for EntityBase:

   1:  public abstract class EntityBase
   2:  {
   3:       public abstract bool IsNew { get; }
   4:       public abstract bool CanDelete { get; }
   5:       public abstract void SetDeleted(bool state);
   6:       public bool IsDeleted { get; protected set; }
   7:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

These are just some very simple properties, many of which are deferring their implementations until a new class is derived inheriting from EntityBase.  Now here is a scaled down version of the CommitChanges method for RepositoryBase.

   1:  public void CommitChanges()
   2:  {
   3:       foreach (T item in _itemList)
   4:       {
   5:            if (item.IsDeleted)
   6:            {
   7:                 Session.Delete(item);
   8:            }
   9:            else
  10:            {
  11:                 if (item.IsNew) // is a new entity and will invoke insert
  12:                 {
  13:                       Session.Save(item);
  14:                  }
  15:                  else // is an existing entity and will invoke update
  16:                  {
  17:                       Session.Update(item);
  18:                   }
  19:            }
  20:       }
  21:       
  22:       _itemList.Clear(); // clear all the entities and reset internal operations
  23:  }
  24:          }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

This is a great example of why I love polymorphism, we are ensuring that T inherits from EntityBase so that means we can use the public properties defined by EntityBase since every type that inherits from it MUST implement those members.

So there you have it, that is a basic Repository pattern base class, now lets explore how you would use this class.

In its more primitive form you could write code like such:

   1:  var series1 = new Series() { Name = "My Series" };
   2:  var series2 = new Series() { Name = "My Other Series" };
   3:   
   4:  using (var repo = new RepositoryBase())
   5:  {
   6:       repo.Add(series1);
   7:       repo.Add(series2);
   8:       repo.CommitChanges();
   9:  }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

In the next section, I will continue exploring the Repository pattern including some drawbacks and how developers are overcoming them.