.Net Code Monkey RSS 2.0
 Thursday, October 30, 2008

Background:

Last night I was doing a little pre-project architecture-checking work, to make sure some ideas I have for my next project will work as anticipated. One part of the web application requires a user to open a popup dialog and edit a value displayed on the main form. There are clearly many solutions to doing this, including posting back the value when submitting, and reloading the parent form when the child form closes. My prefered choice is to acomplish the task in JavaScript.

So first lets create two web pages; Parent.htm and Child.htm.

The Parent Page

In the parent page we are going to add two controls; a pre-populated readonly text box and a button to edit the contents. We will add an "onclick" handler to the button to call a JavaScript method called "editContent()", and we'll add script tags into the head section to place our code. In a real world scenario the JavaScript code would probably be placed in a seperate file.

<html>
<head>
<script language="javascript" type="text/javascript"> <!-- --> </script>
</head>
<body> <form> <input type="text" name="txtEditValue" id="txtEditValue" value="Original content" readonly="readonly" > <input type="submit" name="btnEdit" id="btnEdit" value="Edit" onClick="editContent();" > </form> </body> </html>

In the script section we need to add some JavaScript to open the Child window. First we'll declare a global variable to hold a reference to the window in case we need it later (Possibly in a later article about Modal child forms which will use this code!).

var m_childWindow = null;

Now we wil create the "editContent()" method which will be called from the button "onClick" handler. For the moment the "editContent()" method just calls through to the "openWindow()" method. This may seem a bit of a waste of code, but my reason for it is for program flow code reading clarrity.  The edit button (btnEdit) calls the "editContent()" method, named as it relates directly to the action the user has performed. If I had plugged btnEdit's onclick into the "openWindow()" method it would not be so logical to follow program flow. I guess using this methodalogy a better name for the "editContent()" method would have been "btnEdit_OnClick()", but hell it is just an artical on my blog, not something going into productions, so why am I tying my self up in knots over this?

The "openWindow()" method just opens a new window and assignes a reference to it top our global variable. The first parameter is teh url for the child page, the second the window name, and the third contains the properties for the window; height, width, whether to display menu bar, etc.

function editContent()
{
    openWindow();
}

function openWindow()
{
    var newWin = null;
    newWin = window.open ('Child.htm', 'childWindow', 'menubar=0,resizable=0,status=1,width=350,height=250');
    m_childWindow = newWin;
}

We now need two methods to act as accessors for the text box value; one to get and one to set.

function getEditValue()
{
    var editTextBox;    
    editTextBox = document.getElementById("txtEditValue");
    return editTextBox.value;
}
function setEditValue(value)
{
    var editTextBox;    
    editTextBox = document.getElementById("txtEditValue");
    editTextBox.value = value;
}

The Child Page

Now we'll move on to creating the child page. This will also have two controls; a TextBox and a Button. The text box will be used by the user to edit the value, and the button to submit changes back to the parent form.

<html>
<head>
<script language="javascript" type="text/javascript">
<!--

-->
</script>
</head>
<body onload="bodyOnLoad()"  >
    <form >
        <input type="text" name="txtEditValue" id="txtEditValue">
        <input type="submit" name="btnSubmit" id="btnSubmit" value="Save" onClick="submitForm();" >
    </form>
</body>
</html>

You will hopefully have noticed that the body onload event calls a JavaScript method called "bodyOnLoad()", so we had better create this first. The "bodyOnLoad()" method purely calls the "populateTextBox()" method via JavaScript's own "setTimeout()" method, with a quarter second delay.

function bodyOnLoad()
{
    setTimeout ( "populateTextBox()", 250 );
}

I have used the "setTimeout()" method purely becuase in tests with the Opera browser the window.opener property is not populated in time for aour call to access it in the "populateTextBox()" method. However, in Internet Explorer and Firefox, this was not the case. I presume the reason for needing this delay is to allow Opera to finish building the DOM tree. (Any one have any info on this?)

function populateTextBox()
{
    var editTextBox = null;    
    editTextBox = document.getElementById('txtEditValue');
    
    var windowOpener = null;
    windowOpener = window.opener;
    
    if(windowOpener==undefined)
    {
        alert('No opener');
    }
    else
    {
        if(editTextBox != null)
        {
            editTextBox.value = windowOpener.getEditValue();
        }
    }
}

The "populateTextBox()" method declares two variables, one to hold a reference to the TextBox and the other a reference to the window.opener object. In this case we are assuming that the window.opener will always be our Parent.htm page and will have the "getEditValue()" method available. Obviously in a real world example this should be guarded against. So in essence once the page is loaded, the text box is populated by reading the value returned from the window.opener's "getEditValue()" method.

Editing and saving the value.

Once the value is in the text box the user is free to edit the value, and can then click the save button to call a method to send the value back to the parent form and close the child window.

function submitForm()
{
    var windowOpener = null;
    windowOpener = window.opener;

    var editTextBox = null;    
    editTextBox = document.getElementById("txtEditValue");

    windowOpener.setEditValue( editTextBox.value);
    window.close();
}

So the "submitForm()" method declares two variables to hold references to the TextBox and window opener again, and uses the window.opener's "setEditValue(value)" method to pass back the changed value to the parent form. Then the child form is closed.

Summary

So there you have it a simple JavaScript based solution for editing a value of a parent form from within a child form. My intention for my future project is to embed a RichTextEdit in the child form, and only display the finished HTML in an IFRAME on the parent form. Hopefully this will help someone who is looking to do a similar thing!

Please note through out this example error trapping and defensive coding has been ommitted for clarrity. it would also be preferable for the child page to be a modal window. I will hopefully look into a solution for that a little later.

Thursday, October 30, 2008 7:00:05 AM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
Html | JavaScript
 Sunday, October 26, 2008

It’s been quite a while since I have written anything (yes I really need to finish the last article!), but this morning I came across a problem where I need to provide separate database connections for different website visitors who will be using the same underlying .Net TableAdapters. So I thought I’d write about it.

 

Background:

I have set up my Sql Server 2005 database to have four roles; DbAdmin, WebAdmin, ProductSeller, ProductBuyer. Each of these roles has been given different levels of read / write / execute permission on the various database objects. It is my intention to let the built in .Net 2.0 Membership and Roles objects handle assigning of roles (mirroring the four database roles) to all of the website visitors.

 

As far as I know to make use the database roles properly I will need four separate database logins and database users, and hence in my application I will need four different connection strings.

 

Problem:

The problem is that I could not see any exposed properties of a table adapter to allow the connection to be changed dynamically.

 

My solution:

My solution is to set up the application to have four connection strings for the four database logins, and create an overridden constructor for each TableAdapter that requires role specific database connections.

 

Setting up the database

 

For the purpose of this example I have created the following database logins.

Login

Login Name

Password

Database administrator

MyWesite_DbAdministrator

da1

Website administrator

MyWesite_WebAdministrator

wa1

Product Seller

MyWesite_ProductSeller

ps1

Product Buyer

MyWesite_ProductBuyer

pb1

 

The database roles I have created are as follows.

Role name

Description

DatabaseAdmin

The role assigned to the database administrator

WebsiteAdmin

The role assigned to the web site administrator

ProductSeller

The role assigned to users who can list a product on the site.

ProductBuyer

The role given to public users of the site

 

 

Application Architecture Overview:

The application is written in a layered architecture with the web front end having visibility of the Interfaces layer and the Services layer, and the Services layer having visibility of the Interfaces layer, the Business Entities layer, and the Data Access layer. The data access layer contains all the typed datasets and any other database related objects.

 

Connection strings:

The four connection strings are entered into the Settings tab of the Properties page of the DataAccess project.

 

Name

Type

Scope

Value

> 

DatabaseAdminCon…

(Connection…

Application

Data Source=…

 

WebsiteAdminConn…

(Connection…

Application

Data Source=…

 

ProductSellerConne…

(Connection…

Application

Data Source=…

 

ProductBuyerConne…

(Connection…

Application

Data Source=…

*

 

 

 

 

 

Creating the connection

As we need to provide a role specific connection to the table adapter we need an object that can create and return a connection.

using System;
using System.Data.SqlClient;
using ConnectionStrings = MyProject.DataAccess.Properties.Settings;

namespace MyProject.DataAccess
{
    public class DatabaseConnection
    {
        /// <summary>
        /// Returns a connection for use with the role name passed in
        /// </summary>
        /// <param name="roleName">
        /// Represents the name of the role to get connection string for.
        /// </param>
        /// <returns>
        /// Returns a Sql Server connection.
        /// </returns>
        public SqlConnection GetConnectionForRole(string roleName)
        {
            SqlConnection connection = null;
            string connectionString = string.Empty;

                connectionString = GetConnectionStringForRole(roleName);
                connection = new SqlConnection(connectionString);
            return connection;

        }

        /// <summary>
        /// Returns a connection string based on the passed in rolename.
        /// </summary>
        /// <param name="roleName">
        /// Represents the name of the role to get connection string for.
        /// </param>
        /// <returns></returns>
        private string GetConnectionStringForRole(string roleName)
        {
            string connectionString = string.Empty;            

            switch (roleName)
            {
                case "DatabaseAdmin":
                    connectionString = ConnectionStrings.Default.DatabaseAdminConnectionString;
                    break;

                case "WebsiteAdmin":
                    connectionString = ConnectionStrings.Default.WebsiteAdminConnectionString;
                    break;

                case "ProductSeller":
                    connectionString = ConnectionStrings.Default.ProductSellerConnectionString;
                    break;

                case "ProductBuyer":
                    connectionString = ConnectionStrings.Default.ProductBuyerConnectionString;
                    break;

                default:
                    throw new ArgumentOutOfRangeException("roleName", "Unknown role name encountered.");
            }

            return connectionString;
        }

    }
}

 

Default Constructor:

Next we need to look at the TableAdapter and create a constructor that overrides the default non parametricised constructor. The default constructor for our table adapter looks like this.

[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public MyTableAdapter() {
    this.ClearBeforeFill = true;
}

 

New Constructor:

To override this constructor we are going to take advantage of .Net 2.0’s partial classes. Using these we do not have to modify the auto-generated code of the dataset, and neither do we have to attempt to create a class that inherits from the dataset.

using System;
using System.Data.SqlClient;

namespace MyProject.DataAccess.ApplicationDataSetTableAdapters
{
    public partial class MyTableAdapter: System.ComponentModel.Component
    {
        /// <summary>
        /// Used to provide an overridden constructor for the MyTableAdapter
        /// allowing a connection to be passed in.
        /// </summary>
        /// <param name="sqlConnection"></param>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public MyTableAdapter (SqlConnection sqlConnection)
        {
            this.ClearBeforeFill = true;
            this.Connection = sqlConnection;
        }
    }
}

 

We take care to set the connection via the “Connection” property rather than just setting the _connection fields as the auto-generated "Connection" property ensure all adapter commands get the correct connection assigned to them, see below.

[System.Diagnostics.DebuggerNonUserCodeAttribute()]
 internal System.Data.SqlClient.SqlConnection Connection {
     get {
         if ((this._connection == null)) {
             this.InitConnection();
         }
         return this._connection;
     }
     set {
         this._connection = value;
         if ((this.Adapter.InsertCommand != null)) {
             this.Adapter.InsertCommand.Connection = value;
         }
         if ((this.Adapter.DeleteCommand != null)) {
             this.Adapter.DeleteCommand.Connection = value;
         }
         if ((this.Adapter.UpdateCommand != null)) {
             this.Adapter.UpdateCommand.Connection = value;
         }
         for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
             if ((this.CommandCollection[i] != null)) {
                 ((System.Data.SqlClient.SqlCommand)(this.CommandCollection[i])).Connection = value;
             }
         }
     }
 }

 

Initialising the TableAdapter

So now the code for accessing the adapter should look something like this.

/// <summary>
 /// Used to add an object that implements the IMyItem interface to the database.
 /// </summary>
 /// <param name="product">
 /// Represents the object implementing the IMyItem interface to add to the database.
 /// </param>
 void IMyItem.AddToDatabase(IMyItem product)
 {
     ApplicationAdapters.MyTableAdapter myTableAdapter = null;
     SqlConnection connection = null;
     try
     {
         connection = SqlServerConnectionService.GetConnectionForRole(RoleName);
         myTableAdapter = new ApplicationAdapters. MyTableAdapter (connection);
         MyTableAdapter.Add(product.Id, product.Name);
     }
     catch (Exception ex)
     {
         throw ex;
     }
     finally
     {
         SqlServerConnectionService.CloseConnection(connection);
         connection.Dispose();
         myTableAdapter.Dispose();
     }
 }

 

Connection Handling:

This code still allows the adapter to open and close the connection as necessary, we have just provided the connection we want. This approach has allowed me to ensure that a user logged in as a ProductBuyer should not have the permission to call procedures they shouldn’t even if I end up with a bug in the website code that allows a non authorised user to reach an administration page with add / update / delete functions.

 

As always your opinions and comments on this subject or the approach taken to overcome the problem are most welcome. I hope some one may find this useful.

 

Foot Note:

Some error handling in code has been omitted for sake of clarity

 

Sunday, October 26, 2008 3:34:07 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | Asp.Net | C# | Sql Server | Connection Strings | Database
 Saturday, April 12, 2008

I'm sure many of you are aware that you can override the connection string settings in your DataAccess layer of your web application with connection string settings in your Web.Config. We found this out recently and found it very useful in an intranet application at work recently. However this week one of the other developers required that he could override a setting the BusinessEntity layer of his application from the App.Config in the console layer.

A quick chat with Mr Google didn't turn up a solution for this, so with this in mind all three of us quickly tried to return a working solution. I'm going to try to give an example of what we did, incase it something others may find of use. First we create a solution with two class library projects within it. The first will simulate the DataAccess layer and the second will simulate the BusinessEntity layer in an application. In the BusinessEntity project we will create a reference to the DataAccess project.

Starting with the DataAccess project we will add an App.Config file by creating a setting called "MySetting" in the Settings tab of the project Properties. The setting scope will be set to Application.

This creates a new sectionGroup called applicationSettings and a new section in the App.Config file and places the new setting in their too.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <sectionGroup name="applicationSettings" 
type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="Playground.ConfigurationOverride.DataAccess.Properties.Settings"
type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" /> </sectionGroup> </configSections> <applicationSettings> <Playground.ConfigurationOverride.DataAccess.Properties.Settings> <setting name="MySetting" serializeAs="String"> <value>Setting in DataAccess</value> </setting> </Playground.ConfigurationOverride.DataAccess.Properties.Settings> </applicationSettings> </configuration>

Next we will add a simple class to the DataAccess project with a single static method that will return the value of the setting we have just created.

using System;

namespace Playground.ConfigurationOverride.DataAccess
{
    public static class SettingsHelper
    {
        public static string GetMySetting()
        {
            return Properties.Settings.Default.MySetting;
        }
    }
}

Next we will create anothe simple class, SettingsGetter, in the but in the BusinessEntity layer this time. It will just return the value returned from the SettingsHelper class in the DataAccess layer.

using System;

namespace Playground.ConfigurationOverride.BusinessEntity
{
    public static class SettingsGetter
    {
        public static string GetDataAccessSettingValue()
        {
            return DataAccess.SettingsHelper.GetMySetting();
        }
    }
}
Next we need to create a presentation layer. So first off we will create a small web application and add it to the solution, and grab a reference to the BusinessEntity layer. Set the web site as the startup project. We will also add a Label to the default webform and a Button. In the Page_Load handler method populate the label text from the business entity method.
protected void Page_Load(object sender, EventArgs e)
 {
     uxSettingsLabel.Text = 
         Playground.ConfigurationOverride.BusinessEntity.SettingsGetter.GetDataAccessSettingValue();
 }

...and run the application, and allow the Web.Config file to be created. The value of the setting in the DataAccess App.Config file should be displayed.

 

More to follow soon...

Saturday, April 12, 2008 7:03:24 PM (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.Net | Asp.Net | C# | Config Files | XML