I use ASP.NET MVC4 in my solution. I have the ViewModel below where I would like to validate that the field EmergencyReason is filled only if the field Date is today. I try this:
public class LoadingViewModel
{
public DateTime Date { get; set; }
[RequiredIf("Date", Comparison.IsEqualTo, DateTime.Today)]
public string EmergencyReason { get; set; }
...
}
It doesn't work. The third argument of RequiredIf must be a constant expression, ...
Any idea how can I force the user to enter an EmergencyReason only if Date field is today?
Thanks.
You seem to be using some non-standard RequiredIf attribute which is not part of the standard ASP.NET MVC 4 package.
As you know C# allows you to only pass constant values to attributes. So one possibility is to write a custom attribute:
public class RequiredIfEqualToTodayAttribute: RequiredIfAttribute
{
public RequiredIfEqualToTodayAttribute(string field)
: base(field, Comparison.IsEqualTo, DateTime.Today)
{
}
}
and then:
public class LoadingViewModel
{
public DateTime Date { get; set; }
[RequiredIfEqualToToday("Date")]
public string EmergencyReason { get; set; }
...
}
C# doesn't support DateTime literals, a workaround for this is to use a String like this, but it won't resolve your problem. I suggest you move the validation code inside the Controller and return a ModelState.AddModelError("EmergencyReason", "Emergency Reason is required")
Related
I am getting all customers and including their linked operator.
The only catch is a customer can exist without an operator.
The problem I am having is when i try include the operator any customer that doesn't have a linked operator is not retrieved is there a way to still retrieve all my customers and if thy do not have an operator just have the operator object within the customer be null?
-get all customers method
public List<Customer> GetAllWithRelations()
{
return Context.Set<Customer>()
.Include(cp => cp.Operator).ToList();
}
-Cusomer object
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int? OperatorId { get; set; }
[ForeignKey("OperatorId")]
public virtual Operator Operator { get; set; }
}
-Operator Object
public class Operator
{
public int Id { get; set; }
public string Name { get; set; }
}
Although you did not specify a tag for this, by using the .Include I'm guessing it's a EntityFramework Core linq which is breaking.
I've came across the same case on EF whenever the relationship is not set to allow nulls. So, for instance, your mapping might be explicitly setting it to be required or somehow you're not setting it and EF defaults are stablishing a required map between Customer and Operator.
Just set it to optional wherever you're building your model mappings and you'll get the desired behavior.
See: https://learn.microsoft.com/en-us/ef/core/modeling/required-optional
I'm having some troubles with validation on my application.
Let's say I've the following models:
public class Company
{
public int id { get; set; }
[Required]
public String Name { get; set; }
public String Location { get; set; }
public List<Contacts> Contacts { get; set; }
}
public class Contact
{
public int id { get; set; }
[Required]
public String Name { get; set; }
[DataType(DataType.EmailAddress)]
public String Email { get; set; }
public String Telephone { get; set; }
public String Mobile { get; set; }
}
Now in my company create view I've two buttons, one to add contacts to the company, and another one to create the new company.
I detected which button was used in my controller like this (both buttons are named "button"):
[HttpPost]
public ActionResult Create(String button, FormCollection collection)
{
if(button == "AddContact")
{
AddContact(collection);
}
else
{
CreateCompany(collection);
}
}
While it's being created the object that represents the company that it's being create is stored in the session (for example HttpContext.Session["company"] = company;)
Now the problem is that if, for example, I try to add a contact without first specifying the company name, i get a validation error because the company name is required, which shouldn't happen because the user might want to add the contacts before adding the company info. Or if I try to save the company, I also get a validation error, because usually when saving the "add contact" form is empty, which means that the contact name (which is required as well) was not specified.
What I want to know is that if it's possible to validate the contact properties only when the addContact button is used, and validate the company properties only when the createCompany button is pressed.
For now i only need to do this serve-side, but if anyone has a solution to do this client-side as well i would appreciate the help.
You could trigger your own validation on the individual objects using
Validator.TryValidateObject(Object, ValidationContext, ICollection)
You can provide conditional validation using the Entity Framework by overriding DbEntityValidationResult in the DbContext. When this validation occurs in the DbContext you can access other entities. When validating a contact you can check the company too. For example:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
ValidateContact(result);
return result;
}
private void ValidateContact(DbEntityValidationResult result)
{
var contact= result.Entry.Entity as Contact;
if (contact!= null && contact.ContactId != 0)
{
// Add validation code here, such as:
if(!string.IsNullOrEmpty(contact.Company.Name){
result.ValidationErrors.Add(
new DbValidationError(
"Contact",
"Company name cannot be null or empty when validating contacts.")
);
}
}
}
See Julia Lerman's Programming Entity Framework: DbContext http://www.amazon.com/Programming-Entity-Framework-Julia-Lerman/dp/1449312969 for more details.
I'm after a little help with the techniques to use for Databinding. It's been quite a while since I used any proper data binding and want to try and do something with the DataGridView. I'm trying to configure as much as possible so that I can simply designed the DatagridView through the form editor, and then use a custom class that exposes all my information.
The sort of information I've got is as follows:
public class Result
{
public String Name { get; set; }
public Boolean PK { get; set; }
public MyEnum EnumValue { get; set; }
public IList<ResultInfos> { get; set; }
}
public class ResultInfos { get; set; }
{
public class Name { get; set; }
public Int Value { get; set; }
public override String ToString() { return Name + " : " Value.ToString(); }
}
I can bind to the simple information without any problem. I want to bind to the EnumValue with a DataGridViewComboBoxColumn, but when I set the DataPropertyName I get exceptions saying the enum values aren't valid.
Then comes the ResultInfo collection. Currently I can't figure out how to bind to this and display my items, again really I want this to be a combobox, where the 1st Item is selected. Anyone any suggestions on what I'm doing wrong?
Thanks
Before you bind your data to the grid, first set the DataGridViewComboBoxColumn.DataSource like this...
combo.DataSource = Enum.GetValues(typeof(YourEnum));
I generally do this in the constructor after InitializeComponent(). Once this is set up you will not get an exception from the combo column when you bind your data. You can set DataGridViewComboBoxColumn.DataPropertyName at design time as normal.
The reason you get an exception when binding without this step is that the cell tries to select the value from the list that matches the value on the item. Since there are no values in the list... it throws an exception.
I have a View with a table representing an employee's timesheet. Days across the top, projects down the side, with each day/project intersection containing two values for regular hours and overtime.
The (simplified) class definitions for the page model are:
public class TimesheetFormModel {
public List<Project> Projects;
// other things...
}
public class Project {
public string Name;
public List<WorkUnit> WorkUnits;
}
public class WorkUnit {
public DateTime Date;
public decimal RegularHours;
public decimal OvertimeHours;
}
The form elements on the page are named as follows in an attempt to get the DefaultModelBinder to pick up on them.
model.Projects[0].Name // "New Project"
model.Projects[0].WorkUnits[0].Date // "5/23/2009 12:00:00 AM"
model.Projects[0].WorkUnits[0].RegularHours // 0
model.Projects[0].WorkUnits[0].OvertimeHours // 0
model.Projects[0].WorkUnits[1].Date // "5/24/2009 12:00:00 AM"
model.Projects[0].WorkUnits[1].RegularHours // 0
model.Projects[0].WorkUnits[1].OvertimeHours // 0
model.Projects[0].WorkUnits[2].Date // "5/25/2009 12:00:00 AM"
model.Projects[0].WorkUnits[2].RegularHours // 0
model.Projects[0].WorkUnits[2].OvertimeHours // 0
// etc.
When the view is submitted however, the model parameter isn't being completely populated. model.Projects contains projects, but the Project's WorkUnits field is empty. Does the DefaultModelBinder support nested collections like I'm trying to do? If not, what should I do?
I eventually figured out why DefaultModelBinder wasn't picking up on the properties of WorkUnit: Because they weren't properties, they were fields. DefaultModelBinder only works with properties. Changing the class definition of WorkUnit and Project to use fields made everything click:
public class Project {
public IList<WorkUnit> WorkUnits { get; set; }
public string Name { get; set; }
}
public class WorkUnit {
public DateTime Date { get; set; }
public decimal RegularHours { get; set; }
public decimal OvertimeHours { get; set; }
}
(Note: The source code in the original question had Project.Name defined as a field, in my actual code it was a property. This is why the Projects list was getting populated but WorkUnits wasn't.)
I'm serializing class which contains DateTime property.
public DateTime? Delivered { get; set; }
After serializing Delivered node contains DateTime formatted like this:
2008-11-20T00:00:00
How can I change this property to make it look like this:
2008-11-20 00:00:00
Thanks in advance
The hack I use for odd formatting during XmlSerialization is to have a special property that is only used during XmlSerialization
//normal DateTime accessor
[XmlIgnore]
public DateTime Delivered { get; set; }
//special XmlSerialization accessor
[XmlAttribute("DateTime")]
public string XmlDateTime
{
get { return this.Delivered.ToString("o"); }
set { this.Delivered = new DateTime.Parse(value); }
}
Take a look at XmlAttributeOverrides class.