The LINQ2SQL code generator places an attribute on property fields similar to:
[Column(Storage="_Message", DbType="NVarChar(20)")]
It would be simple to extract and use this information at runtime:
public class Row
{
// normally generated by LINQ2SQL
[Column(Storage = "_Message", DbType = "NVarChar(20)")]
public string Message
{
get;
set;
}
// normally generated by LINQ2SQL
[Column(Storage = "_Property", DbType = "NVarChar(20) NOT NULL")]
public string Property
{
get;
set;
}
}
public class VarCharInfo
{
public int? MaxLen;
public bool IsNullable;
}
public static VarCharInfo GetVarCharInfo(PropertyInfo propertyInfo)
{
var attrib = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false)
.OfType<ColumnAttribute>()
.FirstOrDefault();
if (attrib == null || attrib.DbType == null)
{
return null;
}
var match = Regex.Match(attrib.DbType, @"VarChar\((?'len'\d+)\)(?'notnull' NOT NULL)?");
if (!match.Success)
{
return null;
}
var rvl = new VarCharInfo();
rvl.MaxLen = int.Parse(match.Groups["len"].Captures[0].Value);
rvl.IsNullable = match.Groups["notnull"].Success;
return rvl;
}
public static bool ValidateVarCharColumns(object dataObject)
{
bool success = true;
foreach (var propertyInfo in dataObject.GetType()
.GetProperties()
.Where(pi => pi.PropertyType == typeof(string)))
{
var vci = GetVarCharInfo(propertyInfo);
if (vci != null)
{
var currentValue = propertyInfo.GetGetMethod()
.Invoke(dataObject, null) as string;
if (currentValue == null)
{
if (!vci.IsNullable)
{
// more work: value is null but it shouldn't be
success = false;
}
}
else if (vci.MaxLen != null && currentValue.Length > vci.MaxLen)
{
// more work: value is longer than db allows
success = false;
}
}
}
return success;
}
static void UsageTest()
{
Row t = new Row();
t.Message = "this message is longer than 20 characters";
// t.Property is null
ValidateVarCharColumns(t); // returns false!
}
You could use the ValidationParameters
property to add custom parameters to the rule:
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "futuredate",
};
rule.ValidationParameters.Add("param1", "value1");
rule.ValidationParameters.Add("param2", "value2");
yield return rule;
}
which could be used in the adapter:
jQuery.validator.unobtrusive.adapters.add(
'futuredate',
[ 'param1', 'param2' ],
function (options) {
var param1 = options.params.param1; // shall equal 'value1'
var param2 = options.params.param2; // shall equal 'value2'
// TODO: use those custom parameters to define the client rules
}
);
UPDATE:
As requested in the comments section here's how you could pass those parameters to the custom validator rule function:
jQuery.validator.unobtrusive.adapters.add(
'futuredate',
[ 'param1', 'param2' ],
function (options) {
// simply pass the options.params here
options.rules['greaterThan'] = options.params;
options.messages['greaterThan'] = options.message;
}
);
jQuery.validator.addMethod('greaterThan', function (value, element, params) {
// params here will equal { param1: 'value1', param2: 'value2' }
return ...
}, '');
Best Answer
You can use the
RegularExpression
data annotation for the minimum check and use theStringLength
attribute for the maximum check. Javascript will execute regular expressions client side so they are nice and unobtrusive! You can only use oneRegularExpression
attribute per property, otherwise you could do both maximum and minimum using regular expression.Minimum of 5 characters
Maximum of 50 characters