Asp.net MVC3 custom validator created using dataannotation showing messages in incorrect place - asp.net-mvc-3

I am using Asp.net MVC3, razor view engine and data annotation for model validation.
I have a form in which have to input Url details(Url and Description).Both fields are not required. But if i input one field other must be required.If i input description Url is required and is in correct format and if i enter Url then description is required.
I created a customvalidator for data annotation .It validates and output error message.
But my problem is error message generated by ValidationMessageFor is in incorrect place.
ie,if i enter description ,the required url message, is part of description.
I expect that message as part of ValidationMessageFor url field.
Can any one can help me? Thanks in advance. Folowing are the code i used
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class IsExistAttribute : ValidationAttribute, IClientValidatable
{
private const string DefaultErrorMessage = "{0} is required.";
public string OtherProperty { get; private set; }
public IsExistAttribute (string otherProperty)
: base(DefaultErrorMessage)
{
if (string.IsNullOrEmpty(otherProperty))
{
throw new ArgumentNullException("otherProperty");
}
OtherProperty = otherProperty;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, name, OtherProperty);
}
protected override ValidationResult IsValid(object value,ValidationContext validationContext)
{
if (value != null)
{
var otherProperty = validationContext.ObjectInstance.GetType()
.GetProperty(OtherProperty);
var otherPropertyValue = otherProperty
.GetValue(validationContext.ObjectInstance, null);
var strvalue=Convert.ToString(otherPropertyValue)
if (string.IsNullOrEmpty(strvalue))
{
//return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName),new[] { OtherProperty});
}
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata,ControllerContext context)
{
var clientValidationRule = new ModelClientValidationRule()
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "isexist"
};
clientValidationRule.ValidationParameters.Add("otherproperty", OtherProperty);
return new[] { clientValidationRule };
}
}
in model
[Display(Name = "Description")]
[IsExist("Url")]
public string Description { get; set; }
[Display(Name = "Url")]
[IsExist("Description")]
[RegularExpression("(http(s)?://)?([\w-]+\.)+[\w-]+(/[\w- ;,./?%&=]*)?", ErrorMessage = "Invalid Url")]
public string Url { get; set; }
and in view
<div class="editor-field">
#Html.TextBoxFor(m => m.Description )
#Html.ValidationMessageFor(m => m.Description)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Url)
#Html.ValidationMessageFor(m => m.Url)
</div>
unobstrusive validation logic
(function ($) {
$.validator.addMethod("isexist", function (value, element, params) {
if (!this.optional(element)) {
var otherProp = $('#' + params)
return (otherProp.val() !='' && value!='');//validation logic--edited by Rajesh
}
return true;
});
$.validator.unobtrusive.adapters.addSingleVal("isexist", "otherproperty");
} (jQuery));

You should make the validation the other way round. Change:
if (string.IsNullOrEmpty(otherPropertyValue))
{
//return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName),new[] { OtherProperty});
}
To:
if (string.IsNullOrEmpty(Convert.ToString(value)) && !string.IsNullOrEmpty(otherPropertyValue))
{
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
And remove if (value != null)
The field that will then get invalidated is the empty one, in the case the other one is filled.

Related

Complex Custom Validation in Foolproof Validation

I have implemented Complex custom Foolproof validation in my application from this link but sadly its not working.My requirement is simple,I have a input file for uploading an image and there should be a validation if the user chooses to upload file other than specified below
".jpg",".png",".gif",".jpeg"
Code is
[Required(ErrorMessage = "Please upload Photo", AllowEmptyStrings = false)]
[IsValidPhoto(ErrorMessage="Please select files of type .jpg,.png,.gif,.jpeg")]
public HttpPostedFileBase PhotoUrl { get; set; }
public class IsValidPhotoAttribute : ModelAwareValidationAttribute
{
//this is needed to register this attribute with foolproof's validator adapter
static IsValidPhotoAttribute() { Register.Attribute(typeof(IsValidPhotoAttribute)); }
public override bool IsValid(object value, object container)
{
if (value != null)
{
string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png", ".jpeg" };
var file = value as HttpPostedFileBase;
if (!AllowedFileExtensions.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
{
return false;
}
}
return true;
}
}
CSHTML is
#Html.TextBoxFor(m => m.PhotoUrl, new { #class = "form-control imgUpload",
#placeholder = "Please upload Photo", #id = "txtPhoto", #type = "file" })
#Html.ValidationMessageFor(m => m.PhotoUrl)
You will not be able to get client side validation unless you also create a script to add the rules. It is not necessary to use foolproof and the following method and scripts will give you both server and client side validation
public class FileAttachmentAttribute : ValidationAttribute, IClientValidatable
{
private List<string> _Extensions { get; set; }
private const string _DefaultErrorMessage = "Only file types with the following extensions are allowed: {0}";
public FileAttachmentAttribute(string fileExtensions)
{
_Extensions = fileExtensions.Split('|').ToList();
ErrorMessage = _DefaultErrorMessage;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
HttpPostedFileBase file = value as HttpPostedFileBase;
if (file != null)
{
var isValid = _Extensions.Any(e => file.FileName.EndsWith(e));
if (!isValid)
{
return new ValidationResult(string.Format(ErrorMessageString, string.Join(", ", _Extensions)));
}
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ValidationType = "fileattachment",
ErrorMessage = string.Format(ErrorMessageString, string.Join(", ", _Extensions))
};
rule.ValidationParameters.Add("extensions", string.Join(",", _Extensions));
yield return rule;
}
}
Scripts
$.validator.unobtrusive.adapters.add('fileattachment', ['extensions'], function (options) {
var params = { fileattachment: options.params.extensions.split(',') };
options.rules['fileattachment'] = params;
if (options.message) {
options.messages['fileattachment'] = options.message;
}
});
$.validator.addMethod("fileattachment", function (value, element, param) {
var extension = getExtension(value);
return $.inArray(extension, param.fileextensions) !== -1;
});
function getExtension(fileName) {
var extension = (/[.]/.exec(fileName)) ? /[^.]+$/.exec(fileName) : undefined;
if (extension != undefined) {
return extension[0];
}
return extension;
};
and then use it as
[FileAttachment("jpg|gif|png|jpeg")]
public HttpPostedFileBase PhotoUrl { get; set; }

MVC 3 Model binding and No parameterless constructor defined for this object

I created a view that was working wonderfully until I added some JQuery to support cascading drop downs. I believe in doing that, I broke the binding between the view and the model. I'm getting the error "No parameterless constructor defined for this object." when the form is submitted. The obvious solution would be to add a parameterless constructor, but I'm assuming that the postmodel will be null? Code Snippets below.
Thanks in Advance for your help.
View:
<script type="text/javascript">
$(document).ready(function () {
$("#ddlCategories").change(function () {
var iCategoryId = $(this).val();
$.getJSON(
"#Url.Content("~/Remote/SubCategoriesByCateogry")",
{ id: iCategoryId },
function (data) {
var select = ResetAndReturnSubCategoryDDL();
$.each(data, function (index, itemData) {
select.append($('<option/>', { value: itemData.Value, text: itemData.Text }));
});
});
});
function ResetAndReturnSubCategoryDDL() {
var select = $('#ddlSubCategory');
select.empty();
select.append($('<option/>', { value: '', text: "--Select SubCategory--" }));
return select;
}
});
...
<div class="editor-field">
#Html.DropDownList("iCategoryID", Model.Categories,"--Select Category--", new Dictionary<string,object>{ {"class","dropdowns"},{"id","ddlCategories"}})
#Html.ValidationMessage("iCategoryID")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SubCategories, "SubCategory")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.SubCategories, new SelectList(Enumerable.Empty<SelectListItem>(), "iSubCategoryID", "SubCategory",Model.SubCategories), "--Select SubCategory--", new { id = "ddlSubCategory" })
#Html.ValidationMessage("iSubCategoryID")
</div>
Controller:
[HttpPost]
public ActionResult Create(VendorCreateModel postModel)
{
VendorCreateEditPostValidator createValidator = new VendorCreateEditPostValidator(
postModel.iCategoryID,
postModel.iSubCategoryID,
postModel.AppliedPrograms,
m_unitOfWork.ProgramRepository,
new ModelStateValidationWrapper(ModelState));
if (ModelState.IsValid)
{
int categoryId = int.Parse(postModel.iCategoryID);
int subcategoryId = int.Parse(postModel.iSubCategoryID);
var programIds = postModel.AppliedPrograms.Select(ap => int.Parse(ap));
var programs = m_unitOfWork.ProgramRepository.GetPrograms(programIds);
Vendor vendor = postModel.Vendor;
vendor.Category = m_unitOfWork.CategoryRepository.GetCategory(categoryId);
vendor.SubCategory = m_unitOfWork.SubCategoryRepository.GetSubCategory(subcategoryId);
foreach (Program p in programs)
vendor.Programs.Add(p);
m_unitOfWork.VendorRepository.Add(vendor);
m_unitOfWork.SaveChanges();
return RedirectToAction("Index");
}
VendorCreateModel model = new VendorCreateModel(
postModel.Vendor,
postModel.iCategoryID,
postModel.iSubCategoryID,
postModel.AppliedPrograms,
User.Identity.Name,
m_unitOfWork.CategoryRepository,
m_unitOfWork.SubCategoryRepository,
m_unitOfWork.PermissionRepository);
return View(model);
}
RemoteController:
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult SubCategoriesByCateogry(int id)
{
System.Diagnostics.Debug.WriteLine(id);
var SubCategories = db.SubCategories
.Where(v => v.iCategoryID == id)
.OrderBy(v => v.sDesc)
.ToList();
var modelData = SubCategories.Select(v => new SelectListItem()
{
Text = v.sDesc,
Value = v.iSubCategoryID.ToString()
});
return Json(modelData, JsonRequestBehavior.AllowGet);
}
VendorCreateModel:
public class VendorCreateModel
{
public VendorCreateModel()
{
}
public VendorCreateModel(
Vendor vendor,
string categoryId,
string subcategoryId,
IEnumerable<string> appliedPrograms,
string username,
ICategoryRepository categoryRepository,
ISubCategoryRepository subcategoryRepository,
IPermissionRepository permissionRepository)
{
UserHasProgramsValidator programValidator = new UserHasProgramsValidator(username, permissionRepository);
var availablePrograms = programValidator.AvailablePrograms;
HashSet<Category> applicableCategories = new HashSet<Category>();
foreach (var p in availablePrograms)
foreach (var c in categoryRepository.GetCategoriesByProgram(p.iProgramID))
applicableCategories.Add(c);
this.Vendor = vendor;
this.AppliedPrograms = appliedPrograms;
this.Categories = new SelectList(applicableCategories.OrderBy(x => x.sDesc).ToList(), "iCategoryID", "sDesc");
this.SubCategories = new SelectList(subcategoryRepository.GetAllSubCategories().OrderBy(x => x.sDesc).ToList(), "iSubCategoryID", "sDesc");
if (!string.IsNullOrEmpty(categoryId))
{
int temp;
if (!int.TryParse(categoryId, out temp))
throw new ApplicationException("Invalid Category Identifier.");
}
this.iCategoryID = categoryId;
this.iSubCategoryID = subcategoryId;
this.ProgramItems = availablePrograms
.Select(p => new SelectListItem()
{
Text = p.sDesc,
Value = p.iProgramID.ToString(),
Selected = (AppliedPrograms != null ? AppliedPrograms.Contains(p.iProgramID.ToString()) : false)
});
}
public Vendor Vendor { get; set; }
public SelectList Categories { get; set; }
public SelectList SubCategories { get; set; }
public string iCategoryID { get; set; }
public string iSubCategoryID { get; set; }
public IEnumerable<SelectListItem> ProgramItems { get; set; }
[AtLeastOneElementExists(ErrorMessage = "Please select at least one program.")]
public IEnumerable<string> AppliedPrograms { get; set; }
}
I correct the issue and wanted to share in case someone else was banging their head against their desk like Ihave been. Basically I changed the dropdownlistfor to reflect:
#Html.DropDownListFor(model => model.iSubCategoryID, new SelectList(Enumerable.Empty<SelectListItem>(), "iSubCategoryID", "SubCategory",Model.SubCategories), "--Select SubCategory--", new Dictionary<string,object>{ {"class","dropdowns"},{"id","ddlSubCategory"},{"name","iSubCategoryID"}})
Assuming here the problem is in your VendorCreateModel, you either need to add a parameterless constructor or remove it, and create an instance in your action method and populate it by TryUpdateModel. Or parse the form using FormsCollection (not a fan).
You don't have the code for your viewmodel posted here but the basic assumption is that it will map.

pagination on filtered data getting lost on when clicked on second page in webgrid

I've created a WebGrid in an MVC3 web application. In my application sorting,filtering and paging are enabled.
Problem : Whenever a filtering is performed on the webgrid, it populates the filtered data to Webgrid. But if i click on the second page to see the remaining data filtered by Webgrid on my searched text, it doesnot show the remaining filtered data instead it shows complete list of all items in the grid.
How can i get the data in the second page after filtering my data in webgrid.
I've seen a similar question in the site, even it doesnot solved my problem.
My view: I've created a partial view to populate grid, which is called by a normal view. I've followed this tutorial to do that.
Controller: for the first time, Webgrid loads data by using another method in model so as to populate all the data from the database
My Partial View Code:
#{
ViewBag.Title = "listStudents";
Layout = "~/Views/Shared/_Layout.cshtml";
WebGrid grid = new WebGrid(Model, canPage: true, canSort: true, rowsPerPage: 3);
}
#grid.Pager(WebGridPagerModes.NextPrevious)
#grid.GetHtml( //Error at this line
htmlAttributes: new { id = "grdListStudents" },
fillEmptyRows: true,
headerStyle: "tblHeader",
tableStyle: "tablestyle",
mode: WebGridPagerModes.All,
firstText: "<< First",
previousText: "< Previous", nextText: "Next >",
lastText: "Last >>",
columns: new[]{
grid.Column("intID","SId",canSort:true),
grid.Column("strFirstName","Name",canSort:true,format:(item)=>item.strFirstName+" "+item.strLastName),
grid.Column("strPhone","Phone",canSort:true),
grid.Column("strEmail","Email",canSort:true),
}
)
Here is my code in controller:
public readonly IStudentInfo _istudentrepository;
public studentController( IStudentInfo _iStudentRepository)
{
this._istudentrepository = _iStudentRepository;
}
//To filter according to Searched Text
[HttpPost]
public ActionResult studentController(string txtSearch,string ddlTitle,FormCollection collect)
{
IEnumerable<Students> sList;
sList = _istudentlistrepository.getAllStudentsList();
if (txtSearch != "")
{
switch (ddlTitle)
{
case "intId":
int sId = Convert.ToInt32(txtSearch);
sList = sList.Where(b => b.intId == sId).ToList();
break;
case "strFirstName":
sList = sList.Where(b => b.strFirstName.ToLower().Contains(txtSearch.ToLower())).ToList();
break;
case "strPhone":
sList = sList.Where(b => b.strPhone.ToLower().Contains(txtSearch.ToLower())).ToList();
break;
case "strEmail":
sList = sList.Where(b => b.strEmail.ToLower().Contains(txtSearch.ToLower())).ToList();
break;
}
}
return PartialView("_grdListStudents", sList);
}
public ActionResult studentController(string sort, string sortdir, int? page)
{
int startPage = 0;
IEnumerable<Students> sList;
if (page.HasValue && page.Value > 0)
{
startPage = page.Value;
}
sList = _istudentrepository.GetList(startPage, PageSize, sort, sortdir);
return View(sList);
}
Code in Interface IStudentInfo:
public interface IStudentInfo
{
IEnumerable<Students> GetList(int intPage, int intRecords, string strSort, string sortdir);
}
Code in Model:
private MyEntity _entity;
public StudentListRepository(MyEntity Ent)
{
this._entity = Ent;
}
public IEnumerable<Students> GetList(int intPage, int intRecords, string strSort, string sortdir)
{
var finalresult = new Students();
var bidList = (from userInfo in _entity.tbl_UserInf
join user in _entity.tbl_User on userInfo.UserId equals user.UserId
select new Students()
{
intID=user.UserId,
strFirstName = user.FirstName,
strEmail = userInfo.EmailId,
intPhone=userInfo.Phone
}).OrderByDescending(m => m.intID);
finalresult.TotalResult = bidList.Count();
switch (strSort)
{
case "intID":
if (sortdir == "ASC")
{
sList = sList.OrderBy(r => r.Id);
}
else
{
sList= sList.OrderByDescending(r => r.Id);
}
break;
case "strFirstName":
if (sortdir == "ASC")
{
sList = sList.OrderBy(r => r.strFirstName);
}
else
{
sList= sList.OrderByDescending(r => r.strFirstName);
}
break;
case "strEmail":
if (sortdir == "ASC")
{
sList = sList.OrderBy(r => r.strEmail);
}
else
{
sList= sList.OrderByDescending(r => r.strEmail);
}
break;
//repeat same for phone
}
finalresult.lstStudents = sList.Skip(intPage * intRecords).Take(intRecords).ToList();
return sList.ToArray();
}
Your viewmodel should contain the list of items and the values for searchtext, pagesize, current page and total record count. I use a generic base class with these properties:
public class PagedViewModel<T> {
public IList<T> Items { get; set; }
public int PageSize { get; set; }
public int RowCount { get; set; }
public int Page { get; set; }
public int PageCount { get; set; }
public string sort { get; set; }
public string sortdir { get; set; }
}
Then your concrete Viewmodel looks just like this:
public class StudentsListViewModel : PagedViewModel<Students> {
public string Search { get; set; }
}
From your comments i read, you want to Ajax.BeginForm to update your grid via ajax.
Then you need two actions: One for the whole page and one for the grid (partial).
The first action returns the whole page:
public ActionResult Index() {
StudentsListViewModel model = queryStudents(1, 10, null);
return View(model);
}
The second action returns the partial view for the grid:
public ActionResult UpdateStudentsGrid(StudentsListViewModel model) {
model.Items = queryStudents(model);
return Partial("StudentsGrid", model);
}
A helper method queries the data and returns the filtered list:
private StudentsListViewModel queryStudents(int page, int rowsPerPage,
string search) {
StudentsListViewModel = new StudentsListViewModel {
Page = page,
PageSize = rowsPerPage,
Items = db.Students.Where(s => s.Name == search || search == null)
... add paging...;
};
// ToDo: set additional properties on model
return model;
}
The main page view contains your ajax form. The list will be rendered by the partial view:
#model StudentsViewModel
#using (Ajax.BeginForm("UpdateStudentsGrid",
new AjaxOptions { UpdateTargetId = "grid" })) {
#Html.TextboxFor(m => m.Search)
<input type=submit" />
<div id="grid">
#Html.Partial("StudentsGrid", Model);
</div>
}
The partial view looks something like this and renders just the grid:
#{
var grid = new WebGrid(Model.Items, canPage: true, canSort: true,
rowsPerPage: Model.PageSize);
}
#grid.GetHtml(...)
I havn't tested or compiled the code: it will probably not work as it stands here but it should get you started.
EDIT: The forgotten pager
For getting the pager links to work with your form, you can simple change the form method from POST to GET according to this article: http://www.mikepope.com/blog/DisplayBlog.aspx?permalink=2377
But i'm not sure how that works with an ajax form.
Another approach would be to intercept the clicks on the pager links and submit the form with method POST instead: http://forums.asp.net/t/1703486.aspx/1

client side validation in MVC3 not working

below is the code somehow client side validation is not working...I searched couple of questions in this forum and wrote this..
here is the custom validation attribute "startDateAttribute"
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class StartDateAttribute : ValidationAttribute, IClientValidatable
{
public StartDateAttribute ()
{
}
public override bool IsValid(object value)
{
var date = (DateTime)value;
if (date.Date >= DateTime.Now.Date)
{
return true;
}
return false;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "DateRange"
};
}
}
[CurrentDateAttribute(ErrorMessage = "select the correct date")]
public DateTime? StartDate { get; set; }
here is the JQuery code added
jQuery.validator.addMethod('DateRange', function (value, element, params) {
var d = new Date();
var currentDate = (d.getMonth()+1) + "/"+d.getDate()+ "/" + d.getFullYear() ;
return value >= currentDate;
});
// and an unobtrusive adapter
jQuery.validator.unobtrusive.adapters.add('DateRange', { }, function (options) {
options.rules['DateRange'] = true;
options.messages['DateRange'] = options.message;
});
One of the requirements of client side validation is that the ValidationType and the adapter name should match and should be lower case.
Change the ValidationType and adapter name to 'daterange' and check

drop down list validation message mvc

In my viewModel I have
public string Addressline1 { get; set; }
public List<SelectListItem> StateList
{
get
{
return State.GetAllStates().Select(state => new SelectListItem { Selected = false, Text = state.Value, Value = state.Value }).ToList();
}
}
In the view I have
#Html.DropDownListFor(model => model.StateCode, Model.StateList, "select")
when AddressLine1 is entered, then the statelist DropDownList selection is Required.How do I validate and show an error message when no state is selected in the Drop down list other than default "select" value?
Decorate your StateCode property with the [Required] attribute:
[Required(ErrorMessage = "Please select a state")]
public string StateCode { get; set; }
public IEnumerable<SelectListItem> StateList
{
get
{
return State
.GetAllStates()
.Select(state => new SelectListItem
{
Text = state.Value,
Value = state.Value
})
.ToList();
}
}
and then you could add a corresponding validation error message:
#Html.DropDownListFor(model => model.StateCode, Model.StateList, "select")
#Html.ValidationMessageFor(model => model.StateCode)
UPDATE:
Alright it seems that you want to conditionally validate this StateCode property depending on some other property on your view model. Now that's an entirely different story and you should have explained this in your original question. Anyway, one possibility is to write a custom validation attribute:
public class RequiredIfPropertyNotEmptyAttribute : ValidationAttribute
{
public string OtherProperty { get; private set; }
public RequiredIfPropertyNotEmptyAttribute(string otherProperty)
{
if (otherProperty == null)
{
throw new ArgumentNullException("otherProperty");
}
OtherProperty = otherProperty;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var property = validationContext.ObjectType.GetProperty(OtherProperty);
if (property == null)
{
return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "{0} is an unknown property", new object[]
{
OtherProperty
}));
}
var otherPropertyValue = property.GetValue(validationContext.ObjectInstance, null) as string;
if (string.IsNullOrEmpty(otherPropertyValue))
{
return null;
}
if (string.IsNullOrEmpty(value as string))
{
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
}
and now decorate your StateCode property with this attribute, like so:
public string AddressLine1 { get; set; }
[RequiredIfPropertyNotEmpty("AddressLine1", ErrorMessage = "Please select a state")]
public string StateCode { get; set; }
Now assuming you have the following form:
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.AddressLine1)
#Html.EditorFor(x => x.AddressLine1)
</div>
<div>
#Html.LabelFor(x => x.StateCode)
#Html.DropDownListFor(x => x.StateCode, Model.States, "-- state --")
#Html.ValidationMessageFor(x => x.StateCode)
</div>
<input type="submit" value="OK" />
}
the StateCode dropdown will be required only if the user entered a value into the AddressLine1 field.

Resources