5

How can I replace the Range values with Web.Config values in MVC3?

[Range(5, 20, ErrorMessage = "Initial Deposit should be between $5.00 and $20.00")
public decimal InitialDeposit { get; set; }

web.config:

<add key="MinBalance" value="5.00"/>
<add key="MaxDeposit" value="20.00"/>
1

3 Answers 3

9

You will need to create a custom attribute inheriting from RangeAttribute and implementing IClientValidatable.

    public class ConfigRangeAttribute : RangeAttribute, IClientValidatable
    {
        public ConfigRangeAttribute(int Int) :
            base
            (Convert.ToInt32(WebConfigurationManager.AppSettings["IntMin"]),
             Convert.ToInt32(WebConfigurationManager.AppSettings["IntMax"])) { }

        public ConfigRangeAttribute(double Double) :
            base
            (Convert.ToDouble(WebConfigurationManager.AppSettings["DoubleMin"]),
             Convert.ToDouble(WebConfigurationManager.AppSettings["DoubleMax"])) 
        {
            _double = true;
        }

        private bool _double = false;

        public override string FormatErrorMessage(string name)
        {
            return String.Format(ErrorMessageString, name, this.Minimum, this.Maximum);
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ErrorMessage = FormatErrorMessage(this.ErrorMessage),
                ValidationType = "range",
            };
            rule.ValidationParameters.Add("min", this.Minimum);
            rule.ValidationParameters.Add("max", this.Maximum);
            yield return rule;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value == null)
                return null;

            if (String.IsNullOrEmpty(value.ToString()))
                return null;

            if (_double)
            {
                var val = Convert.ToDouble(value);
                if (val >= Convert.ToDouble(this.Minimum) && val <= Convert.ToDouble(this.Maximum))
                    return null;
            }
            else
            {
                var val = Convert.ToInt32(value);
                if (val >= Convert.ToInt32(this.Minimum) && val <= Convert.ToInt32(this.Maximum))
                    return null;
            }

            return new ValidationResult(
                FormatErrorMessage(this.ErrorMessage)
            );
        }
    }

Example usage:

[ConfigRange(1)]
public int MyInt { get; set; }

[ConfigRange(1.1, ErrorMessage = "This one has gotta be between {1} and {2}!")]
public double MyDouble { get; set; }

The first example will return the default error message, and the second will return your custom error message. Both will use the range values defined in web.config.

Sign up to request clarification or add additional context in comments.

2 Comments

It's great to be appreciated. ;^> Thanks, and best of luck.
@rk1962, well, not so much the genius. I did a quick review of my code, and saw that my server-side validation tests were wrong. :^O I fixed the incorrect lines in the IsValid() function. Please make sure to apply those changes.
4

You won't be able to do that in the attribute declaration on the property as the values need to be known at compile time. The easiest way that I could see of doing this would be to derive an attribute class from RangeAttribute and set the property values to come from web.config in the derived class. Something like

public class RangeFromConfigurationAttribute : RangeAttribute
{
    public RangeFromConfigurationAttribute()
        : base(int.Parse(WebConfigurationManager.AppSettings["MinBalance"]), int.Parse(WebConfigurationManager.AppSettings["MaxDeposit"]))
    {

    }
}

May want to come up with a better name though :)

4 Comments

Thank you so much. I just created a class with the above code and it did not work. Am I missing something?
I'll see if I can put together an example, although counsellorben's code looks like it'd work - stackoverflow.com/users/624472/counsellorben
@Russ Cam, glad someone noticed my contribution. Though you still got the goodies. ;)
Thanks again Russ Cam. The solution given by counsellorben works great!
1

Thinking out loud here, but ConfigRange attribute dictates that the config must be present for this to work. Can you not write a static class that would read your values from web.config, app.config or whatever you see fit, and then use that static class in existing range attribute?

public static class RangeReader
{
    public static double Range1 
    {
        // Replace this with logic to read from config file
        get { return 20.0d; } 
    }        
}

Then annotate your property with:

[Range(ConfigReader.Range1, 25.0d)]

I know that static classes are bad and there might well be a good reason for not doing this,but I thought i'll give a go.

3 Comments

I didn't have any compilation errors with a view model, but didn't have a chance to test this out by passing a view model to the view. Can you remember why this didn't work?
I will try again and let you know the error message. Thanks!
I got compilation error: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.