Microsoft

Blog Categories

Subscribe to RSS feed

Archives

DLL-Specific Configuration Files in .NET

In Oscar Meszar’s recent weblog entry, Config Files in Office Add-ins, he describes the need to set up configuration information specific to a DLL. The "official" method of configuring a .NET application is to create a configuration file associated with the executable file (or the web application), but DLL-specific configuration is only possible with a bit of work. In his case, he chose to create a separate configation file parser.

I encountered the same problem on a client engagement. The main application supported a plug-in architecture and it was necessary to configure each plug-in individually. The pattern I chose was to create a publically visible class and a corresponding internal class derived from MarshalByRefObject. The publically visible class was responsible for creating a new AppDomain, loading and unwrapping the MarshalByRefObject type, and delegating to the internal class which actually implemented the functionality.

Here is some sample code. The publically visible class is called SyncProcessor. The corresponding internal class is SyncProcessorInternal. The method SyncProcessor::GetNewAppDomain creates the new AppDomain and points it to a configuration file whose name is based on the name of the DLL – DLLName.dll.config. The SyncProcessor::GetSPI method instantiates a SyncProcessorInternal in the new AppDomain and returns the instance to the caller.

public class SyncProcessor
{
public void ProcessSelectedLocations( int userCode )
{
AppDomain ad = GetNewAppDomain( );

try
{
SyncProcessorInternal spi = GetSPI( ad );
spi.ProcessSelectedLocations( userCode );
}
finally
{
AppDomain.Unload( ad );
}
}

public void ProcessPendingActions( int userCode )
{
AppDomain ad = GetNewAppDomain( );

try
{
SyncProcessorInternal spi = GetSPI( ad );
spi.ProcessPendingActions( userCode );
}
finally
{
AppDomain.Unload( ad );
}
}

public bool IsChildLocationLocked( string location )
{
AppDomain ad = GetNewAppDomain( );

try
{
SyncProcessorInternal spi = GetSPI( ad );
return spi.IsChildLocationLocked( location );
}
finally
{
AppDomain.Unload( ad );
}
}

/// <summary>
/// Creates a new AppDomain in which to execute synchronization. We are doing this in order to associate a configuration file with the DLL
/// rather than the code base of the parent process. The configuration file will be MAR_Synchronizer.dll.config, and is located in the same
/// directory as the MAR_Synchronizer.dll.
/// </summary>
/// <returns>The new AppDomain</returns>
private AppDomain GetNewAppDomain( )
{
// The confifiguration file shall be located in the same directory as the DLL, and named like xxx.dll.config.
string configFile = Assembly.GetExecutingAssembly( ).CodeBase + ".config";

// Create a new AppDomain setup object and specify the configuration file name/location.
AppDomainSetup ads = new AppDomainSetup();
ads.ConfigurationFile = configFile;

// Create the new AppDomain using the AppDomainSetup.
AppDomain ad = AppDomain.CreateDomain( "SyncProcessorInternal", null, ads );

return ad;
}

/// <summary>
/// Creates an instance of the SyncProcessorInternal class in the specified AppDomain.
/// </summary>
/// <param name="ad">The AppDomain in which to create the class.</param>
/// <returns>An instance of the SyncProcessorInternal class</returns>
private SyncProcessorInternal GetSPI( AppDomain ad )
{
string assemblyName = Assembly.GetExecutingAssembly( ).GetName( ).Name;
string typeName = "MRT.SyncProcessorInternal";

return ( SyncProcessorInternal ) ad.CreateInstanceAndUnwrap( assemblyName, typeName );
}
}

internal class SyncProcessorInternal : MarshalByRefObject
{
public void ProcessSelectedLocations( int userCode )
{
// Implementation code goes here
}

public void ProcessPendingActions( int userCode )
{
// Implementation code goes here
}

public bool IsChildLocationLocked( string location )
{
// Implementation code goes here
}

}

Leave a Reply