Matt
Matt

Reputation: 5142

Is there a way to use a Dictionary-like collection as an Application Settings object?

I'd like to store a set of key/value pairs in the application settings of my ASP.NET web app, but I'm not finding a straightforward way to do that. For example, these two questions tell me that StringDictionary etc. won't serialize to XML and suggest that I'll have to roll my own implementation. But it seems like this should be easier to do; after all, web.config is XML and < applicationSettings> is essentially a collection of key/value pairs, so it feels like I'm missing something obvious. Given my specific case below, do I really have to roll my own serialization, or is there an easier workaround?

The web app in question is a basic contact form that sends email to different recipients based on the value of a parameter; e.g. http://www.examplesite.com/Contact.aspx?recipient=support would send email to [email protected].

The goal is to be able add or remove recipients (or change their addresses) by editing the web.config file so that I don't have to recompile and can easily maintain different configurations in test and production environments. For example:

// I can use something like this for the sender address
SmtpMsg.From = New MailAddress(My.Settings.EmailSender)

// And then just edit this part of web.config to use 
// different addresses in different environments.
<setting name="EmailSender" serializeAs="String">
 <value>[email protected]</value>
</setting>

// I want something like this for the recipients
SmtpMsg.To.Add(My.Settings.Recipients("support"))

// and presumably some sort of equivalent xml in web.config
// maybe something like this???
<recipients>
  <item name="support" serializeAs="String">
   <value>[email protected]</value>
  </item>
  <!-- add or remove item elements here -->
</recipients>

edit: replaced VB comments w/ C# comments because of the code-coloring

Upvotes: 2

Views: 2783

Answers (2)

Zhaph - Ben Duguid
Zhaph - Ben Duguid

Reputation: 26956

The simplist way would obviously be to just drop them in the app settings, but it wouldn't be very neat:

<appSettings>
  <add key="EmailSupport" value="[email protected]" />
  <add key="EmailSales" value="[email protected]" />
</appSettings>

Then in your code you're just doing something like:

if (!string.IsNullOrEmpty(Request["recipient"])) {
  string recipientEmail = 
         WebConfigurationManager.AppSettings["Email" + Request["recipient"]];
  // Send your email to recipientEmail
}

If you want to be a bit neater, you can create a custom Configuration Section like this (C# I'm afraid, but the docs have VB as well):

namespace EmailSystem {
  public class EmailRecipientsSection : ConfigurationSection {
    [ConfigurationProperty("emailSender", IsRequired = true, IsKey = false)]
    public string EmailSender {
        get { return (string)this["name"]; }
        set { this["name"] = value; }
    }

    [ConfigurationProperty("emailRecipients", IsDefaultCollection = true)]
    public EmailRecipientCollection EmailRecipients {
      get {
        var emailRecipientCollection = 
              (EmailRecipientCollection) base["emailRecipients"];
        return emailRecipientCollection;
      }
    }
  }

  public class EmailRecipientCollection : ConfigurationElementCollection {
    public EmailRecipientElement this[int index] {
      get { return (EmailRecipientElement) BaseGet(index); }
      set {
        if (BaseGet(index) != null) {
          BaseRemoveAt(index);
        }
        BaseAdd(index, value);
      }
    }

    public new EmailRecipientElement this[string name] {
      get { return (EmailRecipientElement) BaseGet(name); }
    }

    protected override ConfigurationElement CreateNewElement() {
      return new EmailRecipientElement();
    }

    protected override object GetElementKey(ConfigurationElement element) {
      return ((EmailRecipientElement) element).Name;
    }
  }

  public class EmailRecipientElement : ConfigurationElement {
    [ConfigurationProperty("name", IsRequired = true, IsKey = true)]
    public string Name {
      get { return (string) this["name"]; }
      set { this["name"] = value; }
    }

    [ConfigurationProperty("emailAddress", IsRequired = true)]
    public string EmailAddress {
      get { return (string) this["emailAddress"]; }
      set { this["emailAddress"] = value; }
    }
  }
}

Then in your web.config have something like this:

<configSections>
  [...]
  <section name="EmailSystem" type="EmailSystem, AssmeblyName" />
</configSections>

<EmailSystem emailSender="[email protected]">
  <emailRecipients>
    <clear />
    <add name="Support" emailAddress="[email protected]" />
    <add name="Sales" emailAddress="[email protected]" />
  </emailRecipients>
</EmailSystem>

Then you can call into this:

emailRecipient = Request["recipient"];

var emailSystem = ConfigurationManager.GetSection("EmailSystem")
                    as EmailRecipientsSection;

string recipientEmail = emailSystem.EmailRecipients[emailRecipient].emailAddress;

// send email to recipientEmail.

Upvotes: 5

Jonathan
Jonathan

Reputation: 1892

You can do a couple things, though honestly I think this is easiest:

<appSettings>
    <add key="testValues" value="[email protected], [email protected], [email protected]" />
</appSettings>

Then you can get your object via:

String[] temp =
ConfigurationManager.AppSettings.GetValues("testValues").ToString().Split(',');

and then do a simple foreach statement to retrieve. You could even set this as a static object to be cached so it's a quicker retrieve. :)

Hope this helps,

JP

EDIT: An alternative scenario involves:

<appSettings file="test.config">
<!-- other settings to default to if test.config doesn't exist -->
</appSettings>

In this case, if you have a test.config file existing in your test environment, the AppSettings.GetValues() call will be made against that file. If the test.config file does not exist, the ConfigurationManager class will use the values within the appSettings node in your web.config file.

Upvotes: 3

Related Questions