Web Api validating optional Url with DataAnnotations - c#

Is there a way to make the [Url] validation optional?
As an example
public class Company
{
[Required, StringLength(63, MinimumLength = 2)]
public string Name { get; set; }
[Url, StringLength(127)]
public string Url { get; set; }
}
The above validation works exactly as i intended it to with the exception that the Url property cannot be optional. I don't want the validation to throw an error if it is blank rather I just want it to validate only when a user enters a value.
UPDATE:
Taking into consideration the answer below from Hamid Shahid. I just added a condition to work around my issue until something better comes up:
//Making url validation optional, fix
if (company.Url == string.Empty) company.Url = null;

The URLAttribute validation returns true for null value. If the URL property has a value of NULL, it would be considered as a valid value. If you are setting it to an empty string, it would be considered invalid.
The code below show decompiled version of UrlAttribute class
// System.ComponentModel.DataAnnotations.UrlAttribute
[__DynamicallyInvokable]
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
string text = value as string;
if (UrlAttribute._regex != null)
{
return text != null && UrlAttribute._regex.Match(text).Length > 0;
}
return text != null && (text.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase) || text.StartsWith("ftp://", StringComparison.InvariantCultureIgnoreCase));
}

Related

Better way to return debug information instead of using lots of if-else

So I have a boolean method that is used to verify if a command is valid. This is used inside of an engine in which it verifies that the process can continue or not. This is the validation method:
private bool CommandIsValid(WC command)
{
if (command.Address == null ||
command.UserId < 0 ||
String.IsNullOrEmpty(command.CurrencyCode) ||
command.Amount < .01m ||
command.Address.PrimitiveAddress == null ||
String.IsNullOrEmpty(command.Address.Source) ||
String.IsNullOrEmpty(command.Address.PrimitiveAddress.City) ||
String.IsNullOrEmpty(command.Address.PrimitiveAddress.Country) ||
String.IsNullOrEmpty(command.Address.PrimitiveAddress.FirstName) ||
String.IsNullOrEmpty(command.Address.PrimitiveAddress.LastName) ||
String.IsNullOrEmpty(command.Address.PrimitiveAddress.Region) ||
command.Address.Created <= DateTime.MinValue)
{
return false;
}
return true;
}
And is called here inside of my method here:
if (!CommandIsValid(cmd))
{
_logger.Debug("Invalid command);
}
The issue is that I want to have some type of information regarding what failed validation. The best solution would have a list of what validations didn't pass, so I could relay that in my logging debugger. Obviously I could do this using a bunch of if-else statements, but it seems sloppy, as having a bunch of if else statements seems very poor style and I was wondering if there is any way in c# or in general I can do to avoid this.
Are you familiar with DataAnnotations and it's associated Validator class?
It would require modifications to your object.
public PrimitiveAddress
{
[Required]
public string City {get;set;}
}
and then you use it like so:
var context = new ValidationContext(command.Address.PrimitiveAddress);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(recipe, context, results);
if (!isValid)
{
foreach (var validationResult in results)
{
Console.WriteLine(validationResult.ErrorMessage);
}
}
if you've got a base command class you could probably add it in a more generic fashion. You can create your own validation attributes, use IValidatableObject for anything complex, customize the error messages
[Required(ErrorMessage="This is required.")]
Instead of returning a bool, return a container of bool values where first is the overall status False/True then each one reflects a condition of the above. If first element is False, then you check which condition (index) is the false. Looks like it is fixed in size then you may just agree on the sequence.
Something like this:
List<bool> YourFunction(YourDebuggerThing Input)
{
List<bool> Result = new List<bool>();
if (Input.Condition1 == false || Input.Condition2 == false || Input.Condition3 == false || Input.Condition4 == false || Input.Condition5 == false)
Result.Add(false); // first element is always the overall status
if(Input.Condition1 == false) Result.Add(false); else Result.Add(true); // element 2 is condition 1
if(Input.Condition2 == false) Result.Add(false); else Result.Add(true); // element 3 is condition 2
// ..
// ConditionN
return Result;
}
One idea might be to implement your checks within the Get/Set methods of the class' properties, using a custom exception. Such as;
public class PrimitiveAddresses
{
private string _city;
public string City
{
get
{
if(_city != null) {return _city;}
else {throw new CommandInvalidException("No valid city provided");}
}
set
{
_city = value;
}
}
}
public class CommandInvalidException: Exception
{
public CommandInvalidException(string message)
: base(message)
{
}
}
Then during you implementation, use a try/catch to handle the specific error;
public void foo()
{
try
{
if (String.IsNullOrEmpty(command.Address.PrimitiveAddress.City)){} // Ect
}
catch (CommandInvalidException e)
{
Console.WriteLine("Command invalid due to " + e.message);
// Or any other way you want to deal with the missing data
}
}
Hope it helps :)

How to include a condition to check if cell value in column is empty?

How can I include a condition to check a excel cell column value to see if it is empty or not? I've already mapped the column using linq mapping. When I go to grab the value whether it is null or not in the excel file, i'm getting object not set to reference error. Any help is appreciated. Here's what I got:
public class Test
{
public string excelValue { get; set; }
}
string excel = #"C:\excel.xls";
var excelFile = new ExcelQueryFactory(excel);
excelFile.AddMapping<ExcelClass>(p => p.excelValue, "Name");
var getvalue= excelFile.Worksheet<excelClass>("Sheet1").ToList();
return getvalue;
public string GetMyName(List<excelClass> nameValue)
{
//NEED TO CHECK BEFORE SENDING TO A STRING VARIABLE!!!!!
string name = nameValue[1].excelValue.ToString();
return name;
}
You can't call a method on a null object, whether it is ToString() or anythig else.
if(nameValue[1] != null)
{
if(nameValue[1].excelValue != null)
{
return nameValue[1].excelValue.ToString();
}
}

Same Remote Validation for 2 different properties in a model

I have 2 properties contractor1 and contractor2 in a model, how can I use a single remote validation for both of them
[Display(Name ="Contractor 1:")]
[Remote("ValidateContractor", "Contracts")]
public string Cntrctr1 {get; set;}
[Display(Name = "Contractor 2:")]
[Remote("ValidateContractor", "Contracts")]`enter code here`
public string Cntrctr2 {get; set;}
Remote Validation function in the Controller
public JsonResult ValidateContractor1(string Cntrctr)
{
var valid = Validations.ValidateContractor(Cntrctr);
if (!valid)
{return Json("Enter correct contractor", JsonRequestBehavior.AllowGet);}
else{return Json(true, JsonRequestBehavior.AllowGet);}
}
public static bool ValidateContractor(string CntrctrNM)
{
bool valid;
using (var entities = new CAATS_Entities())
{
var result = (from t in entities.PS_VENDOR_V
where (t.VNDR_1_NM).Equals(CntrctrNM)
select t).FirstOrDefault();
if (result != null)
{
valid = true;
}
else
{
valid = false;
}
}
return valid;
}
This doesn't work. Can you please help me with this?
When remote validation is called, the querystring key is the name of the field, e.g. in your case /Contracts/ValidateContractor1?Cntrctr1=foo. You need a more dynamic solution.
One way you can do this is to not have any parameters in ValidateContractor1 and just grab the first query string value instead. This isn't tested but should work for you:
public JsonResult ValidateContractor1()
{
// gets the name of the property being validated, e.g. "Cntrctr1"
string fieldName = Request.QueryString.Keys[0];
// gets the value to validate
string Cntrctr = Request.QueryString[fieldName];
// carry on as before
var valid = Validations.ValidateContractor(Cntrctr);
if (!valid)
{return Json("Enter correct contractor", JsonRequestBehavior.AllowGet);}
else{return Json(true, JsonRequestBehavior.AllowGet);}
}
Adding onto Rhumborls answer if you find his method not to work it might be because you're using forms; if this is the case you need to use the Form attribute instead of the QueryString as so.
public JsonResult ValidateContractor()
{
// gets the name of the property being validated, e.g. "Cntrctr1"
string fieldName = Request.Form.Keys[0];
// gets the value to validate
string Cntrctr = Request.Form[fieldName];
// carry on as before
var valid = Validations.ValidateContractor(Cntrctr);
if (!valid)
{return Json("Enter correct contractor", JsonRequestBehavior.AllowGet);}
else{return Json(true, JsonRequestBehavior.AllowGet);}
}

CompareAttribute for WPF?

Does anyone know of a CompareAttribute data annotation for WPF, or a way of achieving the same result in WPF?
For those that don't immediately know, CompareAttribute is a property data annotation for validating in WPF, it takes a string for a second property and returns true if the decorated property and the passed property match.
Basically I need to validate a password change form, to ensure the "retyped password" matches the new password, and do this with data annotations so that i can use the xaml validation template.
You can create your own custom validation logic by creating your own CustomValidationAttribute descrided here.
Try Custom Validator like this
public class EqualsValidationAttribute : ValidationAttribute
{
string propertyToCompare;
public EqualsValidationAttribute(string propertyToCompare)
{
this.propertyToCompare = propertyToCompare;
}
public EqualsValidationAttribute(string propertyToCompare,string errorMessage):this(propertyToCompare)
{
this.ErrorMessage = propertyToCompare;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var propInfo=validationContext.ObjectInstance.GetType().GetProperty(propertyToCompare);
if (propInfo != null)
{
var propValue=propInfo.GetValue(validationContext.ObjectInstance);
if(value!=null && propValue!=null && !string.IsNullOrEmpty(value.ToString()) && !string.IsNullOrEmpty(propValue.ToString()) //if either one is empty dont Validate
&& (value.ToString() != propValue.ToString()))
return new ValidationResult(ErrorMessage);
}
else
throw new NullReferenceException("propertyToCompare must be the name of property to compare");
return ValidationResult.Success;
}
}
and use it in Entity like this
[Required(ErrorMessage="Password Required")]
public string Password {
get { return password; }
set { password = value; RaisePropertyChanged("Password"); }
}
[EqualsValidationAttribute("Password", ErrorMessage = "Confirm password must be same as password")]
public string ConfirmPassword {
get { return confirmedpassword; }
set { confirmedpassword = value; RaisePropertyChanged("ConfirmPassword"); }
}
}

Unobtrusive validation C# MVC Razor

Is it possible to have unobtrusive validation to make a field required but only if other properties change?
For Example
[Required]
public Decimal Income {get; set;}
[Required]
public Decimal Tax {get; set;}
//Required if tax or income changes
public string ChangeReason {get; set;}
I thought about having multiple backing store fields and writing a Custom Validator to compare these, but wondered if anyone had a better suggestion?
Custom Validator is the way to go. I had to build something similar a while back.
I'd set up a hidden value - "Changed" - set it to true whenever the user mods the fields of interest.
Set a RequiredIf validator on the 2 properties of interest:
[RequiredIf("Changed", true, ErrorMessage = "Required")]
The code for a RequiredIf validator is shown below:
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
private RequiredAttribute _innerAttribute = new RequiredAttribute();
public string DependentProperty { get; set; }
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue)
{
this.DependentProperty = dependentProperty;
this.TargetValue = targetValue;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// get a reference to the property this validation depends upon
var containerType = validationContext.ObjectInstance.GetType();
var field = containerType.GetProperty(this.DependentProperty);
if (field != null)
{
// get the value of the dependent property
var dependentvalue = field.GetValue(validationContext.ObjectInstance, null);
// compare the value against the target value
if ((dependentvalue == null && this.TargetValue == null) ||
(dependentvalue != null && dependentvalue.Equals(this.TargetValue)))
{
// match => means we should try validating this field
if (!_innerAttribute.IsValid(value))
// validation failed - return an error
return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName });
}
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "requiredif",
};
string depProp = BuildDependentPropertyId(metadata, context as ViewContext);
// find the value on the control we depend on;
// if it's a bool, format it javascript style
// (the default is True or False!)
string targetValue = (this.TargetValue ?? "").ToString();
if (this.TargetValue.GetType() == typeof(bool))
targetValue = targetValue.ToLower();
rule.ValidationParameters.Add("dependentproperty", depProp);
rule.ValidationParameters.Add("targetvalue", targetValue);
yield return rule;
}
private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
{
// build the ID of the property
string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentProperty);
// unfortunately this will have the name of the current field appended to the beginning,
// because the TemplateInfo's context has had this fieldname appended to it. Instead, we
// want to get the context as though it was one level higher (i.e. outside the current property,
// which is the containing object (our Person), and hence the same level as the dependent property.
var thisField = metadata.PropertyName + "_";
if (depProp.StartsWith(thisField))
// strip it off again
depProp = depProp.Substring(thisField.Length);
return depProp;
}
}
Javascript:
/// <reference path="jquery-1.4.4-vsdoc.js" />
/// <reference path="jquery.validate.unobtrusive.js" />
$.validator.addMethod('requiredif',
function (value, element, parameters) {
var id = '#' + parameters['dependentproperty'];
// get the target value (as a string,
// as that's what actual value will be)
var targetvalue = parameters['targetvalue'];
targetvalue =
(targetvalue == null ? '' : targetvalue).toString();
// get the actual value of the target control
// note - this probably needs to cater for more
// control types, e.g. radios
var control = $(id);
var controltype = control.attr('type');
var actualvalue =
controltype === 'checkbox' ?
control.attr('checked').toString() :
control.val();
// if the condition is true, reuse the existing
// required field validator functionality
if (targetvalue === actualvalue)
return $.validator.methods.required.call(
this, value, element, parameters);
return true;
}
);
$.validator.unobtrusive.adapters.add(
'requiredif',
['dependentproperty', 'targetvalue'],
function (options) {
options.rules['requiredif'] = {
dependentproperty: options.params['dependentproperty'],
targetvalue: options.params['targetvalue']
};
options.messages['requiredif'] = options.message;
});
It is possible. You can write your own attribute, to do this exactly.
It basically requires two steps:
Write your own attribute, make it inherit ValidationAttribute amd implement IClientValidatable
Write a Jquery validation adapter to support it
A good working sample is described in this post.
I used a similar approach to create a dependency validation (one field could have values only if another was filled)

Categories