
Introduction
Most of database application UI represent data as a combination of lists and
forms. The pages are very often the same : search criteria (form), result table
(list) with add/edit/delete buttons, and data detail (form) with ok/cancel
button. This is especially the case for admin pages (reference table like
countries / cities) without much business rules (just ensuring the relational
integrity).
A standard approach requires to develop specific code for each table and page
(data object + sql requests + aspx + code behind).
The solution described in this article consists in :
writing all that is specific into one or two description files : meta data
(table name, columns, sql commands) + rendering info (labels, edit types,
layout,...)
generating on the fly the pages for the list and the detail (search criteria
/ result list / master-detail / detail page / buttons) with all these
informations
In order to develop specific simple pages (list + edit), you just have to write
the description files and that's all. No code needed (no class, no aspx, no code
behind) !
Similar articles on CodeProject :
Universal Database Admin for ASP.NET and SQL Server
Database Viewer and Updater for any Database
Database Navigator
Difference : generates end-user UI, not only for DBA
Go to online demo
Detail.aspx - Sample generated detail page
Features
Generic data objects (table / record), data info (metadata) and rendering
info (how to display a table or a record depending on the context)
Interfaces for retrieving and saving the datas : Reader / Writer. The
standard reader and writer access the database but since it's an interface they
can be replaced (for exemple LDAP requests or CSV/XLS files)
Generator on the fly for list / record pages and automatic data binding
Multi-language resources, but also multi-target, multi-user role, multi-client
ASP.NET 1.1 and 2.0, written in C# for .NET 1.1 and 2.0
ADO.NET : Oracle, MySql, Access, SqlServer,...
Possible customization of controls : adding edit types for your specific
needs and the generator would create your web controls
Logging with Log4net (encapsulated so it can be replaced easily)
WindowsForms : to do !
This is mainly for IT developers, not yet for non-developers. Simples pages
can be generated without effort. It also can be used for more complex pages :
the developer would inherit the default page and assemble user controls
(generated by the tool).
This tool is supposed to remain relatively lightweight, simple and extensible.
I'm not a fan of complex architectures especially for simple functionnalities
like CRUD. But I think it can be used with other frameworks : O/R mapping (like
NHibernate) by reflection, controller (like Maverick or NStruts) by interface
(the controller can be replaced).
Description files
The description files consists in :
a module file : sql commands / table / columns / data types and rules / relations
one or many resource file : rendering properties like labels, visible,
enabled, edit types (text box, combo-box, radio buttons, check-box, ...), access
control (can read / insert / update / delete depending on user role), texts,...
These are simple text files with sections (like .ini with parameters in
sections) because they are more human friendly. In future versions, there should
be XML files (if possible compliant to SOAP or NHibernate DTD) and even a
Windows UI for generating and editing these files.
There can be a resource file for each language. The rendering properties may
depend on the language, the action (view/edit/new/�), the target
(web/windows/pocket), the user role (admin / guest / �) and the client base (if
you want to distribute the same application to different customers with
different parameters).
#---- module file for currency table ------------------------------------
[sql]
select = select * from currency
order by cur_cd
selectOne = select * from currency
where cur_id = ?cur_id
checkBeforeDelete = select count(*) from country where cur_id = ?cur_id
#------------------------------------------------------------------------
[table]
name = currency
primaryKeys = cur_id
#------------------------------------------------------------------------
[column name=cur_id #nullable=0]
[column name=cur_cd type=VA3 nullable=0]
Unique = 1
[column name=cur_name domain=name nullable=0]
[column name=cur_name_2 domain=name nullable=0]
[column name=cur_name_3 domain=name]
[column name=cur_type type=N2 nullable=0]
[column name=cur_status type=B nullable=0]
[column name=cur_rate type=N10,5]
[column name=cur_creation_date type=D]
#------------------------------------------------------------------------
[relation columns=cur_type]
Reference = currency-type
ReferenceColumns = cur_type
DisplayField = cur_type_name
See screens below
#---- resource file for currency table (english version) ----------------
[TableRender]
ListTitle = List of currencies
ColumnOrder = cur_cd, cur_name_2, cur_type, cur_status, cur_rate
EditOrder = cur_cd, cur_name_2, cur_name, cur_name_3, cur_type, cur_status, cur_rate, cur_creation_date
EditTitle = Currency detail : {cur_name_2}
[TableRender action=new]
EditTitle = New currency
#------------------------------------------------------------------------
[ColumnRender name=cur_cd]
Label = Code
Link = 1
[ColumnRender name=cur_name]
Label = Name (french)
[ColumnRender name=cur_name_2]
Label = Name
[ColumnRender name=cur_name_3]
Label = Name (german)
[ColumnRender name=cur_rate]
Label = Exchange rate (USD)
[ColumnRender name=cur_type]
Label = Type
RelationDisplayField = cur_type_name_2
[ColumnRender name=cur_status]
Label = Accepted payment
[ColumnRender name=cur_creation_date type=D]
Label = Creation date
There can be expressions. For exemple :
# the column "cur_name_2" will be retrieved from the record
EditTitle = Currency detail : {cur_name_2}
# record will be updateable only if the IsAdmin property
# in the session is set (either by param/key or by reflection)
EditUpdateable = {session.IsAdmin}
The layout can be more complex :
# adds a sublist below the main form
[TableRender]
DetailLists = currency_country
ActiveDetailList = 0
# the layout can be a complex hierarchy of tables / rows / cells
[EditRender]
Layout = row1, row2, row3, row4, row5, row6, row7
row1 = cur_cd
row1.BackColor = magenta
row2 = cur_name_2
cur_name.width = 100px
row3 = cur_name, cur_name_3
cur_name_2.width = 100px
cur_name_3.width = 100px
row4 = cell41
cell41 = label1
cell41.ColumnSpan = 4
label1.Text = Currency properties
label1.ForeColor = #EE00FF
label1.Width = 200px
label1.Height = 20px
row5 = cur_type
row6 = cur_status, cur_rate
row7 = cur_creation_date
Generates Detail.aspx

Class diagram

data objects : Record and RecordTable which are a kind of enhanced DataRow
and DataTable, contains them so standard DataTable controls can be used
(DataGrid / DataList)
data info : RecordInfo with metadata (table / columns properties)
relation info : relation between a source and a destination RecordInfo with
column correspondance (id and label)
render info : RecordRenderInfo depending on a RenderContext (language,
action, target, user role and client base)
Data access layer : interface for reading and writing records. The default
implementation access the database but there can be other implementations for
LDAP or CSV / XLS files.
public interface IRecordEnumerator : IEnumerator {
Record CurrentRecord { get; }
}
public interface IRecordReader : IRecordEnumerator {
RecordInfo RecordInfo { get; }
int Depth { get; }
bool IsClosed { get; }
int RecordsAffected { get; }
void Close();
DataTable GetSchemaTable();
bool NextResult();
bool Read();
int RowNum { get; }
object Parameters { get; }
}
public interface IRecordWriter {
void ExecuteWriter(IDbConnection dbConnection, IDbTransaction dbTransaction, Record rec);
void ExecuteWriter(IDbConnection dbConnection, IDbTransaction dbTransaction, RecordTable rt);
}
Controller / UserControl / Page
There are UserControls (class + ascx) and Pages (class + aspx) for a record and
a list. They implement interfaces so they can be replaced by other classes and controllers.
The interface can even serve for WindowsForms.
The list page (List.aspx) contains a record list (RecordTable or RecordReader),
eventually a parameter record (search criteria) and other elements (message
label for confirmation / warning / error messages, pagination, buttons).
<!---->
<asp:Label id="lblMessage" runat="server" Visible="false"></asp:Label>
<form runat="server">
<% if (HasVisibleParameters) { %>
<ucRecord:Record id="paramRecordControl" runat="server"></ucRecord:Record>
<input type="hidden" name="__action" value="search">
<asp:Button id="btSearch" runat="server" Text="Search" onclick="btSearch_Click"></asp:Button>
<% } %>
<ucList:RecordList id="listControl" runat="server"></ucList:RecordList>
<ucPagination:Pagination id="paginationControl" runat="server"></ucPagination:Pagination>
<asp:Button id="btAdd" runat="server" Text="Add" onclick="btAdd_Click"></asp:Button>
</form>
-->
The detail page (Detail.aspx) contains the main RecordControl, a message label,
validate / cancel buttons and eventually a sublist (RecordTableControl)
<!---->
<form runat="server" Id="form1">
<asp:Label id="lblMessage" runat="server" Visible="false"></asp:Label>
<ucRecord:Record id="recordControl" runat="server" RecordName="record"></ucRecord:Record>
<% if (RenderContext.IsViewAction || RenderContext.IsViewSummaryAction) { %>
<asp:Button id="btReturn" causesValidation="false" runat="server" Text="Retour" onclick="btCancel_Click"></asp:Button>
<asp:Button id="btEdit" runat="server" Text="Modifier" onclick="btEdit_Click"></asp:Button>
<% }
else { %>
<asp:Button id="btCancel" causesValidation="false" runat="server" Text="Annuler" onclick="btCancel_Click"></asp:Button>
<asp:Button id="btValidate" runat="server" Text="Valider" onclick="btOK_Click"></asp:Button>
<% } %>
<asp:ValidationSummary id="validationSummary" runat="server"></asp:ValidationSummary>
<br>
<% if (!RenderContext.IsNewAction && RecordRenderInfo.HasDetailList) {
btAdd.Text = GetText("button.AddSublist");
%>
<ucList:RecordList id="subListControl" runat="server"></ucList:RecordList>
<br>
<asp:Button id="btAdd" runat="server" Text="Add" onclick="btAddSublist_Click"></asp:Button>
<% } %>
</form>
-->
Controller source (List.aspx.cs)
void Page_Init(object sender, EventArgs e) {
base.Page_Init(sender, e);
if (HasVisibleParameters) {
paramRecordControl.Record = ParametersRecord;
paramRecordControl.BuildControls();
}
}
void Page_Load(object sender, EventArgs e) {
base.Page_Load(sender, e);
if (HasVisibleParameters) {
if (!IsPostBack) paramRecordControl.RecordToControls();
else paramRecordControl.ControlsToRecord();
}
ExecuteReader();
if (IsReaderMode) {
listControl.RecordReader = RecordReader;
paginationControl.PageSize = 0;
}
else {
listControl.RecordTable = RecordTable;
paginationControl.PageSize = RecordRenderInfo.PageSize;
paginationControl.PageNum = PageNum;
paginationControl.RowCount = RecordTable.Count;
}
btAdd.Text = GetText("button.Add");
btSearch.Text = GetText("button.Search");
}
Open source project
The work is not finished yet. I have many improvements in mind. I need help for
continuing the work and also would like to share ideas with the community. So I
propose this as an open source project !
People needed for development, testing, documentation, website administration,
translations,... The open source licence would be simple and commercial use would
be authorized.
Please reply to this thread or write me at the address provided in the online demo.
| You must Sign In to use this message board. |
|
|
 |
|
|
 |
|
 |
After converting the databaset to MSSQL and changing in the connection string ..still receiving error.
dd
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
Hi, I am getting following errors while debugging the Source code. Error 211 The type 'Greco.Util.RecordInfoParser' has no constructors defined Error 213 The best overloaded method match for 'Greco.View.RecordRenderInfo.Init(Greco.Model.RecordInfo)' Error 214 Argument '1': cannot convert from 'Greco.Model.RecordInfo [ Error 215 The best overloaded method match for 'Greco.View.FieldRenderInfo.Init(Greco.Model.RecordInfo)' has some invalid arguments Error 216 Argument '1': cannot convert from 'Greco.Model.RecordInfo [D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfo.cs(12)]' to 'Greco.Model.RecordInfo Error 225 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse1' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfoFactory.cs Error 226 'Greco.Util.RecordInfoParser' does not contain a definition for 'HasStaticValues' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfoFactory.cs Error 227 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse2' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfoFactory.cs Error 228 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse3' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfoFactory.cs Error 233 The best overloaded method match for 'Greco.Db.DbProvider.ExecuteReader(System.Data.IDbConnection, Greco.Model.RecordInfo, object, bool)' has some invalid arguments Error 234 Argument '2': cannot convert from 'Greco.Model.RecordInfo [D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfo.cs(12)]' to 'Greco.Model.RecordInfo Error 239 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse2' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordFactory.cs Error 240 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse3' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordFactory.cs Error 242 'Greco.Util.RecordInfoParser' does not contain a definition for 'HasStaticValues' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordFactory.cs Error 243 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse2' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordFactory.cs Error 244 'Greco.Util.RecordInfoParser' does not contain a definition for 'Parse3' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordFactory.cs Error 256 The best overloaded method match for 'Greco.Db.DbProvider.ExecuteWriter(System.Data.IDbConnection, System.Data.IDbTransaction, Greco.Model.RecordTable)' has some invalid arguments Error 257 Argument '3': cannot convert from 'Greco.Model.RecordTable [D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordTable.cs(13)]' to 'Greco.Model.RecordTable [d:\TL\Greco-demo\bin\Greco.dll]' Error 258 The best overloaded method match for 'Greco.Db.DbProvider.ExecuteWriter(System.Data.IDbConnection, System.Data.IDbTransaction, Greco.Model.RecordTable)' has some invalid arguments Error 259 Argument '3': cannot convert from 'Greco.Model.Record' to 'Greco.Model.RecordTable' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordFactory.cs Error 272 The best overloaded method match for 'Greco.View.RecordRenderInfo.RecordRenderInfo(Greco.Model.RecordInfo)' has some invalid arguments Error 273 Argument '1': cannot convert from 'Greco.Model.RecordInfo [D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfo.cs(12)]' to 'Greco.Model.RecordInfo Error 274 'Greco.View.RecordRenderInfo' does not contain a definition for 'renderContext' D:\TL\UIGenerator\UI_Generator\UI_Generator\RecordInfo.cs
And also i want the source code for Greco.View and Greco.util.
Kindly help me to fix the above issues. Thanks in advance.
Gayathri
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi all, Could you please help me how to view and retrieve records of a table using data adaptor or command in ASP.NET...
Thanks alot
Nour Abdel-Salam
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hello
We are searching for exactly the same interface for admin screens. We would like to help you with adding the following options : - adding filtering and paging on list view - change the config to xml schema - adding events from user controls to be able to update the graphic interface and behaviour - ....
how can we coordinate to work together on this project ?
we are also situated in Paris, Issy les moulineaux plus exactement
Thanks
Dimitri (dimitri@fwa.eu)
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Thanks for encouragements 
Yes, a GUI for description files would be great, and also a database browser.
Next version will have this, as well as a WindowsForms generator (it's simplier to generate WindowsForms than ASP.NET).
I also would like to have a PetShop Store demo application, so my presentation could be more convincing. I've read the implementation of PetShop Store by Microsoft in 2002-2003 : http://www.gotdotnet.com/team/compare/petshop.aspx http://www.microsoft.com/downloads/details.aspx?FamilyId=E2930625-3C7A-49DC-8655-A8205813D6DB&displaylang=en I think it's possible to develop the same with much less code.
At the moment, my problem is time/energy because I develop it alone at home. If someone else wants to take part of it...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Good approach.
The next step is to define database table relations and compose entire database editing on dynamic generated site with site map and etc.
So after you change the connection string your site will be absolutly different for each database schema 
AnatolyS
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
Thanks for encouragements 
Table relations can already be defined with [relation] sections. It serves for generating combo-box / list-box / radio-buttons. For exemple :
[relation columns=cnt_id] Reference = country ReferenceColumns = cnt_id DisplayField = cnt_name
These relations can have parameters and depend on other columns values. For exemple displaying only the cities of the selected country ("Params" & "ReferenceParams") :
[relation columns=cty_id] Reference = organization-city ReferenceColumns = cty_id DisplayField = cty_name Params = cnt_id ReferenceParams = cnt_id
The next version will have a database browser so every table could be managed without even writing something (except the connection string) and description files could be also generated. My main problem is time/energy because I have a full time job in software company and I develop this tool at home...
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
|