Wednesday, February 07, 2007

Config Files and Assemblies in the GAC

Be sure to read the update at the bottom of the post.

The 2.0 version of the .NET has improved the application configuration functionality a lot. Read/Write capability being one of the nicest new features. Combined with Visual Studio 2005’s
new settings dialog, using the app.config has gotten a lot easier.

One of the main rules when using the app.config, is that the app.config file has to be in the same folder as its owning dll or exe. Which usually isn’t a problem unless your dll is sitting in the GAC. If you’ve had any experience with the GAC, you know that you can’t just add files to it. It only really accepts .NET dlls.



My current project requires a business layer that will be used by multiple applications, which is a great use of the GAC. There are some settings that will be needed by this business layer. So the question is: How do I get the app.config settings to work with a dll that is stored in the GAC?
It took some figuring out but I found a way. It's not the cleanest way but it works.

Here how:

  1. Copy your dll to the GAC (however you normally do it)

  2. Open command prompt (Start -> Run -> cmd)

  3. Change the path to Windows Root Folder\Assembly

  4. Depending on what you have installed Change the path to:

    • .NET 1.0 or .NET 1.1: cd GAC
    • .NET 2.0: cd GAC_MSIL

  5. If you dir, you will see a list of all the assemblies installed into the GAC. Cd into your assembly's folder
  6. If you dir again, you will see one folder with your assembly's version and public key token. Cd into this folder
  7. If you dir again, you will be glad to see your assembly.
  8. Copy your config file to this folder via the command prompt
  9. Your application should now be able to locate and use any configuration that you have added to that file.
UPDATED: Turns out that I'm only partially correct with the above post. You can put files into the GAC folders using the above steps. However, you cannot use the built in app.config settings functionality. For some reason it won't read in the file. I've since replaced the app.config settings with a custom class that has all the values that I want to use as settings and then serialize/deserialize the object to the same directory as the owning application or dll.


UPDATED 2: Thanks to commenters on further research, the above option of serialization is not required. All you need to do is setup your settings for the built in app.config funcationality and then use the OpenMappedExecConfiguration method. Example:


   Private Shared Function GetConfigurationSection() As Configuration.ClientSettingsSection 
Dim codebase As String = System.Reflection.Assembly.GetExecutingAssembly().CodeBase
Dim fileMap As New Configuration.ExeConfigurationFileMap()
Dim p As New Uri(codebase)
Dim localPath As String = p.LocalPath
Dim executingFilename As String = System.IO.Path.GetFileNameWithoutExtension(localPath)

Dim sectionGroupName As String = "applicationSettings"
Dim sectionName As String = String.Format("{0}.My.MySettings", executingFilename)

Dim configName As String = String.Format("{0}.config", localPath)

fileMap.ExeConfigFilename = configName
Dim config As Configuration.Configuration = _
Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, Configuration.ConfigurationUserLevel.None) 'System.AppDomain.CurrentDomain.)

If config IsNot Nothing Then
Dim group As Configuration.ConfigurationSectionGroup = config.GetSectionGroup(sectionGroupName)

If group IsNot Nothing Then

Return DirectCast(group.Sections(sectionName), Configuration.ClientSettingsSection)
End If
End If
Return Nothing
End Function




5 comments:

Anonymous said...

what if that didn't work. do i reboot the machine?

Cody Schouten said...

I need a little more information. Try running your application not in the GAC and see if it works. If not, it's a code issue. If it does, make sure the config file is in the right spot and that your dll can see it.

Anonymous said...

Reading a config from a dll in the GAC worked for me once I used the following...

System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);
_connection = new SqlConnection(config.ConnectionStrings.ConnectionStrings["SBPSEConnectionString"].ConnectionString);


PS
I also copied the config into the GAC as described above.

Anonymous said...

this one really works, don't waste time with serialization:

System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location);

great post, btw!
cheers

Anonymous said...

That worked like a charm. Thanks, I was stuck for days trying to figure out why my changes to the config file were ignored even following a reboot.