Net-Q Networks Dotnet Module Structure

The general structure of applications built with this DotNet framework is a solution that contains about a dozen projects.  Each project either produces a program or a DLL library.  There are several core themes in this design.
  1. The database is created in SQL Server and becomes the framework upon which to build the application.
  2. A code generator program accesses the database and generates the code necessary to translate the database tables into data objects, and save these objects to their corresponding tables.
  3. The DB module provides all database interaction.
  4. The data objects are manipulated by a set of business classes isolated to a business module.
  5. The programs that interface with the outside world entirely depend on these modules.
All components are written in the dotnet framework and C# language.  Each component is a Visual Studio project.  This diagram represents the dependency tree of the various projects in the solution.

Module Structure

DB Module

This module is based on a design proposed by Mike Robski.  The Data Access class is called "DataMapper".  There is one Data Mapper class named [Table]DM and one Data Object class named [Table]Object generated for each table in the database.  The Data Object class provides a one-to-one mapping of database columns to Class attributes.  All the code  in these files is C#. The DataMapper extends a base class that provides data binding for each data type, basic Fetch functionality and handles the database connection protocols.   Each Data Mapper class includes methods for Fetch, Save, Update, Delete.  A ReadAllCommand() method provides a base SQL command for selecting the data for the standard data object.  A LoadFrom() method maps the loaded database values to C# data values in the Data Object class.  Each DataMapper depends on the generated Data Object class.

The DataObject classes extend a base class in Core.  This class defines an ObjectList as an extension of the dynamic List class in DotNet.  Results returned from the data mappers are either of the type  [Table]Object or ObjectList<[Table]Object>.  The chief advantage of ObjectList over List is it provides a RenderAsTable()  method that returns a Dotnet DataTable object for the returned list of objects.  DataTables when provided as DataSources to GridView controls allow sorting on any column, whereas Lists do not.

In most cases, new access methods are added to the DataMapper modules tuned to the needs of the application screens.  This is preferable to passing SQL fragments to a generic Fetch() method.  

In some cases, special Report Object classes are defined within the DataObject file and used to package the results for particular reports.  In other cases, the DataObject just adds new attributes to support the extended data requirements of reports.

With the DB Module in place, all other components do all database access through these classes.  SQL code never appears outside of the DB Module.

Bus Module

If the required data for the application is a simple list of objects, the web screens or services may call DataMapper methods directly.  In many cases, the returned data needs to be modified, or the request needs to be augmented before the DataMapper method can be called.  This may often require references to other types of objects.  While it is possible to place this logic in the application screen, it is generally located in a Business class in this module.  Business methods are generally grouped thematically into files of related operations on similar DataObjects.  In this role, Business classes act as a wrapper for DataMapper classes.  

Business module classes also implement communication with other data sources.  An example is a ConstantContact class that controls communication with the ConstantContact API.  Other classes provide communication with external (SOAP) web services as needed.  Another Business class controls the Paypal API interaction.

A core class of the Business module is the Privilege class.  This uses a set of tables in the database to implement limited access to individual screens, and particular operations within the screens.  Any action that can allow changing data checks first for a privilege, before the button is displayed.  Lack of a privilege disables an active control.  Access for each screen is granted to groups, and each user is a member of one or more groups.

Controls Module

While the application uses largely standard Microsoft controls, it encapsulates some re-used screen controls in a Controls Module.  Many Drop Down Lists are implemented as a specific control including its data source.  Extensions to validation controls are defined in this module, as well as the basic extended controls for GridView, Buttons, HyperLinks, and LinkButton.  The extended controls allow the implementation of Privileges for these operations.

Web Application

The central application is a dotnet web application, with a separate designer file.  All aspx files are built as Code Behind with the partial classes containing all code.  The methods in these Page classes tend to be event handlers for the controls on the screen.  They do no data manipulation themselves, so each method tends to be very short.

Each web application screen is a Web Content screen with a Master Page.  There are two master pages, one with built-in navigation, and one with no navigation.  The primary master page includes a static Navigation Menu and the logic to restrict access based on privileges.  The Privileges class has the ability to regenerate the access data table from the Master Page navigation tree.  Both Master Pages provide for standard display of information and Error messages via an ErrorMessage class.

The aspx files are built almost entirely from GridViews and FormViews.  All data access is through ObjectDataSources defined at the top of each aspx file.  The typical aspx files will be based on a MultiView Control, with the default view displaying a GridView of the items of interest.  Selecting a record in the grid view will cause an event to switch to a view containing a formview that edits the selected record.  A  button on the page will switch to a view with a Form to insert a new object.  Each FormView on a screen will generally be either Edit mode or Insert mode.  ReadOnly mode is seldom used, and no FormView includes more than a single template.  The basic FormView class is used on all screens, styled by the Skinfile in the current Theme.  The GridView, however, is always a customized GridView that provides better record navigation and support for delete verification.  This, and all other custom controls are defined in the Controls module.  

The web application has several folders that store special elements.  The UserControls folder contains all the UserControls used by the aspx screens.  To reduce the size and complexity of screens, special UserControls are defined for certain operations (Edit or Add).  These are then embedded in the screens in a particular MultiView view.  UserControls generally provide their own data source, and are on occasion re-used in multiple screens.

The Reports folder contains all reports in the application.  Each report is built on the DotNet ReportWriter (rdlc) control.  This places certain restrictions on the flexibility of reports, but it provides easy generation of PDF and Excel files for output.  Reports always use ObjectDataSources provided in the containing aspx file.

Nearly all ObjectDataSource Update or Insert operations catch the  OnUpdated or OnInserted events in a method that checks for Errors, and displays them in a designated field.  When the application screen is a single files, these events may also force the DataBind() event to be raised for GridViews or Forms that are likely changed by them.  When multiple files are used, the UserControl will generally raise a custom Event caught by the parent to re-display the screen as needed.

Web Service

All applications other than the Web Application that use this system obtain their data exclusively from a Web Service module.  This module contains thematically related classes that implement methods to select data for display and save new records.  Most of these methods are fairly lightweight, depending on Business methods to do most of the work of validation and repackaging.  The web services are available to external websites and Windows applications.  Since the database is always remote from the active site, Windows applications need to use the internet to obtain and save data.  

Batch Applications

There is generally at least one Batch Application that is a Console Application built on the underlying DLLs.  This application can be run overnight to update data from external sources or complete operations that might otherwise interfere with performance during the day.  One regular function of this application is to synchronize the local database with Constant Contact and external POS systems.

Windows Applications

The role of collecting sign-in data from non-staff users is provided by a set of Windows Applications.  Unlike browser-based web applications, these cannot be redirected for other purposes.  They install a complete, encapsulated environment that is easier to configure at remote sites.  The screens implement forms for data capture that are saved to a common Lookup class.  This class communicates with a DataAccess class that controls communication with the relevant Web Service.  In some cases, the application has the ability to operate when disconnected from the internet by caching needed data in a local SQL Express database, then resynchronizing with the Web Service when it becomes available.  The DataAccess class manages this transparently to the Screens or Lookup classes.

The Windows Applications, because they are public facing, provide more data protection than the Web Application.  This is a bit of a switch on traditional design, where the web application is the public facing program.  In general, the Windows Applications will not supply personal information based on incomplete identifying data.  The Web Application will provide auto-complete Ajax controls for finding likely matches for people's names.