# "Wisej Pubs Demo App", an application for beginners

*by* [*Gabriele del Giovine*](https://www.learnwisej.net/authors/gabriele-del-giovine)*, translated by* [*Julie Hirt*](https://www.learnwisej.net/authors/julie-hirt)

## 4.1 Introduction

In this chapter, we explore the structure of an application for beginners that presents concepts and functional characteristics typical of line-of-business (LOB) applications. The application includes login management, access to databases, and the corresponding presentation of data, as well as user interface management functions with search and reporting mechanisms. "Wisej Pubs Demo App" constitutes a simple starting point in code structure and at the same time introduces the necessary development concepts to tackle the world of web-based LOB. You can find the online demo here: <https://wisejdemo.delgiovine.it/WisejPubsDemoApp>, while the original source code can be found at <https://github.com/gdelgiovine/WisejPubsDemoApp>. A forked copy of the source code which has been improved in order to make it easier to run on a new machine can be found here: <https://github.com/JulieHirt/WisejPubsDemoApp>.

## 4.2 The structure of the application

The application implements the management of a slightly modified version of the sample database used in Microsoft SQL Server in its early days, the famous DB Pubs, which is the database of a book distribution organization. The application uses a mix of the Web Application template and the Web Desktop Application template. In terms of the role distribution patterns/methods, such as the popular MVC (Model, View, Controller) pattern, this application, due to the need for conceptual simplicity, uses a much simplified approach that involves a Model and ViewControllers (the classic forms of Windows Forms). In reality, there is nothing preventing you from organizing your projects according to preferred patterns, and Wisej.NET, unlike many typical development environments for LOB applications, does not restrict the developer to rigid architectural models.

\
Regarding data management, I employ a basic type of object-relational mapping (ORM) that I have written myself, which almost completely hides the programmer from the challenges of database access and management. This ORM, called BasicDAL, integrates with Wisej.NET in data presentation functions, as well as in search and reporting functions by integrating "SAP Crystal Reports for Visual Studio" (required to run the application). BasicDAL and the extensions for Wisej 3.0 are always available at <https://github.com/gdelgiovine>. I chose to use this ORM precisely because it is extremely concise and relatively simple compared to more powerful tools, which tend to be much more complex.

Below are some screenshots of the running application.

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2F1PoKF1I9D0ornzY5Lrur%2Flogin.png?alt=media&#x26;token=e2ec8749-40f9-4015-94c5-6eb80d6f4819" alt=""><figcaption><p>Login Function</p></figcaption></figure>

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FOwuNgP8evpTzc5TI7suC%2Fdesktop.png?alt=media&#x26;token=be562022-d903-4722-a803-174eced0357d" alt=""><figcaption><p>Desktop after logging in</p></figcaption></figure>

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2Fa11oXrybdynGklY0Y2sh%2Fstandardform.png?alt=media&#x26;token=e112aebe-239c-459c-b598-d9ef842b6273" alt=""><figcaption><p>Standard form</p></figcaption></figure>

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FIhBHU4AQ9jFtgLTXISn3%2Fsearchfunction.png?alt=media&#x26;token=0bdbc9d1-b0e5-4466-970c-97f06a782c82" alt=""><figcaption><p>Search function in the navigation bar</p></figcaption></figure>

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FdT7iyyVOa1XezERb4Z4m%2Freportsexecution.png?alt=media&#x26;token=6d40771e-2789-4be4-ad2b-49f17e3c8373" alt=""><figcaption><p>Reports execution with function that can be called from the navigation bar.</p></figcaption></figure>

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FqtTBPb6ZovtXywyaeaDV%2Fwisejdemoapp.png?alt=media&#x26;token=542aaecc-c2b2-4a2e-b1b3-5850cbdacaf6" alt=""><figcaption><p>Standard form with Forms-List View, look-up for validation data management and master-detail relationship management.</p></figcaption></figure>

Below is the structure of the Visual Studio project as shown in the "Solution Explorer" section.

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FPlAV4wsYC130A0gBSA5E%2Fsolutionexplorer.png?alt=media&#x26;token=17d29919-6135-45b8-87a6-820e86d857ef" alt=""><figcaption></figcaption></figure>

The "Default.json" file contains the full name of the method for starting the application- `WisejPubsDemoApp.Program.Main` - which indicates a namespace of `WisejPubsDemoApp` containing the `Program` class and the `Main()` method.

```json
{
"url": "Default.html",
"startup": "WisejPubsDemoApp.Program.Main, WisejPubsDemoApp"
}
```

To see the code that runs when the application starts, we can open the "Program.cs" file, which contains the `Main()` method:

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2F3Zq7XEWhQeyYjnTFMULP%2Fprogram_cs.png?alt=media&#x26;token=b143fa9e-16ab-4307-a916-09cc1652f210" alt=""><figcaption></figcaption></figure>

In the `Main()` method, we find the creation of an object of the `frmLogin` class and the invocation of its `Show()` method. It's worth noting that the prefix "frm" is used to identify all the `Form` objects that will be used in the application to manage user interaction.

## 4.4 The `frmLogin` object

The `frmLogin` object is an instance of the `Wisej.Web.Form` class. It implements the functionality that prompts the user to enter a username and password, verifies their correctness, and, in case of success, passes control of the flow to another object, this time of type `Wisej.Web.Desktop`. Let's take a look at the interesting elements of `frmLogin`.

<div><figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FmIAqg7jV651bIaj65Tfi%2FfrmLogin.png?alt=media&#x26;token=7f77909b-3dda-42b0-99d4-72f5ae35eabe" alt=""><figcaption><p>frmLogin as viewed in the Visual Studio Designer</p></figcaption></figure> <figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FWDs0jhLEJB6eSUuQxL4Y%2FdocumentOutline.png?alt=media&#x26;token=451b2b1d-cd8a-486f-bd8f-b6be87821db1" alt=""><figcaption><p>The Document Outline for frmLogin</p></figcaption></figure></div>

{% hint style="info" %}
NOTE: `Wisej.Web.Form` objects correspond to the "Empty Window" template.
{% endhint %}

When viewed in the designer, you can see that the `frmLogin` object is a `Form` with two textboxes and a button.&#x20;

Shown below is the code for the `frmLogin` class:

```csharp
//frmLogin.cs
using System;
using Wisej.Web;

namespace WisejPubsDemoApp
{
    public partial class frmLogin : Form
    {
        public AppConfig appConfig = new AppConfig();
        System.Collections.Generic.List<WebAppUser> _WebAppUsers;
        public frmLogin()
        {
            InitializeComponent();
            // create users list - this is only for demo purpose NEVER use in a real application
            _WebAppUsers = new System.Collections.Generic.List<WebAppUser>();
            _WebAppUsers.Add(new WebAppUser () { UserName = "User1" , Password = "Password1" });
            _WebAppUsers.Add(new WebAppUser() { UserName = "User2", Password = "Password2" });
            _WebAppUsers.Add(new WebAppUser() { UserName = "User3", Password = "Password3" });
        }
        private void btn_Login_Click(object sender, EventArgs e)
        {
            if (!IsValidLogin(ref this.appConfig.CurrentWebAppUser))
            {
                MessageBox.Show("UserName or Password not valid!");
            }
            else
            {
                PubsDesktop pubsDesktop = new PubsDesktop();
                pubsDesktop.appConfig = this.appConfig;
                pubsDesktop.Show();
                this.Close();
            }
        }
        private bool IsValidLogin(ref WebAppUser LoggedInWebAppUser)
        {
            LoggedInWebAppUser = new WebAppUser() ;
            WebAppUser UserToCheck = new WebAppUser();
            UserToCheck.UserName = this.txt_UserName.Text.Trim().ToLower();
            UserToCheck.Password = this.txt_Password.Text;
            bool UserOk = false;
            foreach (WebAppUser _WebAppUser in _WebAppUsers)
            {
                if (_WebAppUser.UserName.ToLower()  == UserToCheck .UserName)
                {
                    if (_WebAppUser.Password == UserToCheck.Password)
                    {
                        LoggedInWebAppUser.UserName  = _WebAppUser.UserName;
                        LoggedInWebAppUser.Password  = _WebAppUser.Password ;
                        this.appConfig.CurrentWebAppUser = LoggedInWebAppUser;
                        UserOk = true; 
                        break;
                    }
                }

            }
            return UserOk;
        }
    }
    public class WebAppUser
    {
        public string UserName;
        public string Password;
        public WebAppUser()
        {
        }
   
    }
}        
```

When examining the "frmLogin.cs" code, note the use of a provider class called `AppConfig`. This class contains all the configuration objects and operational parameters of the application. Each class that is capable of receiving an instance of `AppConfig` has a public attribute called `appConfig`.

```csharp
public AppConfig appConfig = new AppConfig();
```

`AppConfig` is propagated to all classes that need such information- `frmLogin`, `frmTitles`, `frmStores`, `frmSales`, `frmRoySched`, `frmPubsInfo`, `frmPublishers`, `frmJobs`, `frmEmployee`, `frmDiscounts`, and `PubsDesktop`. Shown below is the code where the instance of `AppConfig` is passed from `frmLogin` to `PubsDesktop`:

```csharp
//frmLogin.cs
PubsDesktop pubsDesktop = new PubsDesktop();
pubsDesktop.appConfig = this.appConfig;
```

The `AppConfig` class contains an instance of the `WebAppUser` class within it, which will hold the username and password of the user who has successfully authenticated through the private method `IsValidLogin()`. If the user is authenticated correctly, the instance of `AppConfig` is passed to the `PubDesktop` object, which represents the Web Desktop that will host all the other forms of the application.

Please note that the authentication section mentioned here is for a demo application, and it's crucial NOT to hardcode usernames and their corresponding passwords in actual programs. Regarding authentication, Wisej.NET can utilize "anonymous" authentication or Windows authentication (in the case of applications developed for the .NET Framework). You can choose the authentication types and enable SSL usage in the Project's Properties.

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FpzkstYwHihCpw65U84I4%2Fauth.png?alt=media&#x26;token=6cd4ba05-747e-481c-899f-fccc9d22e470" alt=""><figcaption></figcaption></figure>

## 4.5 The `AppConfig` object

In the"AppConfig.cs" flie,you will find the class responsible for retrieving some of the configuration parameters from the "Web.Config" file and passing the application's configuration to various components. Let's analyze it in detail.

```csharp
//AppConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WisejPubsDemoApp
{
    public class AppConfig
    {
        public WebAppUser CurrentWebAppUser = null;
        public BasicDAL.DbConfig DbConfig;
        public bool IsPublicDemo = false;
        public string PublicDemoMessage = "";
        public AppConfig()
        {
            DbConfig = new BasicDAL.DbConfig();
        }

        public Boolean ReadWebConfigAppConfig()
        {
            bool _ok = false;
            if (System.Configuration.ConfigurationManager.AppSettings.Count > 0)
            {
                try
                {
                    this.IsPublicDemo  = Convert.ToBoolean (System.Configuration.ConfigurationManager
                                                                   .AppSettings["IsPublicDemo"]);
                    this.PublicDemoMessage = System.Configuration.ConfigurationManager
                                                                  .AppSettings["PublicDemoMessage"];
                    this.DbConfig.ServerName = System.Configuration.ConfigurationManager
                                                                    .AppSettings["DbConfigServerName"];
                    this.DbConfig.DataBaseName = System.Configuration.ConfigurationManager
                                                                    .AppSettings["DbConfigDataBaseName"];
                    this.DbConfig.UserName = System.Configuration.ConfigurationManager
                                                                    .AppSettings["DbConfigUserName"];
                    this.DbConfig.Password = System.Configuration.ConfigurationManager
                                                                    .AppSettings["DbConfigPassword"];
                    this.DbConfig.AuthenticationMode = Convert.ToInt32(
                                                                       System.Configuration.ConfigurationManager
                                                                       .AppSettings["DbConfigAuthenticationMode"]
                                                                       );
                    // AuthenticationMode = 0 (Zero) means DB Native Authentication
                    // AuthenticationMode = 1 (One) means Windows Authentication

                    _ok = true;
                }
                catch (Exception)
                {
                    Wisej.Web.MessageBox.Show("Error reading Web.Config");
                    _ok = false;
                }
            }
            return _ok;
        }

    }
}
```

The `AppConfig` class contains two objects: `CurrentWebAppUser` of type `WebAppUser` and `DbConfig` of type `BasicDAL.DbConfig`. The latter object is part of the ORM (Object-Relational Mapping) library "BasicDAL" and, specifically, is responsible for managing the connection context to an ADO.NET data source. To function correctly, it requires certain mandatory parameters such as the DB Server name, database name, authentication mechanism used, and optionally the username and password to access the database if our database server doesn't support Windows authentication. All of these parameters are used to generate the database connection string. In our implementation, these parameters are stored in the Web.Config file and are read by the `ReadWebConfigAppConfig` function. Below is the relevant snippet from Web.Config.

```xml
<appSettings>
    <add key="Wisej.LicenseKey" value=""/>
    <add key="Wisej.DefaultTheme" value="Bootstrap-4"/>
	<add key="IsPublicDemo" value="false"/>
	<add key="PublicDemoMessage" value="Sorry! This is a Public Demo. Add or Delete is not allowed!"/>
	<add key="DbConfigServerName" value="(local)"/>
	<add key="DbConfigDataBaseName" value="pubs"/>
	<!--DbConfigAuthenticationMode  0 = Native DB Auth (username/password) 1 = Windows Integrated Auth. -->
	<add key="DbConfigAuthenticationMode" value="0"/>
	<!-- DON'T DO THIS IN REAL WORLD!!! ALWAYS CRYPT VALUE THAT CONTAINS SENSIBLE DATA-->
	<add key="DbConfigUserName" value="WisejPubs"/>
	<add key="DbConfigPassword" value="pubs"/>
	<!-- DON'T DO THIS IN REAL WORLD-->
  </appSettings>
```

## 4.6 The PubDesktop object

\
This class serves two fundamental functions:

1. **Completing Configuration Retrieval**: It completes the retrieval of configuration settings, such as those related to database access.
2. **Menu Management**: It implements the management of the menu that allows the selection of interactive application functions available to the authenticated user.

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2F3QGChJt1rM794XUIXqOQ%2Fpubdesktop.png?alt=media&#x26;token=48953cd6-fff3-4019-8d01-2eeb0e090a24" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
NOTE: Desktop objects such as **PubDesktop** are instances of the Wisej.Web.Desktop class and correspond to the "Custom Desktop" template.
{% endhint %}

Scrolling through the class code, we can observe, highlighted in yellow, some aspects that will be subject to further examination

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2F2GlS6zYYD7Bo2cN5qjTn%2Fpubdesktop2.png?alt=media&#x26;token=5cfe1cc6-2a86-4c81-81cf-55d3c28d4f4f" alt=""><figcaption></figcaption></figure>

`PubDesktop` has a public instance of the `AppConfig` object. As mentioned previously, the `AppConfig` object has been passed from the Login window (`frmLogin`), and it contains the `CurrentWebAppUser` object populated with the username and password.

```csharp
public AppConfig appConfig = new AppConfig();
```

The  `LoadAppConfig` method is invoked by the event handler for the Desktop's `Load` event.

```csharp
private void PubsDesktop_Load(object sender, EventArgs e)
        {
            this.LoadAppConfig();
            this.txt_CurrentUser.Text = this.appConfig.CurrentWebAppUser.UserName;
        }
```

The `LoadAppConfig` method sets a portion of the `BasicDAL.DbConfig` object related to the parameters of the Runtime UI environment in which the BasicDAL ORM will operate, specifically in the case of Wisej.NET.&#x20;

```csharp
private void LoadAppConfig()
        {
            this.appConfig.DbConfig.RuntimeUI = BasicDAL.RuntimeUI.Wisej;
            this.appConfig.DbConfig.RedirectErrorsNotificationTo = new BasicDALWisejControls.BasicDALMessageBox();
            this.appConfig.DbConfig.Provider = BasicDAL.Providers.SqlServer;
            if (!this.appConfig.ReadWebConfigAppConfig())
            {
                MessageBox.Show("Error reading Web.Config parameters!");
                Application.Exit();
            }
        }
```

This enables interactive handling of error situations and their corresponding messages, which will be redirected to the client's browser using a native Wisej.NET `MessageBox` object passed through the `RedirectErrorsNotificationTo` property.&#x20;

```csharp
this.appConfig.DbConfig.RedirectErrorsNotificationTo = new BasicDALWisejControls.BasicDALMessageBox();
```

Additionally, the type of database server being used, Microsoft SQL Server, is set via the `Providers` property.

```csharp
this.appConfig.DbConfig.Provider = BasicDAL.Providers.SqlServer;
```

The configuration operation continues by reading the data present in the "Web.Config" file using the `ReadWebConfigAppConfig` method.&#x20;

```csharp
if (!this.appConfig.ReadWebConfigAppConfig())
            {
                MessageBox.Show("Error reading Web.Config parameters!");
                Application.Exit();
            }
```

Once this is completed, the TextBox containing the current user's name is populated, and the application waits for the user to select an item from the `mnuBar1` menu. The selection is handled by the `ManageMenuBar` method.

```csharp
ManageMenuBar(e.MenuItem.Name);
```

`ManageMenuBar()` receives the name of the selected menu item and, through a switch block, activates a new instance of the chosen Form. A utility function from the BasicDAL module is invoked, which implements Wisej.NET user controls (BasicDALWisejControls). Then, the configuration is passed, and finally, the `Show()` method is called.

```csharp
 private void ManageMenuBar(string MenuItemName)
        {
            switch (MenuItemName)
            {
                case "mnuFile_Exit":
                    break;

                case "mnuDiscounts" :
                    frmDiscounts frmDiscounts = new frmDiscounts();
                    BasicDALWisejControls.Utilities.SetFixedWindowStyles(frmDiscounts);
                    frmDiscounts.appConfig = this.appConfig;
                    frmDiscounts.Show();
                    break;

                case "mnuAuthors" :
                    frmAuthors frmAuthors = new frmAuthors();
                    BasicDALWisejControls.Utilities.SetFixedWindowStyles(frmAuthors);
                    frmAuthors.appConfig = this.appConfig;
                    frmAuthors.Show();
                    break;
                    
                //more cases- one for each form type
                default:
                    break;
            }
        }
```

## 4.7 The application model and data management

As mentioned in [section 4.2](#4.2-the-structure-of-the-application), the application architecture follows a very simple architectural pattern, typical of the world of simple Windows Forms, using a Model-View approach where the View also implements some business logic controller functions. In the real world, this approach is usable for moderately complex applications when data management is delegated to an ORM (Object-Relational Mapping) that can handle almost all aspects of interaction with the database. In our case, the ORM BasicDAL is capable of performing this task, completely abstracting the database management from the developer and allowing the complete avoidance (if desired) of using SQL language within the application.

### 4.7.1 BasicDAL in summary

The following is a simple explanation of BasicDAL's structure in terms of constituent objects and main functionalities. BasicDAL is an ORM that, in addition to ORM functions, also incorporates data binding functions to presentation objects with properties that can be displayed in a UI. Its default operating pattern is that of the Active Record; however, in situations where the memory allocated by the record set is considered excessive or when it is not necessary to keep active records in memory, it is possible to switch to DataReader mode with a forward-only cursor.

The main objects are:

| Role/Function                                                                                                                                                        | Object Class           |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| Database Connection Context                                                                                                                                          | BasicDAL.DbConfig      |
| Mapping of Database Objects (Tables, Views, Stored Procedures, Functions, SQL Statements) and Their Interaction (Read, Update, Insert, Delete, Select, Presentation) | BasicDAL.DbObject      |
| Mapping Single Column                                                                                                                                                | BasicDAL.DbColumn      |
| Mapping Single Parameter                                                                                                                                             | BasicDAL.DbParameter   |
| Binding Between Column Values and Presentation Objects                                                                                                               | BasicDAL.BoundControls |
| Creation of Query Language Statements Specific to the Database Provider Used by the Database Connection Context                                                      | BasicDAL.DbFilters     |

{% hint style="info" %}
BasicDAL.DbObject requires an association with a BasicDAL.DbConfig to access the data
{% endhint %}

Hierarchy of main object compositions:

<table><thead><tr><th width="220.33333333333331">Object</th><th width="265">Contains Collection of Objects</th><th>Name of Object Collection</th></tr></thead><tbody><tr><td>BasicDAL.DbObject</td><td>BasicDAL.DbColumn</td><td>BasicDAL.DbColumns</td></tr><tr><td>BasicDAL.DbObject</td><td>BasicDAL.DbParameter</td><td>BasicDAL.DbParameters</td></tr><tr><td>BasicDAL.DbObject</td><td>BasicDAL.DbFilters</td><td>BasicDAL.DbFIltersGroup</td></tr><tr><td>BasicDAL.DbColumn</td><td>BasicDAL.BoundControl</td><td>BasicDAL.BoundControls</td></tr></tbody></table>

### 4.7.2 The Model

In our application, the model is represented by the file "BasicDALPubsModel.cs." The model is made up of a set of objects, derived from the base class `BasicDAL.DbObject`**:**

* DbT\_dbo\_authors
* DbT\_dbo\_discounts
* DbT\_dbo\_employee
* DbT\_dbo\_jobs
* DbT\_dbo\_pub\_info
* DbT\_dbo\_publishers
* DbT\_dbo\_roysched
* DbT\_dbo\_salesmaster
* DbT\_dbo\_salesdetails
* DbT\_dbo\_stores
* DbT\_dbo\_titleauthor
* DbT\_dbo\_titles
* DbV\_dbo\_titleview
* DbSP\_dbo\_byroyalty
* DbSP\_dbo\_reptq1
* DbSP\_dbo\_reptq2
* DbSP\_dbo\_reptq3
* DbV\_dbo\_titles\_publishers
* DbV\_dbo\_AuthorsFullname
* DbV\_dbo\_pub\_info\_publisher

The purpose of these objects is to map Database objects (Tables, Views, Stored Procedures, Functions).  Let's take a look at the class `DbT_dbo_authors`, which is related to a Table.

```csharp
public class DbT_dbo_authors : BasicDAL.DbObject
{
    private BasicDAL.DbColumn _DbC_au_id = new BasicDAL.DbColumn("[au_id]", System.Data.DbType.String, true, "");
    private BasicDAL.DbColumn _DbC_au_lname = new BasicDAL.DbColumn("[au_lname]", System.Data.DbType.String, false, "LAST");
    private BasicDAL.DbColumn _DbC_au_fname = new BasicDAL.DbColumn("[au_fname]", System.Data.DbType.String, false, "FIRST");
    private BasicDAL.DbColumn _DbC_phone = new BasicDAL.DbColumn("[phone]", System.Data.DbType.String, false, "PHONE");
    private BasicDAL.DbColumn _DbC_address = new BasicDAL.DbColumn("[address]", System.Data.DbType.String, false, "ADDRESS");
    private BasicDAL.DbColumn _DbC_city = new BasicDAL.DbColumn("[city]", System.Data.DbType.String, false, "CITY");
    private BasicDAL.DbColumn _DbC_state = new BasicDAL.DbColumn("[state]", System.Data.DbType.String, false, "ST");
    private BasicDAL.DbColumn _DbC_zip = new BasicDAL.DbColumn("[zip]", System.Data.DbType.String, false, "ZIP");
    private BasicDAL.DbColumn _DbC_contract = new BasicDAL.DbColumn("[contract]", System.Data.DbType.Boolean, false, false);
    private BasicDAL.DbColumn _DbC_email = new BasicDAL.DbColumn("[email]", System.Data.DbType.String, false, "EMAIL");
    
    public BasicDAL.DbColumn DbC_au_id
    {
        get { return _DbC_au_id; }
        set { _DbC_au_id = value; }
    }

    public BasicDAL.DbColumn DbC_au_lname
    {
        get { return _DbC_au_lname; }
        set { _DbC_au_lname = value; }
    }

    public BasicDAL.DbColumn DbC_au_fname
    {
        get { return _DbC_au_fname; }
        set { _DbC_au_fname = value; }
    }

    public BasicDAL.DbColumn DbC_phone
    {
        get { return _DbC_phone; }
        set { _DbC_phone = value; }
    }

    public BasicDAL.DbColumn DbC_address
    {
        get { return _DbC_address; }
        set { _DbC_address = value; }
    }

    public BasicDAL.DbColumn DbC_city
    {
        get { return _DbC_city; }
        set { _DbC_city = value; }
    }

    public BasicDAL.DbColumn DbC_state
    {
        get { return _DbC_state; }
        set { _DbC_state = value; }
    }

    public BasicDAL.DbColumn DbC_zip
    {
        get { return _DbC_zip; }
        set { _DbC_zip = value; }
    }

    public BasicDAL.DbColumn DbC_contract
    {
        get { return _DbC_contract; }
        set { _DbC_contract = value; }
    }

    public BasicDAL.DbColumn DbC_email
    {
        get { return _DbC_email; }
        set { _DbC_email = value; }
    }

    public DbT_dbo_authors()
    {
        this.InterfaceMode = BasicDAL.InterfaceModeEnum.Private;
        this.DbObjectType = BasicDAL.DbObjectTypeEnum.Table;
        this.DbTableName =  "authors";
    }
}
```

The `DbT_dbo_authors` class derives from the base class `BasicDAL.DbObject` and maps the "author" table. Each column is mapped with a `BasicDAL.DbColumn` class field, which uses a part of the table name as its name. The constructor of `BasicDAL.DbColumn` expects the following mandatory parameters: column name, column data type, primary key membership, default value.\
\
In the previous code sample of the `DbT_dbo_authors` class, the `DbColumn` fields are declared as private and associated with a public property to access the customization of the Get and Set methods. If there is no need to access these methods, the class could be composed as follows:

```csharp
public class DbT_dbo_authors_public : BasicDAL.DbObject
{
    public BasicDAL.DbColumn _DbC_au_id = new BasicDAL.DbColumn("[au_id]", System.Data.DbType.String, true, "");
    public BasicDAL.DbColumn _DbC_au_lname = new BasicDAL.DbColumn("[au_lname]", System.Data.DbType.String, false, "LAST");
    public BasicDAL.DbColumn _DbC_au_fname = new BasicDAL.DbColumn("[au_fname]", System.Data.DbType.String, false, "FIRST");
    public BasicDAL.DbColumn _DbC_phone = new BasicDAL.DbColumn("[phone]", System.Data.DbType.String, false, "PHONE");
    public BasicDAL.DbColumn _DbC_address = new BasicDAL.DbColumn("[address]", System.Data.DbType.String, false, "ADDRESS");
    public BasicDAL.DbColumn _DbC_city = new BasicDAL.DbColumn("[city]", System.Data.DbType.String, false, "CITY");
    public BasicDAL.DbColumn _DbC_state = new BasicDAL.DbColumn("[state]", System.Data.DbType.String, false, "ST");
    public BasicDAL.DbColumn _DbC_zip = new BasicDAL.DbColumn("[zip]", System.Data.DbType.String, false, "ZIP");
    public BasicDAL.DbColumn _DbC_contract = new BasicDAL.DbColumn("[contract]", System.Data.DbType.Boolean, false, false);
    public BasicDAL.DbColumn _DbC_email = new BasicDAL.DbColumn("[email]", System.Data.DbType.String, false, "EMAIL");
    
    public DbT_dbo_authors_public()
    {
        this.InterfaceMode = BasicDAL.InterfaceModeEnum.Private;
        this.DbObjectType = BasicDAL.DbObjectTypeEnum.Table;
        this.DbTableName =  "authors";
    }
}
    
```

The `BasicDAL.DbObject` and `BasicDAL.DbColumn` objects have dozens and dozens of properties, fields, methods, and events. The complete documentation is available on the GitHub website at <https://github.com/gdelgiovine>.

BasicDAL also provides a tool for generating `BasicDAL.DbObject` classes. The tool is called BasicDAL ClassBuilder and is available on the GitHub website.

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2F8DEZ7B5EHmqv4MJcKL0M%2FbasicDAL.png?alt=media&#x26;token=e32f71f7-aed8-4ab3-a5a2-d21dbf78ba73" alt=""><figcaption></figcaption></figure>

## 4.8 The forms (`Wisej.Web.Form`)

In the application, forms are characterized by the suffix "frm" in their names and all share the same basic structure, derived from a template. Therefore, we will only analyze some forms that implement interesting functionality. To do this, we will examine `frmSales` and `frmAuthors`, which offer some interesting insights.

### 4.8.1 The form `fmSales`

In Wisej.NET, forms are preferably designed using a drawing surface (designer) without the need to manually write HTML or CSHTML code, which is necessary for ASP.NET MVC, ASP.NET Core, Angular, or React applications. This is the designer for the `frmSales` form:

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2FPhVHSof711GvrPldXVE3%2FfrmSales.png?alt=media&#x26;token=7c3cb411-1d50-4db7-8d23-398f05e63194" alt=""><figcaption><p>frmSales as viiewed in the Wisej.NET deisgner</p></figcaption></figure>

As seen, the form in the design phase closely resembles its runtime appearance. &#x20;

The files that make up the form look like this in the "Solution Explorer." Note that this is the same structure that we saw in [section 3.4.2](https://www.learnwisej.net/drawing-surfaces-objects-and-widgets#3.4.2-code-generated-by-the-designer)[ ](https://www.learnwisej.net/drawing-surfaces-objects-and-widgets#3.4.2-code-generated-by-the-designer)for the "Page1.cs" file.

<figure><img src="https://3188166459-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FYZg1RIEjJ5H42ECDnFfU%2Fuploads%2Fpq0VAVeB19Zez1xiw536%2FfrmSales2.png?alt=media&#x26;token=6a7a7e64-3703-4670-b2a7-4b0b315a1b08" alt=""><figcaption></figcaption></figure>

### 4.8.2 The code of `frmSales`

The vast majority of the code found in the two files implementing the `frmSales` class, namely "frmSales.cs" and "frmSales.Designer.cs", is located in the latter file. The code in the "frmSale.Designer.cs" file is typically generated and managed automatically by the Wisej.NET designer. The code present in the "frmSales.cs" file is kept to a minimum and primarily consists of declarations of objects related to the BasicDAL ORM and UI object event handlers. Due to the use of a simplified version of the Model-ViewController pattern, the frmSales.cs file also contains fragments of business logic. It's important to emphasize that Wisej.NET does not impose any specific architectural pattern.

{% hint style="info" %}
This section contains relevant code snippets from frmSales.cs, but does not contain frmSales.cs in its entirety. The full contents of the frmSales.cs class can be found on github here: <https://github.com/JulieHirt/WisejPubsDemoApp/blob/main/WisejPubsDemoApp/WisejPubsDemoApp/frmSales.cs>
{% endhint %}

#### 4.8.2.1 frmSales.cs - fields

Let's begin by looking at the fields declared in `frmSales`. We'll talk about what values they are assigned.

```csharp
//the fields of FrmSales
public partial class frmSales : Form
    {
        public AppConfig appConfig = new AppConfig();
        private BasicDAL.DbConfig DbConfig = new BasicDAL.DbConfig();
        private BasicDALWisejControls.BasicDALMessageBox BasicDALMessageBox = new BasicDALWisejControls.BasicDALMessageBox();
        private DbT_dbo_salesdetails dbT_Dbo_SalesDetails = new DbT_dbo_salesdetails();
        private DbT_dbo_titles dbT_Dbo_Titles = new DbT_dbo_titles();
        private DbT_dbo_stores dbT_Dbo_Stores = new DbT_dbo_stores();
        private DbT_dbo_salesmaster dbT_Dbo_SalesMaster = new DbT_dbo_salesmaster();
        private BasicDAL.DbLookUp dbl_stor_id = new BasicDAL.DbLookUp();
        private bool FormInit = false;
        private bool DataNavigatorHandlerInitialized = false;
        
        //...
        
    }
```

Looking specifically at the first two fields in frmSales, `appConfig` and `DbConfig`, we see the following:

```csharp
// frmSales.cs
public AppConfig appConfig = new AppConfig();
private BasicDAL.DbConfig DbConfig = new BasicDAL.DbConfig();
```

`appConfig` receives the complete application configuration from the `PubDesktop` object:

```csharp
// PubsDesktop.cs
frmSales frmSales = new frmSales();
//...
frmSales.appConfig = this.appConfig;
frmSales.Show();
```

`DbConfig` is populated with a copy of the BasicDAL.DbConfig database context present in the `AppConfig` object:

```csharp
//code from InitDataContext() in frmSales.cs
this.DbConfig = this.appConfig.DbConfig.Clone();
```

Next, let's look at the fields `dbT_dbo_salesdetails`, `dbT_dbo_titles`, `dbT_dbo_stores`, and `dbT_dbo_salesmaster`:

<pre class="language-csharp"><code class="lang-csharp">// frmSales.cs
<strong>private BasicDALWisejControls.BasicDALMessageBox BasicDALMessageBox = new BasicDALWisejControls.BasicDALMessageBox();
</strong>private DbT_dbo_salesdetails dbT_Dbo_SalesDetails = new DbT_dbo_salesdetails();
private DbT_dbo_titles dbT_Dbo_Titles = new DbT_dbo_titles();
private DbT_dbo_stores dbT_Dbo_Stores = new DbT_dbo_stores();
private DbT_dbo_salesmaster dbT_Dbo_SalesMaster = new DbT_dbo_salesmaster();
</code></pre>

The classes `DbT_dbo_salesdetails`, `DbT_dbo_titles`, `DbT_dbo_stores`, and `DbT_dbo_salesmaster` are declared in "BasicDALPubsModel.cs" ([see section 4.7.2](#4.7.2-the-model)). All of these classes derive from `BasicDAL.DbObject`. They are the entities that map the corresponding Table objects in the Pubs database. (For example, `DbT_dbo_titles` maps to the 'titles' table).

Next, observe the declaration and instantiation of `dbl_stor_id`**,** which is a `BasicDAL.DbLookUp` object:&#x20;

```csharp
// frmSales.cs
private BasicDAL.DbLookUp dbl_stor_id = new BasicDAL.DbLookUp();
```

This object implements a LookUp function towards a `BasicDAL.DbObject` by adding `BasicDAL.DbFilters` to its `BasicDAL.DbFilters` collection and associating UI controls for data binding through its `BasicDAL.BoundControls` collection. <br>

<pre class="language-csharp"><code class="lang-csharp">// InitDataContext() in frmSales.cs
// Declare of DbLookUp 
this.dbl_stor_id.DbObject = this.dbT_Dbo_Stores;
this.dbl_stor_id.Filters.AddBoundControl(this.dbT_Dbo_Stores.DbC_stor_id, 
    BasicDAL.ComparisionOperator.Equal,
<strong>    this.txt_stor_id,
</strong>    "text");
this.dbl_stor_id.BoundControls.Add(this.dbT_Dbo_Stores.DbC_stor_name,this.lbl_stor_name, "text");
</code></pre>

{% hint style="info" %}
Note for Domain-Driven Design (DDD) purists: \
\
BasicDAL also allows the use of Plain Old Class Objects (POCO) as the basis for all presentation and business logic. This enables an additional level of code abstraction, gradually decoupling it from the specific ORM. This is made possible through the concurrent use of an attribute class for defining POCO classes that describe application entities (components and aggregates) and the presence of the .ToList() and .FromList() methods of the BasicDAL.DbObject. These two methods allow mapping the data set of the BasicDAL.DbObject entity to a POCO List, whose properties are decorated with BasicDAL attributes.
{% endhint %}

#### 4.8.2.2 frmSales.cs - Code that runs when the form is initially loaded

\
The `InitDataNavigatorHandler()` method is responsible for creating and associating event handlers for the `BasicDALWisejControl.DataNavigator` object used in the form.

```csharp
//frmSales.cs
private void InitDataNavigatorHandler()
        {
            // Declare Events Handlers for DataNavigator
            if (DataNavigatorHandlerInitialized == true)
            {
                return;
            }
            this.dataNavigator1.eAddNew -= new BasicDALWisejControls.DataNavigator.eAddNewEventHandler(this.dataNavigator1_eAddNew);
            this.dataNavigator1.eAddNew += new BasicDALWisejControls.DataNavigator.eAddNewEventHandler(this.dataNavigator1_eAddNew);
            this.dataNavigator1.ePrint -= new BasicDALWisejControls.DataNavigator.ePrintEventHandler(this.dataNavigator1_ePrint);
            this.dataNavigator1.ePrint += new BasicDALWisejControls.DataNavigator.ePrintEventHandler(this.dataNavigator1_ePrint);
            this.dataNavigator1.eDelete -= new BasicDALWisejControls.DataNavigator.eDeleteEventHandler(this.dataNavigator1_eDelete);
            this.dataNavigator1.eDelete += new BasicDALWisejControls.DataNavigator.eDeleteEventHandler(this.dataNavigator1_eDelete);
            this.dataNavigator1.eRefresh -= new BasicDALWisejControls.DataNavigator.eRefreshEventHandler(this.dataNavigator1_eRefresh);
            this.dataNavigator1.eRefresh += new BasicDALWisejControls.DataNavigator.eRefreshEventHandler(this.dataNavigator1_eRefresh);
            this.dataNavigator1.eClose -= new BasicDALWisejControls.DataNavigator.eCloseEventHandler(this.dataNavigator1_eClose);
            this.dataNavigator1.eClose += new BasicDALWisejControls.DataNavigator.eCloseEventHandler(this.dataNavigator1_eClose);
            this.dataNavigator1.eFind -= new BasicDALWisejControls.DataNavigator.eFindEventHandler(this.dataNavigator1_eFind);
            this.dataNavigator1.eFind += new BasicDALWisejControls.DataNavigator.eFindEventHandler(this.dataNavigator1_eFind);
            this.dataNavigator1.eSave -= new BasicDALWisejControls.DataNavigator.eSaveEventHandler(this.dataNavigator1_eSave);
            this.dataNavigator1.eSave += new BasicDALWisejControls.DataNavigator.eSaveEventHandler(this.dataNavigator1_eSave);
            this.dataNavigator1.eMovePrevious -= new BasicDALWisejControls.DataNavigator.eMovePreviousEventHandler(this.dataNavigator1_eMovePrevious);
            this.dataNavigator1.eMovePrevious += new BasicDALWisejControls.DataNavigator.eMovePreviousEventHandler(this.dataNavigator1_eMovePrevious);
            this.dataNavigator1.eMoveFirst -= new BasicDALWisejControls.DataNavigator.eMoveFirstEventHandler(this.dataNavigator1_eMoveFirst);
            this.dataNavigator1.eMoveFirst += new BasicDALWisejControls.DataNavigator.eMoveFirstEventHandler(this.dataNavigator1_eMoveFirst);
            this.dataNavigator1.eMoveLast -= new BasicDALWisejControls.DataNavigator.eMoveLastEventHandler(this.dataNavigator1_eMoveLast);
            this.dataNavigator1.eMoveLast += new BasicDALWisejControls.DataNavigator.eMoveLastEventHandler(this.dataNavigator1_eMoveLast);
            this.dataNavigator1.eMoveNext -= new BasicDALWisejControls.DataNavigator.eMoveNextEventHandler(this.dataNavigator1_eMoveNext);
            this.dataNavigator1.eMoveNext += new BasicDALWisejControls.DataNavigator.eMoveNextEventHandler(this.dataNavigator1_eMoveNext);
            this.dataNavigator1.eUndo -= new BasicDALWisejControls.DataNavigator.eUndoEventHandler(this.dataNavigator1_eUndo);
            this.dataNavigator1.eUndo += new BasicDALWisejControls.DataNavigator.eUndoEventHandler(this.dataNavigator1_eUndo);

            DataNavigatorHandlerInitialized = true;
        }
```

The `frmSales_Load()` event invokes the `InitDataContext()` method. Therefore, the `InitDataContext()` method runs when the `frmSales` form is initially loaded.

```csharp
//frmSales.cs
private void InitDataContext(bool ForceFormInit = false)
        {
            if (ForceFormInit == true)
            {
                FormInit = false;
            }
            if (this.FormInit)
            {
                return;
            }
     
            this.DbConfig = this.appConfig.DbConfig.Clone();
            this.DbConfig.RedirectErrorsNotificationTo = this.BasicDALMessageBox;
            this.dbT_Dbo_SalesDetails.Init(this.DbConfig);
            this.dbT_Dbo_Stores.Init(this.DbConfig);
            this.dbT_Dbo_Titles.Init(this.DbConfig);
            this.dbT_Dbo_SalesMaster.Init(this.DbConfig);
            this.dbT_Dbo_SalesMaster.DataBinding = BasicDAL.DataBoundControlsBehaviour.BasicDALDataBinding;
            //binding for BasicDAL DbObject columns into UI objects.
            this.dbT_Dbo_SalesMaster.DbC_ord_date.BoundControls.Add(this.dtp_ord_date, "value");
            this.dbT_Dbo_SalesMaster.DbC_ord_num.BoundControls.Add(this.txt_ord_num, "text");
            this.dbT_Dbo_SalesMaster.DbC_stor_id.BoundControls.Add(this.txt_stor_id, "text");
            this.dbT_Dbo_SalesMaster.DbC_stor_ord_date.BoundControls.Add(this.dtp_stor_ord_date, "value");
            this.dbT_Dbo_SalesMaster.DbC_stor_ord_num.BoundControls.Add(this.txt_stor_ord_num, "text");
            this.dbT_Dbo_SalesMaster.DbC_payterms.BoundControls.Add(this.cmb_payterms, "text");
            // Declare of DbLookUp 
            this.dbl_stor_id.DbObject = this.dbT_Dbo_Stores;
            this.dbl_stor_id.Filters.AddBoundControl(this.dbT_Dbo_Stores.DbC_stor_id, 
                                                     BasicDAL.ComparisionOperator.Equal,
                                                     this.txt_stor_id,
                                                     "text");
            this.dbl_stor_id.BoundControls.Add(this.dbT_Dbo_Stores.DbC_stor_name,this.lbl_stor_name, "text");
            this.dataNavigator1.DbObject = this.dbT_Dbo_SalesMaster;
            this.dataNavigator1.ManageNavigation = false;
            this.dataNavigator1.DataGrid = this.dgv_SalesDetails;
            this.dataNavigator1.DataGridActive = false;
            this.dataNavigator1.DataGridListView = this.dgvList;
            this.dataNavigator1.ListViewColumns.Add(this.dbT_Dbo_SalesMaster.DbC_ord_num , "Order Number", "");
            this.dataNavigator1.ListViewColumns.Add(this.dbT_Dbo_SalesMaster.DbC_ord_date, "Order Date", "dd/MM/yyyy");
            this.dataNavigator1.ListViewColumns.Add(this.dbT_Dbo_SalesMaster.DbC_stor_id , "Store Id", "");
            this.dataNavigator1.DataNavigatorInit(true);
           
        }
```

The connection context to the local database `DbConfig` is cloned from the one present in the received configuration class. (`this.DbConfig = this.appConfig.DbConfig.Clone();`)This cloning operation allows for having a context separate from the one received, enabling independent transaction handling within your code without affecting operations on other objects not involved in the transaction. The use of connection context cloning is an additional option available to the developer.

Next, the message window used by the ORM is then redirected to report any unhandled exceptions to the user.

By using the .Init() method of the various DbObject entities that map database objects, they are associated with the specific BasicDAL.DbConfig connection context of the form. All BasicDAL.DbObject entities associated with the context are available in the BasicDAL.DbConfig.ManagedDbObjects collection.

By default, BasicDAL.DbObject objects do not perform data binding for the Value property of BasicDAL.DbColumn objects that map database columns. The binding mode is set/read through the `DataBinding` property, which can have these values:

<pre class="language-csharp"><code class="lang-csharp">// BasicDAL.cs
public enum DataBoundControlsBehaviour
{
    WindowsFormsDataBinding = 2,
    BasicDALDataBinding = 1,
<strong>    NoDataBinding = 0
</strong>}
</code></pre>

In our `frmSales` form, the only BasicDAL.DbObject object that requires data binding to multiple user interface controls is the instance `dbT_Dbo_SalesMaster` of the `DbT_dbo_salesmaster` class, which represents the sales master table. For each of the BasicDAL.DbColumn objects, their corresponding UI controls are added to their own BasicDAL.BoundControls collection with an indication of whether they are meant to be used for setting or reading the user-entered values. Data binding can be set to write-only to the control, read from the control, read from the control only during the creation of a new data row, or a combination of these values. The direction of data binding is managed by the BindingBehaviour property of the BoundControl object.

Here's an example:

```csharp
this.dbT_Dbo_SalesMaster.DbC_ord_num.BoundControls.Add(this.txt_ord_num, "text");
```

`this.txt_ord_num` refers to the control that contains the order number in the `frmSales` form. In this context, "text" is the name of the property from which values are read (using the control's property's getter to update `DbColumn.Value`) or to which values are written (using the control's property's setter with the value of the `DbColumn.Value` property).

Next, we proceed to populate the `dbl_stor_id` instance by associating it with the `dbT_Dbo_Stores` object, which is the DbObject representing the database object that we will use as a data source for performing a lookup. It is necessary to provide the value or values for filtering that will be entered by the user in various controls. This is done by creating a filter based on a `BoundControl`. In the `BoundControl`, you specify the BasicDAL.DbColumn of the table for the lookup query, the comparison operator, the UI control, and the name of the property of this control from which to retrieve the value.

```csharp
this.dbl_stor_id.Filters.AddBoundControl(this.dbT_Dbo_Stores.DbC_stor_id, 
                                                     BasicDAL.ComparisionOperator.Equal,
                                                     this.txt_stor_id,
                                                     "text");
```
