Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX

By submitting your information, you agree that devx.com may send you DevX offers via email, phone and text message, as well as email offers about other products and services that DevX believes may be of interest to you. DevX will process your information in accordance with the Quinstreet Privacy Policy.


.NET Building Blocks: Build a Configurable Database Credential Selector : Page 6

This handy control gives you everything you need to control how users input usernames, passwords, select servers, and choose connection types.




Application Security Testing: An Integral Part of DevOps

Architecture of the Demo Project
To use the ConnectionStringManager in your own applications study Figure 9, which shows the demo project architecture. With a good grasp of this, you will find it very easy to use the control. For the demo project the user in the figure represents you, the designer. Your various selections on the main form adjust exposed properties of the credential form, also a class in the demo project. In turn, the credential form sets properties of the ConnectionStringManager control. Solid arrows indicate properties that are directly determined, whereas dotted arrows are set by the program indirectly. Also note that some arrows point right (indicating data flows left to right), some point left, and some are bidirectional, illustrating that the DbType and ConnectionString properties are the only ones read from the ConnectionStringManager. In the demo program, those are passed through the credential form back to the main form.

Figure 9. Demo Project Architecture: The main form, credential form, and ConnetionStringManager control exhibit this flow of settings and properties.
The ConnectionString is, of course, the whole focus of the ConnectionStringManager control. You start with either a complete, default connection string, or a partial, base version of a connection string. In either case you pass it from your main application to the credential form. The credential form hands it off internally to the ConnectionStringManager for manipulation. After a user has interacted with it, the credential form retrieves it and sends it back to your main application. The demo project also needs the DbType in the main application so that it knows whether to formulate a SQL Server or an Oracle test query when you press the Run Test Query button.

The code for the credential form (see Listing 1) is not complicated; most of the methods simply pass property values to the ConnectionStringManager. The last method (RenderingByHiding) is different only because it must convert between a Boolean and an access level.

The Mode property requires more code, as illustrated in Figure 9. Based on the radio button selected on the main form, this property sets the exposure level of the six input fields on the ConnectionStringManager control as shown in Listing 2.

The only remaining bits of code in the credential form are the event handlers for the OK and Cancel buttons:

private void cancelButton_Click(object sender, EventArgs e) { Close(); } private void okButton_Click(object sender, EventArgs e) { connStrMgr.Accept(); Close(); }

The Cancel button event handler does nothing but close the form. The OK event handler performs one crucial method call, connStrMgr.Accept(), which tells the ConnectionStringManager to commit the changes the user has made. Those changes are then available in any of the ConnectionStringManager properties (ConnectionString, SecureConnectionString, or ConditionalConnectionString).

Figure 10. Your Project Architecture: You customize ConnectionStringManager properties at design time on the credential form.
Architecture of a Real Project
In a real application, you'll determine most if not all the run-time actions of the ConnectionStringManager control at design time, so the architecture looks much simpler (see Figure 10). The user in Figure 10 this time represents your application's users. Notice that there is much less coupling between the main form and the credential form, as good design practice dictates. Also, although it appears at first glance as if there's just as much coupling between the credential form and the ConnectionStringManager, most are dotted arrows, which signify property settings you can set at design time, as you lay out your form.

If your application requires a dual login—say a connection to both a SQL Server and an Oracle database—your main form can use this method to interact with the credential form (cf in the following code):

private string SetCredentials( string connString, string title) { cf.AllowServerSelection = ((Control.ModifierKeys & Keys.Shift) == Keys.Shift); cf.SetConnection(connString, title); cf.ShowDialog(); return cf.ConnectionString; }

Line one of the SetCredentials method above lets advanced users change servers by simply holding down the Shift key. The AllowServerSelection property shown above sets the familiar ExposeServer property of the ConnectionStringManager control. In this dual-login scenario, you maintain two separate connection strings, passing the appropriate one along with an appropriate title for the credential form. Here's the AllowServerSelection property code:

public bool AllowServerSelection { set { connStrManager.ExposeServer = value? ConnectionStringManager.AccessLevel.Edit : ConnectionStringManager.AccessLevel.Hide; } }

Line two of the SetCredentials method invokes SetConnection, which prepares the credential form for display. This method sets four entities—marked by the numbers in square brackets in the comments below:

public void SetConnection(string connString, string title) { key = title; // [1] set title connStrManager.ControlTitle = title + " login"; // [2] set connection string AttributeDictionary connStrDict = new AttributeDictionary(connString); userDict = new AttributeDictionary( Properties.Settings.Default.Usernames); if (userDict.ContainsKey(key)) { connStrDict["User ID"] = userDict[key]; } pwdDict = new AttributeDictionary( Properties.Settings.Default.Passwords); if (pwdDict.ContainsKey(key)) { connStrDict["Password"] = pwdDict[key]; } connStrManager.ConnectionString = connStrDict.ToString(); // [3] set remember pwd checkbox connStrManager.RememberPassword = Properties.Settings.Default.StorePasswords; // [4] set db type connStrManager.DbType = title.Equals("sqlserver") ? ConnectionStringManager.DBTypes.SqlServer : ConnectionStringManager.DBTypes.Oracle; }

The items marked with [1], [3], and [4] in the preceding code should look familiar by now. Item [2] illustrates a technique for maintaining username and password dictionaries separate from the connection string. So, just before setting the ConnectionStringManager's ConnectionString property the code manipulates the connection string to add the appropriate username and password.

Line three of the SetCredentials method opens the credential form. When the user closes the form, control returns to line four of SetCredentials, which simply returns the connection string via a pass-through property:

public string ConnectionString { get { return connStrManager.ConnectionString; } }

For completeness, here's the rest of the credential form class definition, not counting the separate, designer-generated portion:

public partial class CredentialForm : Form { private AttributeDictionary userDict; private AttributeDictionary pwdDict; private string key; public CredentialForm() { InitializeComponent(); } /* add other code fragments shown earlier… */ private void acceptButton_Click(object sender, EventArgs e) { connStrManager.Accept(); AttributeDictionary connStrDict = new AttributeDictionary( connStrManager.ConnectionString); userDict[key] = connStrDict["User ID"]; pwdDict[key] = connStrDict["Password"]; Properties.Settings.Default.Usernames = userDict.ToString(); Properties.Settings.Default.Passwords = pwdDict.ToString(); Properties.Settings.Default.StorePasswords = connStrManager.RememberPassword; Close(); } private void cancelButton_Click(object sender, EventArgs e) { Close(); } }

The preceding code contains two event handlers, one for the OK button, and one for the Cancel button, just as in the demo project. The code in the acceptButton_Click routine assists with maintaining the dictionary of usernames and corresponding dictionary of passwords introduced earlier in the SetConnection method.

Finding a .NET application today that does not use a back-end database is rare, so you should easily find a use for the concepts and tools presented in this article. The ConnectionStringManager typifies the well-known "lazy axiom" of software development, to wit: create something only once and use it as a building block. Let me know if you find it useful.

Michael Sorens is a freelance software engineer, spreading the seeds of good design wherever possible, including through his open-source web site, teaching (University of Phoenix plus community colleges), and writing (contributed to two books plus various articles). With BS and MS degrees in computer science and engineering from Case Western Reserve University, he has worked at Fortune 500 firms and at startups, using C#, SQL, XML, XSL, Java, Perl, C, Lisp, PostScript, and others. His favorite project: designing and implementing the world's smallest word processor, where the medium was silicon, the printer "head" was a laser, and the Declaration of Independence could literally fit on the head of a pin. You can discuss this or any other article by Michael Sorens here.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date