How to set dynamic value in my Attribute

I would like to pass a dynamic variable as a parameter to my attribute. Here I want to use Environment.MachineName, see the code below:

public interface IMonitoringViewModelConfiguration : IConfigurationContainer
{
    [ConfigurationKey("MonitoringService", Environment.MachineName)]
    string ConnectionString { get; }
}

But I get this error: Error 1 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type Abc.ServiceBus.Monitoring.ViewModel

Is there any workaround as clean as possible in order to pass my Environment.MachineName ?

Thanks.

John

PS: I've found some articles which talk about this case but it have been written like 2-3 years ago. But today, does the clr which comes from .NET 4.0 gives some nice solution ?


Solution 1:

You could create an enum with special values, and accept them in a separate constructor overload in the attribute:

enum SpecialConfigurationValues
{
    MachineName
    // , other special ones
}

class ConfigurationKeyAttribute : Attribute
{
    private string _key;
    private string _value;

    public ConfigurationKeyAttribute(string key, string value)
    {
        // ...
    }

    public ConfigurationKeyAttribute(string key, SpecialConfigurationValues specialValue)
    {
        _key = key;
        switch (specialValue)
        {
            case SpecialConfigurationValues.MachineName:
                _value = Environment.MachineName;
                break;
            // case <other special ones>
        }
    }
}

[ConfigurationKey("MonitoringService", SpecialConfigurationValues.MachineName)]

Solution 2:

Attribute parameters are evaluated at compile time, not at runtime. So they have to be compile time constants...

However, you could create a derived class LocalMachineConfigurationKey attribute that takes only one parameter and uses Environment.MachineName at runtime to evaluate the property.

public class ConfigurationKeyAttribute : Attribute
{
    private readonly string _key;
    private readonly string _machineName;

    public ConfigurationKeyAttribute(string key, string machineName)
    {
        _key = key;
        _machineName = machineName;
    }

    protected ConfigurationKeyAttribute(string key) : this(key, null)
    {
    }

    public string Key { get { return _key; } }
    public virtual string MachineName { get { return _machineName; } }
}

public class LocalMachineConfigurationKeyAttribute : ConfigurationKeyAttribute
{
    public LocalMachineConfigurationKeyAttribute(string key) : base(key)
    {
    }

    public override string MachineName { get { return Environment.MachineName; } }
}