Fetching Connection Strings

clock December 27, 2007 04:49 by author jamesstill

Let's assume you wish to store your database connection string in the <connectionStrings> configuration section of Web.config. This is the best practice in my opinion because you can (and should) encrypt the section in production. Now you have two basic options:

(1) fetch the connection string at the UI level and pass it back to the data layer.

(2) remove the dependency altogether and let the data layer fetch it from Web.config

I've done it both ways. With option (1) you have a simple call to the ConfigurationManager:

string connectionString = ConfigurationManager.ConnectionStrings["FooBar"].ConnectionString;

 

Most people do this and it's quick and simple. If you don't want the coupling or you don't feel like parameter passing or you want your unit test assembly to be able to get a connection string without needing to reflect over the UI assembly, then option (2) involves creating a helper method that any assembly in your solution can call. Here's one that opens a config file from an explicit virtual root location and returns a string value that matches the passed in key:

public static string GetConnectionString(string connectionName) {
    string connectionString = string.Empty;
    // reading from explicit IIS virtual root alias name rather than "~"
    Configuration c = WebConfigurationManager.OpenWebConfiguration(@"\Widget");
    if (c != null) {
        ConnectionStringsSection section = c.GetSection("connectionStrings") as ConnectionStringsSection;
        foreach (ConnectionStringSettings css in section.ConnectionStrings) {
            if (css.Name.ToUpper().CompareTo(connectionName.ToUpper()) == 0) {
                connectionString = css.ConnectionString;
                break;
            }
        }
    }
    return connectionString;
} 

 

Then it's pretty simple to fetch a connection string from your DAL layer: 

string connectionString = GetConnectionString("FooBar");
SqlConnection cn = new SqlConnection(connectionString);

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Enumerate Application Settings

clock December 13, 2007 06:09 by author jamesstill

Here's my own solution to a problem that seems to plague a lot of .NET developers out there. The problem is how best to enumerate application settings stored in a section of an ASP.NET 2.0 app.config file at runtime. Let's suppose you have a settings file called Color.settings with the following key-value pairs:

BLU - Blue
BRO - Brown
GRN - Green
HAZ - Hazel

 

The designer stores those settings in app.config. It also creates the getters for each key and decorates them with the value:

[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Blue")]
public string BLU {
    get {
        return ((string)(this["BLU"]));
    }
}

 

In this way the Color class is strongly-typed and, given a code, makes it easy to fetch its value through the settings property:

string color = Color.Default.BLU;

 

But what if you don't know the key at design time? Fortunately, the singleton instance exposed by the Color.settings class implements ApplicationSettingsBase Properties. Reference System.Configuration and simply enumerate the SettingsPropertyCollection to find the value:

string key = "BLU";
string value = string.Empty;
foreach (SettingsProperty sp in Color.Default.Properties) {
    if (sp.Name.Equals(key)) {
        value = sp.DefaultValue.ToString();
        break;
    }
}

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Custom SiteMapProvider

clock December 13, 2007 05:55 by author jamesstill

Usually custom SiteMap providers are written because we're pulling our nodes from a source other than xml. Jeff Prosise's provider written for SQL Server is a classic example. But I had a case recently in which the out of the box XmlSiteMapProvider was just fine; my problem was that I needed to do some peculiar security trimming on the nodes. No problem, just add roles to the nodes and enable security trimming in Web.config for the provider right? Not exactly. The requirements were that the system had to ship with the ability to turn a major piece of functionality on or off in production. Let's call the functionality "ViewWidgets" and let's say there's an app setting in Web.config called "ViewWidgets" with value="false". That means, the web site should suppress the Widgets unless and until it is flipped to true. Then Widgets should be available to the end user. One way of implementing this would have been to set a generic role or override Web.config in a subfolder. But I wanted the webmaster to be able to flip the flag to true or false in Web.config where he was more comfortable working. The solution turns out to be pretty easy. Just derive a custom provider from XmlSiteMapProvider and override the Initialize method to trim the node based on the app setting:

[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
public class CustomSiteMapProvider : XmlSiteMapProvider {
 
    const string VIEW_WIDGET_KEY = "ViewWidgets";
 
    public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes) {
        lock (this) {
            base.Initialize(name, attributes);
            bool viewWidget = Convert.ToBoolean(AppSettingHelper.GetAppSetting(VIEW_WIDGET_KEY));
            if (!viewWidget) {
                foreach (SiteMapNode childNode in base.RootNode.ChildNodes) {
                    if (childNode.ResourceKey.ToUpper().Equals("WIDGET")) {
                        base.RemoveNode(childNode);
                        break;
                    }
                }
            }
        }
    }
}

 

In this case I've encapsulated calls to AppSettings in an AppSettingHelper class. And of course you have to register your custom provider in the <system.web> section of Web.config. And that's about it.

Currently rated 4.0 by 3 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


Generics and Nullable Types

clock December 12, 2007 08:50 by author jamesstill

It is often useful in OR mapping to analyze a value type that might be null prior to setting it in a business entity. For instance, SqlDateTime type (in System.Data.SqlTypes namespace) is a value type that is nullable. You can call IsNull to check and Value to retrieve the underlying DateTime type:

SqlDateTime d = new SqlDateTime();
if (d.IsNull) 
    Trace.WriteLine("SqlDateTime is null");
d = DateTime.Now;Trace.WriteLine(string.Format("SqlDateTime is {0}", d.Value.ToString()));

 

This is useful when fetching data from SQLServer. DataSets allow nullable values but strongly-typed classes do not. So if I'm instantiating a business entity, I often call TryParse first to protect against null:

//instantiate SqlCommand cm here
SomeBusinessEntity obj = new SomeBusinessEntity();
DateTime dt = new DateTime();
SqlDataReader dr = cm.ExecuteReader();
if (dr != null) {    
    while (dr.Read()) {        
        obj.ID = (DBNull.Value != dr["ID"]) ? Convert.ToInt32(dr["ID"]) : 0;
        if (DateTime.TryParse(dr["ApprovalDate"].ToString(), out dt))              
            obj.ApprovalDate = dt;
    }
}

 

Wouldn't it be great to have a DateTime struct in C# that allows for null? A bunch of folks have gnashed their teeth over this issue since the release of .NET. And now .NET Framework 3.0 supports nullable value types. But I'm still in 2.0 land and will likely remain there for some time so here's my solution. The goal is to support both the above OR mapping logic via generics and to emulate the nullable feature of the SqlDateTime type. In the end we want to do something like this:

Nullable<DateTime> ndt = new Nullable<DateTime>();
if (Nullable<DateTime>.TryParse(DateTime.Now.ToString(), out ndt))
    obj.ApprovalDate = ndt;

 

We start with a basic generics-enabled struct with exposed properties Value and IsNull:

public struct Nullable<T> {
    private static bool _isnull;
    private T _value;
 
    static Nullable() {
        _isnull = true;
    }
 
    public bool IsNull {
        get { return _isnull; }
    }
 
    public T Value {
        get {
            return _value;
        }
        set {
            _value = value;
            _isnull = false;
        }
    }
}

 

The struct has a private _isnull member which is set to true in the static constructor. Only when the value is set does that flag flip to false. So by default it will be null even if the type is not really null; for instance if the underlying DateTime is initialized at 1/1/0001 or the underlying Int32 is initialized at 0. Now we support the TryParse functionality by adding a delegate function that mimics the signature. Note that I'm not supporting the overloaded method for IFormatProvider but rather keeping it simple:

private delegate bool TryParseDelegate<T>(string s, out T result);

 

Then add a private static function to do the work:

private static bool ParseNullable<T>(string s, out Nullable result, TryParseDelegate Parse) where T : struct {
    if (string.IsNullOrEmpty(s)) {
        result = default(Nullable<T>);
        return false;
    }
    else {
        T t;
        bool success = Parse(s, out t);
        Nullable<T> n = new Nullable<T>();
        n.Value = t;
        result = n;
        return success;
    }
}

 

At this point it's just a matter of adding public methods for each type that you need to support. I've added two methods, one for DateTime and one for Int32. Here is the complete Nullable struct:

public struct Nullable<T> {
 
    private static bool _isnull;
    private T _value;
    private delegate bool TryParseDelegate<T>(string s, out T result);
 
    static Nullable() {
        _isnull = true;
    }
        
    public bool IsNull {
        get { return _isnull; } 
    }
 
    public T Value {
        get {
            return _value;
        }
        set {
            _value = value;
            _isnull = false;
        }
    }
 
    public static bool TryParse(string s, out Nullable<Int32> result) {
        return ParseNullable<Int32>(s, out result, Int32.TryParse);
    }
 
    public static bool TryParse(string s, out Nullable<DateTime> result) {
        return ParseNullable<DateTime>(s, out result, DateTime.TryParse);
    }
 
    private static bool ParseNullable<T>(string s, out Nullable<T> result, TryParseDelegate<T> Parse) where T : struct {
        if (string.IsNullOrEmpty(s)) {
            result = default(Nullable<T>);
            return false;
        }
        else {
            T t;
            bool success = Parse(s, out t);
            Nullable<T> n = new Nullable<T>();
            n.Value = t;
            result = n;
            return success;
        }
    }
}

 

To exercise the struct:

class Program {
    static void Main(string[] args) {
            
        // exercise Nullable<T> with type DateTime
        Nullable<DateTime> ndt = new Nullable<DateTime>();
        Console.WriteLine(string.Format("Is null? {0}", ndt.IsNull.ToString()));
        Console.WriteLine(string.Format("Value is {0}", ndt.Value.ToString()));
        ndt.Value = DateTime.Now;
        Console.WriteLine(string.Format("Is null? {0}", ndt.IsNull.ToString()));
        Console.WriteLine(string.Format("Value is {0}", ndt.Value.ToString()));
        Console.WriteLine();
            
        // exercise Nullable<T> with type Int32
        Nullable<int> nint = new Nullable<int>();
        Console.WriteLine(string.Format("Is null? {0}", nint.IsNull.ToString()));
        Console.WriteLine(string.Format("Value is {0}", nint.Value.ToString()));
        nint.Value = 42;
        Console.WriteLine(string.Format("Is null? {0}", nint.IsNull.ToString()));
        Console.WriteLine(string.Format("Value is {0}", nint.Value.ToString()));
            
        // exercise TryParse functionality
        if (Nullable<DateTime>.TryParse(DateTime.Now.ToString(), out ndt)) {
            Console.WriteLine(string.Format("Successful TryParse with result {0}", ndt.Value.ToString()));
        }
 
        if (Nullable<int>.TryParse("99", out nint)) {
            Console.WriteLine(string.Format("Successful TryParse with result {0}", nint.Value.ToString()));
        }
        Console.ReadKey();         
    }
}

 

Looking for custom .NET solutions or help with an existing project? Give me a call at (503) 475-3808 and let's talk about your situation.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5


About

SquareWidget LLC is an Oregon-based software development company that specializes in handcrafted .NET software solutions.

Search

Archive

Categories


Sign in