Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I programmatically assign linqpad config file to be used?

Tags:

linqpad

Linqpad is the only scripting like environment where I can work with my large code base. The reason it is the only environment that works for me is that other solutions (ironpython etc) always fail to properly load configuration from app.config, but linqpad.config works

The problem is, I have multiple config files and every time I want to use one of them for a script, I have to go to linqpad installation directory, rename the right config file to linqpad.config and restart linq. Hardly productive.

I've tried to set the file through:

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"C:\Shared\app.config"); 

but it did not have any effect. Is there any way I can change the config file that will be used in the Main() method of a C# Program in Linqpad? If I could make a call to a function that sets the config file to be used and then run the rest of my code, that'd be great.

like image 237
mahonya Avatar asked May 13 '15 07:05

mahonya


1 Answers

Example Linq Query:

void Main()
{
    var configPath = Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "app.config");

    // Load custom config
    var configProxy = new ConfigurationProxy(configPath);
    if (!configProxy.InjectToConfigurationManager())
    {
        Trace.TraceError("Cannot load config from " + configPath);
        throw new InvalidOperationException("Cannot load config " + configPath);
    }

    ConfigurationManager.AppSettings["LogPath"].Dump();
}

Add this class to your Linq query:

/// <summary>
/// A custom config injector.
/// </summary>
public sealed class ConfigurationProxy : IInternalConfigSystem
{
    /// <summary>
    /// The custom sections
    /// </summary>
    private readonly Dictionary<string, IConfigurationSectionHandler> customSections;

    /// <summary>
    /// The configuration
    /// </summary>
    private Configuration config;

    /// <summary>
    /// Initializes a new instance of the <see cref="ConfigurationProxy"/> class.
    /// </summary>
    /// <param name="fileName">
    /// Name of the file.
    /// </param>
    /// <remarks>
    /// this is called filename but really it's the path as needed
    /// it defaults to checking the directory you're running in.
    /// </remarks>
    public ConfigurationProxy(string fileName)
    {
        this.customSections = new Dictionary<string, IConfigurationSectionHandler>();

        if (!this.Load(fileName))
        {
            throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, "File: {0} could not be found or was not a valid configuration file.", this.config.FilePath));
        }
    }

    /// <summary>
    /// Gets the configuration.
    /// </summary>
    public Configuration Configuration
    {
        get
        {
            return this.config;
        }
    }

    /// <summary>
    /// Returns the configuration object based on the specified key.
    /// </summary>
    /// <param name="configKey">The configuration key value.</param>
    /// <returns>
    /// A configuration object.
    /// </returns>
    public object GetSection(string configKey)
    {
        if (configKey == "appSettings")
        {
            return this.BuildAppSettings();
        }

        object sect = this.config.GetSection(configKey);

        if (this.customSections.ContainsKey(configKey) && sect != null)
        {
            var xml = new XmlDocument();

            xml.LoadXml(((ConfigurationSection)sect).SectionInformation.GetRawXml());

            // I have no idea what I should normally be passing through in the first
            // two params, but I never use them in my config handlers so I opted not to
            // worry about it and just pass through something...
            sect = this.customSections[configKey].Create(this.config, this.config.EvaluationContext, xml.FirstChild);
        }

        return sect;
    }

    /// <summary>
    /// The refresh config.
    /// </summary>
    /// <param name="sectionName">
    /// The section name.
    /// </param>
    public void RefreshConfig(string sectionName)
    {
        // I suppose this will work. Reload the whole file?
        this.Load(this.config.FilePath);
    }

    /// <summary>
    /// Gets a value indicating whether supports user config.
    /// </summary>
    public bool SupportsUserConfig
    {
        get
        {
            return false;
        }
    }

    /// <summary>
    /// Injects to configuration manager.
    /// </summary>
    /// <returns>Whether the configuration was injected</returns>
    public bool InjectToConfigurationManager()
    {
        // inject self into ConfigurationManager
        var configSystem = typeof(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic);
        if (configSystem != null)
        {
            configSystem.SetValue(null, this);
        }

        // lame check, but it's something
        if (ConfigurationManager.AppSettings.Count == this.config.AppSettings.Settings.Count)
        {
            return true;
        }

        return false;
    }

    /// <summary>
    /// Loads the specified file.
    /// </summary>
    /// <param name="file">
    /// The file.
    /// </param>
    /// <returns>
    /// Is file loaded
    /// </returns>
    private bool Load(string file)
    {
        var map = new ExeConfigurationFileMap { ExeConfigFilename = file };
        this.config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

        var xml = new XmlDocument();
        using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
        {
            xml.Load(stream);
        }

        // var cfgSections = xml.GetElementsByTagName("configSections");

        // if (cfgSections.Count > 0)
        // {
        // foreach (XmlNode node in cfgSections[0].ChildNodes)
        // {
        // var type = System.Activator.CreateInstance(
        // Type.GetType(node.Attributes["type"].Value))
        // as IConfigurationSectionHandler;

        // if (type == null) continue;

        // customSections.Add(node.Attributes["name"].Value, type);
        // }
        // }
        return this.config.HasFile;
    }

    /// <summary>
    /// The build app settings.
    /// </summary>
    /// <returns>
    /// The <see cref="NameValueCollection"/>.
    /// </returns>
    private NameValueCollection BuildAppSettings()
    {
        var coll = new NameValueCollection();

        foreach (var key in this.config.AppSettings.Settings.AllKeys)
        {
            coll.Add(key, this.config.AppSettings.Settings[key].Value);
        }

        return coll;
    }
}
like image 50
Zuhaib Avatar answered Nov 04 '22 02:11

Zuhaib