Jammer.NET - Open Source C# Software Development Framework

Open Source C# Software Development Framework

Archive for August, 2007

Jammer.NET API Documentation

Posted by Randolph Cabral on Thursday August 9, 2007

Our Sandcastle documentation for Jammer.NET is up!

Check it out at:

 http://jmr.bongeek.com/

Special thanks to Mohammed Mudassir Azeemi for his generousity in hosting our docs! He’s one of the finest .NET developers in the open source community!

Click here for more information about Microsoft’s Sandcastle project.

Posted in Documentation, Getting Started | 2 Comments »

How to Create a Two-way Object Binding for ASP.NET WebForms

Posted by Randolph Cabral on Wednesday August 8, 2007

One of the features we spent a lot of time implementing is the concept of two-way object binding in ASP.NET.  The idea was to create a closer analog to windows forms style development where objects are stateful and can be bound to HtmlControls and WebControls alike.  After many cycles, we finally iterated to a successful implementation that is natural and easy to use. 

 Two-way object binding in ASP.NET with Jammer.NET is achieved by the use of serializable entities, the “PersistState” attribute, the “WebPageBase” class, and the “IAutoBindable” interface as shown in the code sample below.

    1 using System;

    2 using Jmr.Web.UI;

    3 using Northwind.Entities;

    4 

    5 public partial class Pages_JmrWebForm : WebPageBase, IAutoBindable

    6 {

    7   [PersistState] protected Customer _customer = null;

    8 

    9   protected void Page_Load(object sender, EventArgs e)

   10   {

   11     if (!IsPostBack)

   12     {

   13       _customer = new Customer(1);

   14       _customer.Load(); // Loads customer object with values from db.

   15 

   16       BindBusEntity(txtName, “_customer.ContactName”);

   17       DataBind();

   18     }

   19   }

   20 

   21   protected void btnSave_Click(object sender, EventArgs e)

   22   {

   23     _customer.Save();

   24   }

   25 }


At first glance, this code file looks like any other until you examine the logic further.  Line 5 is the first clue that something different is in the works.  Firstly, the page derives from our very own “WebPageBase” class which can be found in the “Jmr.Web.UI” namespace.  This class encapsulates many features including the ability to persist variables over postbacks and two-way object binding.  Secondly, the “IAutoBindable” interface is added to the inheritance chain.  This tells the base page class to enable binding logic as a part of page processing.  We use the “IAutoBindable” interface as a switch and therefore does not actually implement any public members.

 Line 16 is, as I like to say, where the “magic” happens.  The “WebPageBase” class implements the “BindBusEntity()” method which accepts both HtmlControls and WebControls as the first argument, and a string representation of the named object and property name as the second argument.  It is important to note that the object that is to be bound to the control must be declared at the class level and marked protected.  It also must be persisted using the PersistState attribute.  For more information about the “PersistState” attribute, please see How to Persist Object State Over Postbacks in ASP.NET WebForms.  Lastly, you must call the “DataBind()” method of the base page to invoke binding logic.  Take note, however, that the “DataBind()” method must only be called on initial page load only.  Be sure to wrap the method call with an “IsPostback” check.

The event handler “btnSave_Click” is remarkably telling.  Only one line is needed in the handler to call the “Save()” method of the “_customer” object.  Remember, the “PersistState” attribute persists the object state automatically and the object binding was defined in the “Page_Load” handler on line 16 eliminating the need to re-hydrate the “_customer” object and set object values from the “txtName” control.  All that’s left is to save the business object and if you’re using Jammer.NET entities, you get the “Save()” method automatically which updates the data store with the new values.

Clearly, this methodology indeed enables a more windows forms-like development experience for ASP.NET as the need to assign values manually or re-hydrate object state manually is eliminated.  Yes, there will still be the case to use manual value assignments and manual object state persistence, but having these capabilities when you need it has proven to be a huge time-saver for us and we hope it will be for your development efforts too.

Posted in ASP.NET, How-to, Two-way Binding | 6 Comments »

How to Persist Object State Over Postbacks in ASP.NET WebForms

Posted by Randolph Cabral on Tuesday August 7, 2007

The PersistState Attribute 

Persisting object state over postbacks in ASP.NET is a one line operation with Jammer.NET.  Meet the PersistState attribute.

[PersistState] protected Customer _customer = null;


It may not seem like much on the surface, but the result is truly empowering.  With that one line of code, the “_customer” object state is persisted in ViewState and restored on postback automatically. 

Remember the amount of code you used to have to write just to save the customer object?  Reload object state, then set property values to new values, then finally call save.  With the PersistState attribute, you no longer need to make another round trip to the database to restore object state.  Let’s examine the following example.

    1 using System;

    2 using Jmr.Web.UI;

    3 using Northwind.Entities;

    4 

    5 public partial class Pages_JmrWebForm : WebPageBase

    6 {

    7   [PersistState] protected Customer _customer = null;

    8 

    9   protected void Page_Load(object sender, EventArgs e)

   10   {

   11     if (!IsPostBack)

   12     {

   13       _customer = new Customer(1);

   14       _customer.Load(); // Loads customer object with values from db.

   15     }

   16   }

   17 

   18   protected void btnSave_Click(object sender, EventArgs e)

   19   {

   20     _customer.ContactName = txtName.Text;

   21     _customer.Save();

   22   }

   23 }

 
In this example, the “_customer” object is adorned with the PersistState attribute and is initialized to null.  The “Page_Load” event handles loading the “_customer” object on initial page load by calling “Load()” on the entity (lines 13 and 14).  Note also that lines 13 and 14 are only run the first time the page actually loads.  The surrounding “if” statement ensures this by checking the “IsPostBack” page property.

Notice the “btnSave_Click” event handler does not need to create a new instance of the Customer object.  Normally, the “_customer” object reference would be null and lines 13 and 14 would have to be repeated to prevent a null reference exception from getting thrown.

Using PersistState 

In order to activate the PersistState feature, there are three elements that are required.  First, make sure that the object to persist is declared at the class-level and marked protected.  Secondly, adorn the new variable with the PersistState attribute.  The PersistState attribute can be found in the “Jmr.Web.UI” namespace which is included as one of the using statements in the above example.  Finally, make sure your web page derives from “Jmr.Web.UI.WebPageBase”.  The “WebPageBase” class encapsulates all of the logic that makes object persistence possible. 

Changing the Persistence Container with PersistScope

It’s important to note that any data that gets saved to a pages’ ViewState causes the size of the rendered mark-up to bloat.  Because of this, ViewState may not always be the right container to persist object state.  To change the persistence container, PersistState can accept a PersistScope enumeration value as a constructor argument.  PersistScope values are as follows:  Application, Cache, Session, and ViewState where ViewState is the default value if using the default constructor.

[PersistState(PersistScope.Session)] protected Customer _customer = null;

PersistScope Values
<–This screen capture illustrates the PersistScope enumeration and its’ values.

Please see MSDN’s ASP.NET State Management Overview for more information on state management in ASP.NET.  

Posted in ASP.NET, Getting Started, How-to | No Comments »

How to Create an Entity / Object-relational Mapping

Posted by Randolph Cabral on Saturday August 4, 2007

Entities 

Jammer.NET entities contain all of the mapping metadata in-line with the C# source code.  We’ve found this implementation affords benefits that outweigh any incremental gains of keeping the mapping metadata in a separate file.  Typically, changes made to a database schema are significant enough to require changes to the C# application source anyway.  Let’s face it; how often does a requirement or feature enhancement come along that amounts to changing one column type or name?  Most feature enhancements require a significant schema and application modification that necessitate a redeployment of application code even if the enhancement is as innocuous as adding a secondary email address to a web form.

Inline Metadata Mapping using Custom Attributes

Jammer.NET takes advantage of custom attributes.  Custom attributes are adorned to the appropriate class members to define class member mappings as well as mappings to database objects and the database itself.  The following code sample illustrates how these mappings are declared.

[Database("Northwind")]

[Load("usp_Customers_Get")]

[Save("usp_Customers_Insert", "usp_Customers_Update")]

[Delete("usp_Customers_Delete")]

public partial class Customers : EntityBase, IEntityValidateable

{

  [Key][FieldMap("CustomerID")] private string _CustomerID;

  [FieldMap("CompanyName")] private string _CompanyName;

  [FieldMap("ContactName")] private string _ContactName;

  [FieldMap("ContactTitle")] private string _ContactTitle;

  [FieldMap("Address")] private string _Address;

  [FieldMap("City")] private string _City;

  [FieldMap("Region")] private string _Region;

  [FieldMap("PostalCode")] private string _PostalCode;

  [FieldMap("Country")] private string _Country;

  [FieldMap("Phone")] private string _Phone;

  [FieldMap("Fax")] private string _Fax;

 
The Database attribute defines the name of the connection instance to use which is defined in the <connectionStrings> section of the web or  application configuration file.  The Load, Save and Delete attributes define mappings to specific CRUD stored procedures which only are executed when base methods of the same names are invoked.   The following code sample shows the application configuration file definition.

<connectionStrings>

  <add name=Northwind providerName=System.Data.SqlClient connectionString=server=SERVER;database=DATABASE;uid=USER;pwd=PASSWORD />

</connectionStrings>


The Key() Attribute

The key attribute is used to define the primary key column(s) of a given table.  The usage of the key attribute is demonstrated in the following code sample. 

  [Key][FieldMap("CustomerID")] private string _CustomerID;


The FieldMap() Attribute

Creating mappings to columns in a table or columns returned by a stored procedure are defined by the use of the FieldMap() attribute.  In the following code sample,  the database column “CompanyName” is mapped to a class-level private variable “_CompanyName”.  Note: FieldMap() attributes should only be used on class-level private variables.

  [FieldMap("CompanyName")] private string _CompanyName;


Use Visual Studio IDE “Go To Definition” Functionality

Go To Definition Context MenuOne of the greatest benefits to using inline attribute-based mapping is the ability to use the Visual Studio IDE’s “Go To Definition” feature to navigate to the mapping definitions.  This feature can be used from any tier in the code base as long as the project with the source is included in your solution.  It comes in handy when you need to follow execution logic as well. 

To use this feature, place the cursor at a method or property call, or variable reference and right-click.  Select “Go To Definition” from the context menu and left-click.  Visual Studio will open the corresponding source file and auto-scroll to the proper line where the definition is made.   The image to the right is a screen capture of the context menu in Visual Studio 2005.

To return to the previous cursor location use the control-minus key stroke combination ([CTRL] + [-]).  For more IDE productivity features, you can visit Microsoft’s Visual Studio Developer Center website.

Posted in Entity (ORM) Layer, Getting Started, How-to | 8 Comments »