Validation using Regular Expression - c#

Im having some problems utilizing RegularExpression attribute in a ASP.net MVC project.
It seems to work client side, it goes away when it fits, however then upon post action, the model state is checked for being valid, it ends up posting error, that it must follow the regular expression.
I have tried theese following:
^[0-9]{1,2}/[0-9]{1,2}/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}$
^\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{1,2}$
Essentially it must catch 14/12/2014 14:20 as input.
Any ideas? I'm lost.
Model:
[Required]
[Display(Name = "TimeDisplay", ResourceType = typeof(Resources.Models.Log))]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy HH:mm}")]
[RegularExpression(#"^[0-9]{1,2}/[0-9]{1,2}/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}$")]
public DateTime Time { get; set; }
Controller Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Log log)
{
if (ModelState.IsValid)
{
db.Logs.Add(log);
db.SaveChanges();
TempData["Notification"] = AlertGenerator.GenerateAlert(AlertGenerator.Level.Success, "Success! Log Saved");
return RedirectToAction("Index");
}
return View(log);
}

As I know, MVC will use current CultureInfo (on server) to parse DateTime format, so you cannot directly binding "dd/MM/yyyy HH:mm" to your entity.
My solution is creating ViewModel then use DateTime.ParseExact(...) to parse the date:
Model:
[Display(Name = "TimeDisplay", ResourceType = typeof(Resources.Models.Log))]
[Required]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy HH:mm}")]
public DateTime Time { get; set; }
ViewModel
[Display(Name = "TimeDisplay", ResourceType = typeof(Resources.Models.Log))]
[Required]
public string Time { get; set; }
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(LogViewModel logViewModel)
{
if (ModelState.IsValid)
{
// convert from ViewModel to Entity Model
Log log = new Log(logViewModel);
// parse the time
log.Time = DateTime.ParseExact(logViewModel.Time, "dd/MM/yyyy HH:mm", null);
db.Logs.Add(log);
db.SaveChanges();
TempData["Notification"] = AlertGenerator.GenerateAlert(AlertGenerator.Level.Success, "Success! Log Saved");
return RedirectToAction("Index");
}
return View(log);
}

Related

MVC Remote validation - transfer of entered data

How to pass form data to remote mvc validation? Here is my model:
[Remote(action: "VerifyContinousOfReservation", controller: "Reservation",
AdditionalFields = nameof(EndOfReservation))]
public DateTime StartOfReservation { get; set; } = DateTime.Now;
[Remote(action: "VerifyContinousOfReservation", controller: "Reservation",
AdditionalFields = nameof(StartOfReservation))]
public DateTime EndOfReservation { get; set;} = DateTime.Now;
Here is my controller:
[AcceptVerbs("GET", "POST")]
public IActionResult VerifyContinousOfReservation(string StartOfReservation, string EndOfReservation)
{
var start = StartOfReservation;
var end = EndOfReservation;
return Json(true);
}
I want to know what user send from input and check that there is no reservation in this data range. But start and end is null.
I don't know if I'm taking the right approach.
I have a JSON file with reserved dates. I want to use validation to check if the date range specified by the user does not contain a reserved date.

ASP.NET CORE DataFormat is effecting Edit action

In my project I have properties that I would like to be displayed in dollar format.In my class I have it set up to do so
public class Worker{
public int Id {get;set;}
public string Name {get;set;}
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = true)]
public double Rev {get;set;}
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = true)]
public double Cost {get;set;}
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = true)]
public double Profit {get;set;}
}
This works and displays properly however when I go to the edit page All of the info is displayed in this format and I have to change every field from the dollar sign to the double or I get an error. Here is a screenshot showing.
Even if I want to change one field I have to rewrite every field from $50,000 to 50000.00. How can I fix it so in Edit I don't have to worry about fixing every field, and my dollar sign format will be displayed in Index or Details and so on? Here is my controller for Edit
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var worker = await _context.Workers.FindAsync(id);
if (worker == null)
{
return NotFound();
}
return View(worker);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Rev,Cost,Profit")] Worker worker)
{
if (id != worker.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(worker);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!WorkerExists(worker.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(worker);
}
At this point I am not concerned whether the currency format is displayed in edit view or just a number. I just do not want to have to convert every field from currency to a number in order to save the updates on one single property. How can I get rid of this error? Either leaving in this format or in number format.
Even if I want to change one field I have to rewrite every field from $50,000 to 50000.00. How can I fix it so in Edit I don't have to worry about fixing every field, and my dollar sign format will be displayed in Index or Details and so on?
IMO, you just need to set ApplyFormatInEditMode=false or remove it from model.
public class Worker
{
public int Id { get; set; }
public string Name { get; set; }
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = false)]
public double Rev { get; set; }
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = false)]
public double Cost { get; set; }
[DisplayFormat(DataFormatString = "{0:C0}", ApplyFormatInEditMode = false)]
public double Profit { get; set; }
}

Validator.TryValidateObject does not call Remote validation

I have a class with a remote validation data annotation as follows:
public partial class LuInspectionWindow
{
[Required]
public int InspectionWindowId { get; set; }
[Required]
public string Description { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime StartDate { get; set; }
[Required]
[Remote("ValidateWindowEndDate", "InspectionWindow", AdditionalFields = "StartDate")]
public DateTime EndDate { get; set; }
}
That calls this annotation:
[AcceptVerbs("Get", "Post")]
public IActionResult ValidateWindowEndDate(DateTime? endDate, DateTime? startDate)
{
int minWeeks = 8;
if (startDate.HasValue && endDate.HasValue
&& (endDate < startDate.Value.AddDays(minWeeks * 7)))
{
return Json(data: $"Inspection window end date must be at least {minWeeks} weeks after start date.");
}
return Json(data: true);
}
If I invalidate the object and then validate it as follows I only get one error, for the null Description (which is marked Required), the remote validation is not checked at all.
luInspectionWindow.EndDate = luInspectionWindow.StartDate.AddDays(1);
luInspectionWindow.Description = null;
var context = new ValidationContext(
luInspectionWindow, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(luInspectionWindow, context, results);
await _context.SaveChangesAsync();
The remote validation works fine from the view, so it is wired up correctly. Is Validator.TryValidateObject expected to check remote validations?

Validate nullable date time with fluent validation

In my web api project, I have model class RegisterModel, There is nullable date time, I want to validate input enter by user only when if user has enter the dob.
I'm using Json.Net Serializer
my model class
[Validator(typeof(RegisterModelValidator))]
public class RegisterModel
{
[JsonProperty("dob")]
public Nullable<DateTime> DOB { get; set; }
}
my validator
public class RegisterModelValidator : AbstractValidator<RegisterModel>
{
public RegisterModelValidator()
{
RuleFor(x => x.DOB).Must(BeAValidDate).WithMessage("Please enter valid date.");
}
private bool BeAValidDate(DateTime date)
{
if (date == default(DateTime))
return false;
return true;
}
private bool BeAValidDate(DateTime? date)
{
if (date == default(DateTime))
return false;
return true;
}
}
But when I pass value e.g: "dob":"123 APR 2015"
It ModelState.IsValid return false, But does not return validation message.
Validating DateTimes using fluent validation only does not seem to possible, as mentioned here. This answer seems to provide the most useful ways of actually validating invalid dates.
public ActionResult UpdateDateOfBirth(ModelClass model)
{
if (ModelState.IsValid)
{
// your logic
}
AddErrors(ModelState);
return View();
}
// in my case i have to be add in viewbag
private void AddErrors(ModelStateDictionary result)
{
ViewBag.ErrorMessages = result;
//foreach (KeyValuePair<string,System.Web.Mvc.ModelState> error in result)
//{
// //ModelState.AddModelError(error.Key,error.Value.Errors[0].ErrorMessage);
//}
}
// and you can add the validation message on
public class ModelClass
{
[StringLength(100, ErrorMessage = "Not a valid date of birth"]
[DataType(DataType.DateTime)]
[Display(Name = "Date of Birth")]
public string DateOfBirth{ get; set; }
}

Enable Display Format annotation from a ViewModel

I am trying to develop an application using MVC 5 and EF 6 code first approach.
I am new at software devolpment.
I would like to add this data annotation:
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
to a property named Birthdate from a ViewModels
An Example to illustrate:
public class StudentRegisterViewModel
{
public string LastName { get; set; }
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
}
The problem here is that the field EnrollmentDate does not recognize DisplayFormat annotations.
Can anyone help me, to handle it, please?
The [DisplayFormat] attribute is only used by DisplayFor and EditorFor. And not by the other helpers like TextBoxFor.
To format it further, you can create a css class and use jQuery to apply it:
$("EnrollmentDate").addClass("class-name")
To apply the format specified in [DisplayFormat] you need to access the value via Html.DisplayFor(). For example, in a view that would be:
#Html.DisplayFor(vm => vm.EnrollmentDate)
Write your own ValidationAttribute. To do this you override the IsValid() method with your own logic.
Add more validation if you wish:
public class MyAmazingValidationClass : ValidationAttribute
{
protected override bool IsValid(object value)
{
DateTime date;
bool parsed = DateTime.TryParse((string)value, out date);
//or maybe :
bool parsed = DateTime.ParseExact((string)value),"dd/MM/yyyy")
if(!parsed)
return false;
return true;
}
}
Then go to your awesome class and decorate it:
public string FirstMidName { get; set; }
[DataType(DataType.Date)]
[MyAmazingValidationClass(ErrorMessage="You made a big mistake right now!")]
public DateTime EnrollmentDate { get; set; }

Categories

Resources