Archive

Archive for March, 2010

CodeFluent Entities, ASP.NET ObjectDataSource and GridView

March 17, 2010 2 comments

In this article, we will show how to use CodeFluent, to bind data to a GridView, using the ASP.NET ObjectDataSource control. We will show the following functionalities:

  1. How CodeFluent Entities takes care of paging for you,
  2. How easy it is to add sorting using PageOptionsParameter class.

We will be using Visual Studio 2010 and .NET 3.5, although this article applies also to Visual Studio 2008. We will omit the generation of the layers, assuming you already have that ready.

Setting up the ObjectDataSource with the generated BOM (Business Object Model)

In the image above, we have our solution structure, with the 3 projects:

  • Contacts.Design,
  • Contacts BOM,
  • Contacts.Website Layer for our user interface.

In the default.aspx, we will be implementing the complete example, to simplify the coding, and make it easy to understand. In real customer scenarios, all code will be put in the BOM, user controls (ascx) or custom controls in respect with your coding architecture.
Here’s the entity we will be using :

The generated Contacts database shown hereafter:

First, let’s add the references and connection string to our generated database. This connection string of course is necessary for the BOM to connect to the Contacts database:

1 – Add reference to the Business Object Model :

Select the Contacts Project, and click ok.

2 – Next, go to the Web.Config and add the following section right under the <ConfigSections> opening Tag:

<section name="Contacts" type="CodeFluent.Runtime.CodeFluentConfigurationSectionHandler, CodeFluent.Runtime"/>

This will define the possibility to have our own custom section, to manipulate database connection strings.
Next, add the following element:
<Contacts connectionString="server=(local);database=Contacts;uid=sa;pwd=SoftFluent2010"/>

3 – Now we get started with the creation of the GridView, ObjectDataSource and the aspx page

Select the Contacts.PersonCollection, or the collection you are using, and click next:

In the “Select” Tab, choose the PageLoadAll with the two parameter signature, and click Next.

pageIndex and pageSize parameters

The default values for each parameter are shown on the page. Then click Finish.

Paging

Let’s add the paging functionality. We start by setting the following properties to the ObjectDataSource:
EnablePaging="true"
MaximumRowsParameterName="pageSize"
StartRowIndexParameterName="pageIndex"

By default, Paging is already enabled, in the ObjectDataSource. The default paging mechanism for this control, is that it will load all data in memory, then, let you page through it. It can quickly become a mess if you need to load huge amounts in a heavily accessed application.

By setting EnablePaging=”true”, we’re telling the ObjectDataSource that we want to implement our own paging. In this case, we use the PageLoadAll parameters, which takes the two parameters, handled by the ObjectDataSource (MaximumRowsParameterName=”pageSize” and StartRowIndexParameterName=”pageIndex”).

This way, we let CodeFluent Entities take care of paging, by constructing only the necessary rows, and thus, gaining a lot in performance, and not having to code our own custom paging.

Notice: in we dive a little bit more into this paging mechanism, the BOM layer which is usually installed on the application server (IIS for instance), will retrieve all the rows between 1 to pageSize x pageIndex. But, only the retained rows corresponding to what the user expects in the GridView, will be constructed in memory and put in the corresponding collection, in our case, the PersonCollection object.

CodeFluent implements a great custom paging mechanism that can be easily used in your project without any development.

This is it for paging, the grid should work just fine. Here’s a complete code listing :

ASP.NET code for with paging capabilities

Sorting

For each column of you GridView that you need to sort, you must add a SortExpression:

<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName"
SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName"
SortExpression="LastName" />
<asp:BoundField DataField="Email" HeaderText="Email"
SortExpression="Email" />
</Columns>

The PageLoadAll method has two overloads, the second overload supports 3 parameters. So we will simply add the third parameters to the “SelectParameters” section.

For Sorting, we will add a custom parameter, provided by CodeFluent Entities, which will handle most of the mechanism for us.

Here’s the Register directive for this control:

<%@ Register TagPrefix="_cfwc" Namespace="CodeFluent.Runtime.Web.UI.WebControls" Assembly="CodeFluent.Runtime.Web" %>

And here’s the syntax for adding this parameter to the SelectParameters tag:

<_cfwc:PageOptionsParameter Name="pageOptions" DefaultPageSize="100" />

This will change the code list for the GridView and ObjectDataSource to this:

Using PageOptionsParameter

For now, the sorting, will still not work, as we have to tell the gridview, to use the sorting mechanism provided by CodeFluent Entities.  In this case, we will add a handler to the “OnSorting” event, in order to have custom sorting activated.

Finally, we need to add code, which will execute the HandlePostBackEvent method of the PageOptionsParameter class as shown hereafter:

Sorting event used by the GridView

Here’s the complete code listing with paging and sorting capabilities:

Complete code listing with paging and sorting capabilities

The corresponding aspx.cs code is the following:

Corresponding aspx.cs code

Notice 1:  the SortExpression must use an expression expected by the underlying stored procedure generated by CodeFluent. If you look at the content of the Person_LoadAll stored procedure, you’ll notice that CodeFluent has inserted a sorting behavior and you’ll immediately understand on which expression the sorting relies.
Notice 2: if you need to allow update operations through the GridView (also works with FormView, DetailsView and ListView), you must populate the DataKeyName attribute with the correct properties which are usually “Id” and “RowVersion” in a standard CodeFluent project.

Conclusion

In this tutorial, we illustrated how to include paging and sorting functionalities, using CodeFluent Entities, the Gridview control and the ObjectDataSource control. In upcoming articles, we will be focusing also on the ListView Control, on paging and performance, and other functionalities of CodeFluent, which can help enhance your WebForms, MVC or WebForms MVP developments.

Oussama Dinia – SoftFluent Consultant

Categories: ASP.NET

Messages in CodeFluent Entities

March 1, 2010 2 comments

CodeFluent Entities supports localization thanks to the message concept. Even though its use is quite simple, the message concept has multiple facets which we’ll describe in this section.

Local and Global Messages

Messages represent text resources in the .NET sense. It means that declaring a message in your model will generate an entry in the generated resource file (.resx file). Therefore, it’s common practice in CodeFluent Entities projects to see model parts (e.g. MyApplication.Messages.xml) which contain all localizable strings of an application. This way all the text that needs to be localized by your translation team is centralized into one file, from which the actual .NET resource files (one per handled locale) will be generated.

Defining global messages is done as so:

<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1" defaultNamespace="MyApplication">
   <cf:message name="FatalError" cultureName="fr-FR">Erreur fatale</cf:message>
   <cf:message name="FatalError" cultureName="en-US">Fatal Error</cf:message>

   <cf:message name="FileNotFoundError" cultureName="fr-FR">Erreur: Le fichier '{0}' est introuvable</cf:message>
   <cf:message name="FileNotFoundError" cultureName="en-US">Error: File '{0}' not found</cf:message>

<cf:project>

In the example above we defined global messages. Since the name attribute is specified in the message declaration, the generated resource manager class will contain corresponding properties (FatalError, and FileNotFoundError) which depending on the current thread’s culture will return one localized message version (English) or the other (e.g. French).

Messages can also be local, that is to say linked with another concept such as an entity, an enumeration, a property, a method, etc. It’s very interesting because in such cases, UI producers will be able to use localized strings representing the object rather than the object name (by default).

<GenderEnum>
(...)
 <Mrs>
    <cf:message cultureName="en-US">Mrs</cf:message>
    <cf:message cultureName="fr-FR">Mme</cf:message>
 </Mrs>
(...)
</GenderEnum>

In the example above, we declared two local messages, that are linked to the Mrs enumeration value. This way, whenever the value will be used in produced UI layers, the localized string will be used, instead of the enumeration value.

Validation Messages

CodeFluent Entities supports Validation Rules, therefore validation messages are needed to warn an end-user that typed-in data is invalid. By default, all validation rules have their default messages, however it’s possible to override those messages. Technically speaking, validation messages are global messages, that is to say messages declared at the project level. They can be overridden if necessary by declaring them explicitly in your model.

Those messages are contained in the following namespace: CFV.[ValidatorName].[ValidationRule]. For instance, overriding the validation message used by a MaxLength validation rule would be done as so:

<cf:message name="CFV.StringValidator.MaxLength"  cultureName="en-US" >
    Global English message for CFV.StringValidator.MaxLength
</cf:message>

By doing as shown here-before, all MaxLength validation messages raised by the string validator will use the specified message.

In order to modify the validation for a single property, you should declare it in the rule body such as:

<cf:property name="Code2">
      <cf:rule typeName="StringValidate" maxLength="2">
        <cf:message name="MaxLength"  cultureName="en-US" >
          English local message 'Code2' for StringValidate
        </cf:message>
      </cf:rule>
</cf:property>

Supporting Cultures

Cultures supported are the cultures defined in the application concept of your project (Design Concepts). By default, two cultures are supported: English and French in the default application. From the cultures defined in the application concept of your model, one resource file will be generated by culture. Each resource file will contain all messages of the corresponding culture name.

To support, cultures other than English and French, you need to declare handled cultures, ergo you need to define your application. Consequently the first step is to disable the creation of the default application, which can be done by setting the createDefaultApplication attribute to false on the cf:project node. Then in your own custom application, define your desired cultures.

<cf:application xmlns:cf="http://www.softfluent.com/codefluent/2005/1"
  xmlns:ctl="MyApplication.UI.CommonControls"
  xmlns="CodeFluent.Model.UI.ControlDefinitions"
  name="Custom">
(...)
    <cf:culture name="en-US"/>
    <cf:culture name="fr-FR"/>
    <cf:culture name="it-IT"/>
(...)
</cf:application>

Classes

Messages have a class attribute which lets developers specify a class to a message. This attribute is made to group messages that can afterwards be used to produce something. For instance, CodeFluent Entities provides the _doc class. Declaring a message in the _doc class will produce a code remark on the parent node in the Business Object Model (BOM).

<Car>
  <cf:message class="_doc">Code documentation for "Car"</cf:message>
  (...)
</Car>

In the example above the Car entity class will be decorated with the given message:

/// <summary>
/// Code documentation for "Car"
/// </summary>
public partial class Car: ...

Furthermore, you can define your own classes which you could use in patterns or with the Template Producer to produce extra outputs such as a RTF file documenting your BOM which was illustrated in the following post: http://codefluententities.wordpress.com/2009/08/13/generate-a-documentation-of-your-codefluent-model-using-codefluent-api/

CodeFluent Entities R&D Team

Follow

Get every new post delivered to your Inbox.

Join 52 other followers