Creating Custom Configuration Settings

March 25, 2009

The .NET framework has several options to offer when it comes to storing configuration settings in your configuration file.  When storing simple key-value settings, the AppSettings section may be all that you need.  However, in other cases, you might want to store more complex configuration settings.  If that is the case, creating your own, custom configuration section may be a better option.

.NET Framework 2.0 allows you to create a class that inherits from the ConfigurationSection class, which makes creating a custom configuration section a piece of cake.  The class I am showing here as an example is not very spectacular, but show the most important features.  The class represents settings that might be used for a form in your application that allows users to contact you.  This example assumes that all mail from your application will be sent to one, configurable email address.  It also assumes that you might want to prefix the subject (as entered by the user) with a short prefix, so you can use it for easy filtering in your mail client.

First, you need to create the class that will be used to retrieve the configuration settings from te configuration file:

namespace CustomConfigurationDemo
{
  public class MailFormConfiguration : ConfigurationSection
  {
    [ConfigurationProperty("mailTo",
      IsRequired = true)]
    public string MailTo
    {
      get
      {
        return (String)this["mailTo"];
      }
      set
      {
        this["mailTo"] = value;
      }
    }
    [ConfigurationProperty("subjectPrefix",
      DefaultValue = "",
      IsRequired = false)]
    public string SubjectPrefix
    {
      get
      {
        return (String)this["subjectPrefix"];
      }
      set
      {
        this["subjectPrefix"] = value;
      }
    }
  }
}

The important things to note here, are:

  • The class inherits from ConfigurationSection;
  • Each property has a ConfigurationProperty attribute

For the ConfigurationProperty attribute to work, you must specify the name of the attribute in the coniguration file that will be used to retrieve the value.  The ConfigurationProperty attribute also allows you to specify a DefaultValue, and you can use IsRequired to indicate whether the attribute must be included in the configuration file.  If you set IsRequired to true and the attribute is not found in the configuration file, a ConfigurationErrorsException will be thrown.

In order to use this MailFormConfiguration class, you will need to include the following in your configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="mailFormConfiguration"
             type="CustomConfigurationDemo.MailFormConfiguration,
                   CustomConfigurationDemo" />
  </configSections>
  <mailFormConfiguration mailTo="somebody@somepany.com" />
</configuration>

As you can see, the subjectPrefix attribute is not required, and is not included in the configuration file.  Its value will be set to the default value specified using the ConfigurationProperty attribute which, in this case, is an empty string.

The following code fragment shows how the custom configuration settings class can be used in your application:

MailFormConfiguration config =
  (MailFormConfiguration)ConfigurationManager.GetSection(
  "mailFormConfiguration");
string mailTo = config.MailTo;
string subjectPrefix = config.SubjectPrefix;

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

ASP.NET MVC RTM Release Available

March 19, 2009

A moment a lot of people have been waiting for has arrived: ASP.NET MVC RTM has been released!

Read more about the release on Phil Haack’s blog.  You can also find some extra information about last minute changes (mostly to T4 templates) here: Visual Web Developer Team Blog.

And most important of all, links to the new goodies:

ASP.NET MVC 1.0 download (The Futures download can be found on the same page).

ASP.NET MVC 1.0 source code download

Have fun with the new toys. :)

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

ASP.NET MVC RenderPartial Compiler Error

March 4, 2009

Am I the only person who can stare at a piece of code for ten minutes and not notice the obvious?  I was trying to use the HtmlHelper.RenderPartial method tonight, using the code fragment below:

<%= Html.RenderPartial(
    "~/Views/Shared/ProductSummary.ascx", product) %> 

For those of you who are just getting started with a more recent version of ASP.NET MVC, the RenderPartial method replaces the RenderUserControl method in previous versions.  Anyway, I got this compiler error:

“Cannot implicitly convert type ‘void’ to ‘object’.”

It took me TEN minutes to figure out what was wrong…  The RenderPartal method does not return a string, but void.  So, I should have used the following code fragment:

<% Html.RenderPartial(
    "~/Views/Shared/ProductSummary.ascx", product); %>

So, if you get a similar compiler error and don’t see what is wrong, there are two differences, because the method returns void and not a string, as most HtmlHelper methods do:

  1. You have to use <% instead of <%=
  2. You have to put a ; after the closing ) of the RenderPartial statement

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

Content-Transfer-Encoding System.Net.Mail.MailMessage

March 4, 2009

If you have tried to send an email using the System.Net.Mail.MailMessage class and System.Net.Mail.SmtpClient class, you may have come across the problem described in this blog post.  The recipient may receive a garbled message, in which carriage returns are not recognized and are shown are strange characters instead:

This is a test message.=0D=0ANew line should start here.=0D=0A

However, when opening the mail in Outlook, it may appear fine.  It took me some time to figure out what was happing.  I used the TcpTrace tool for intercepting the actual message being sent.  The message message had the following items in its header:

Content-Transfer-Encoding: quoted-printable

When using the obsolete System.Web.Mail classes, the Content-Transfer-Encoding had been 7bit instead of quoted-printable.  I thought the strange characters might have something to do with the Content-Transfer-Encoding being used, and started playing around with the AlternativeView class to add an alternative view to my message which, hopefully, would display correctly in the recipient’s client.  Unfortunately, adding an AlternativeView leaves the original view in the message as well, and this particular client still tried to read that original view. 

At first, I thought I would have to revert to the old System.Web.Mail client.  I decided to try one more Google search to see if there was a way around this, and found a comment by Stanley Roark, buried on the MSDN Library’s page about the MailMessage class.  This solution worked so well for me that I decided it deserved a blog post in its own right, hoping it would make it easier for people to find this solution.  My version of the code, in which you will have to replace some of the strings with those appropriate for your own message:

MailMessage message = new MailMessage(
    "from@somepany.com", "to@somepany.com");
message.Subject = "Some Subject";
message.IsBodyHtml = false;
message.Body = null;
using (AlternateView body =
    AlternateView.CreateAlternateViewFromString(
        "Some Message Body",
        message.BodyEncoding,
        message.IsBodyHtml ? "text/html" : null))
{
    body.TransferEncoding = 
        TransferEncoding.SevenBit;
    message.AlternateViews.Add(body);
    try
    {
        SmtpClient smtp = new SmtpClient("mail.somepany.com", 25);
        smtp.Send(message);
    }
    catch (SmtpException ex)
    {
        System.Diagnostics.Debug.WriteLine(
            ex.Message);
    }
} 

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

Accessing Spring.NET From Global.asax.cs

February 26, 2009

Yesterday, I was working on a web application in which I wanted to use the EntityTranslatorService and EntityTranslator classes as can be found in the Smart Client Software Factory, simply because I like the concept behind these mappers.  My application also needs to be testable.  I am using Spring.NET’s Inversion Of Control + Dependency Injection mechanism.

I wanted the EntityTranslatorService to be a singleton, so I would only have to register the EntityTranslators once.  I figured it should be possible to create a ConfigurationService class, with a RegisterTranslators method that would allow me to access the singleton instance of the EntityTranslatorService in order to register the different translators I would be using.  And what better place to do this than the Application_Start EventHandler in the Global.asax.cs file of my web application?  That way, the entity translators would only have to be set up once.  I added the following piece of code to the Application_Start EventHandler:

IConfigurationService configurationService =
     SpringContextRegistry.Context.Resolve<IConfigurationService>();
configurationService.RegisterEntityTranslators();

(SpringContextRegistry.Context.Resolve is just a helper method I created to be able to resolve objects based on the string representation of their type.) 

Wrong!

As soon as I tried to run my application, I was presented with the following error message:

“WebSupportModule not initialized. Did you forget to add <add name=”Spring” type=”Spring.Context.Support.WebSupportModule, Spring.Web”/> to your web.config’s <httpModules>-section?”

Whoops…  I should have realized that the application would not have been fully initialized by the time I made my Spring.NET call…  The Spring.NET WebSupportModule wasn’t available yet.

It didn’t take me long to find the solution to the problem, though.  I just needed to move my code and put it in the Init() method:

public override void Application_Init()
{
     base.Init();
     IConfigurationService configurationService =
          SpringContextRegistry.Context.Resolve<IConfigurationService>();
     configurationService.RegisterEntityTranslators();
}

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

Smart Client Software Factory VS2008 SP1 Bug

February 20, 2009

I ran across an issue with the Smart Client Software Client Factory in Visual Studio 2008 SP1 Today.  I tried creating and building the “Hello World Application” as described in the “Getting Started” document.  After hitting F5 to try and run the project, I was presented with the following error message:

“Assembly file C:\Data\Projects\Smart Client Software Factory\HelloWorldApplication\bin\Debug\Infrastructure.Layout.dll was not found.”

I checked the debug folder and noticed that the output of the Infrastructure.Layout project (in the same solution) was named “HelloWorldApplication.Infrastructure.Layout.dll” instead.  Well, that explained part of what was going on.

I then tried to figure out how the smart client application knew which assembly files to load, and came across the ProfileCatalog.xml file in the Shell project.  This file contained the following section:

<Section Name="Layout">
     <Modules>
          <ModuleInfo AssemblyFile="Infrastructure.Layout.dll" />
     </Modules>
</Section>

So this is what was causing the mismatch between the files in the debug folder and the files the application was trying to find.  I also noticed on the Infrastructure.Layout projects Project Properties – Application tab, that the name of the assembly was prefixed with the name of the solution.  Please note that I described the situation for the Infrastructure.Layout assembly only, but ALL of the Hello World Application’s assemblies are prefixed with the solution name.

Of course you can adjust the ProfileCatalog.xml file and make the names of the assemblies match those of the actual assembly names.  Or you could adjust the settings on the Project Properties – Application tab for all of the projects in the solution.  However, there is an easier way to fix this.

The problem is in the guidance package’s source code and there is a knowledge base article that explains how to fix this.  The same page also mentions another problem with the SCSF and VS2008 SP1, which concerns the absence of the “Add View” functionality.  Mariano Converti has already created a fixed version of the guidance package that is available for download.

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

SQL Server Reporting Services Database Version

February 20, 2009

Yesterday, I installed SQL Server Reporting Services on an existing instance of SQL Server 2005, Service Pack 2.  I then started Reporting Services configuration with the Reporting Services Configuration Tool.  On the Database Setup tab, I selected the machine, and tried to add a new database using the New… dialog.  At first, it looked like everything was going to be okay, because I noticed that the two Reporting Services database had been created in SQL Server.  However, I also noticed a warning notice at the bottom of the Database Setup tab.

I then tried to apply my changes, and was asked to upgrade my database.  I was a little surprised by that question because I had not seen it when installing Reporting Services before.  I have to mention though, that on previous occasions, I had installed SQL Server 2005 and Reporting Services in one go, and that this was the first time I was adding Reporting Services to an existing SQL Server 2005 instance.

Anyway, to make a long story short…  I was presented with the following error messages:

“The database version (C.0.8.40) does not match your reporting services installation. You must upgrade your reporting services database.”

“Couldn’t generate the upgrade script. There is no upgrade script available for this version.”

At first, I had no idea what was going on.  After searching the web for some answers, I was able to conclude that the problem was caused by the fact that I had done the following:

  1. Install SQL Server 2005
  2. Install SQL Server 2005 when it became available
  3. Install SQL Server Reporting Services 2005 using the same setup I used for the initial install of SQL Server 2005

In other words: I had installed the non-Service Pack 2 version of SQL Server Reporting Services 2005 on a SQL Server 2005 Service Pack 2 instance.  The solution to the problem: re-install Service Pack 2!

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

ValidateInput Attribute and ASP.NET MVC

February 18, 2009

ASP.NET has built-in request validation in order to prevent security issues such as Cross Site Scripting.  If you have a form with an editor such as TinyMCE on it and perform a postback, ASP.NET will present you with an error page:

“A potentially dangerous Request.Form value was detected from the client…”

In order to prevent this error mesage, you can disable Request Validation by disabling it in your web.config file (for all the files in that location) or by adding a Page directive to specific pages: 

<%@ Page ValidateRequest="false" ... %>

Today I was working on an ASP.NET MVC application in which I needed to integrate TinyMCE, and was surprised to see that neither the Page directive nor the web.config adjustment solved this problem.   Eventually, Google helped me find the solution.

In order to disable request validation in ASP.NET MVC, you need to add a ValidateInput attribute to your controller’s method, as shown in the code fragment below:

[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult Edit(string editor)
{
   ViewData["editor"] = editor;  
   return View();
}

Works like a charm…  However, do note that you may need to implement your own request validation in order to prevent users from using the text editor to execute malicious scripts.

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com

Extension Methods

February 17, 2009

Extension methods allow you to add functionality to existing classes, whether they are .NET Framework classes or your own.  The MSDN library offers more information on extension methods in C# 3.0 and Visual Basic 2008.

I often use extension methods for formatting Double values.  For some reason, I can’t seem to remember how these are supposed to be formatted, so I created extension methods for this purpose.  The following class shows the code that is needed to format a Double value using the local regional settings, or using a specific culture:

using System;
using System.Globalization;

namespace IDevelop.Framework.Utilities.Extensions
{
  public static class DoubleExtensions
  {
    public static string ToLocalCurrencyString(this double value)
    {
      return (String.Format("{0:C}", value));
    }

    public static string ToSpecificCurrencyString(this double value,
      string cultureName)
    {
      CultureInfo culture = new CultureInfo(cultureName);
      return (string.Format(culture, "{0:C}", value));
    }
  }
}

In order to use these extension methods, make sure that the class in which you use them has a using statement to import the namespace in which the extension methods are located. Then, you can call the two extension methods as shown in the following two samples:

double localCurrencyString = 9.95;
double specificCurrencyString = 11.21;

Debug.WriteLine("Local: " +
     localCurrencyString.ToLocalCurrencyString());
Debug.WriteLine("Specific: " +
     specificCurrencyString.ToSpecificCurrencyString("nl-NL"));

This outputs the following strings:

Local: $9.95
Specific: € 11,21

These are just two simple examples that show how extension methods can be used to add functionality to existing classes.

If you found this post helpful, please click below to “Kick” it:

kick it on DotNetKicks.com


Follow

Get every new post delivered to your Inbox.