ASP.NET Core 3.1 ModelState validation fail for nullable - asp.net

The issue I am having, is that if you provide a null value for an item, that is nullable, the ModelState.IsValid flags a validation error saying "The value ParentID is not valid for ParentID."
I want [int?] to allow null.
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
[Route("common/menu-setting/add")]
public IActionResult AddMenuSetting(Menu model)
{
if (!ModelState.IsValid)
{
ViewData["ParentMenus"] = _commonRepository.GetParentMenus();
return View(model);
}
var returnValue = _commonRepository.AddMenu(model);
if (!returnValue)
{
return RedirectToAction("AddMenuSetting");
}
return RedirectToAction("MenuSetting");
}
Model:
public class Menu
{
public int MenuID { get; set; }
public string MenuName { get; set; }
public int? ParentID { get; set; }
public string ParentMenuName { get; set; }
public int SortGroup { get; set; }
public int Sort { get; set; }
}

Related

Why navigation property in one to many relationship in model makes ModelState Invalid

First of all I should say my code was working fine before transferring DataAccess (Db Context & Entity classes) to class library but after transfer The value of ModelState.Isvalid return's false because the navigation property (Category) in The Review model is null.
The problem will solved by adding an nullable annotation to Category property but my question is why this problem has arisen after using class library for DataAccess.
This is my Review Model :
public class Review
{
public int Id { get; set; }
public string Author { get; set; }
[MaxLength(500)]
public string Body { get; set; }
public int Rating { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
And this is my Category Model :
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Description { get; set; }
public List<Review> Review { get; set; }
}
This is my action :
public async Task<IActionResult> AddReview(Review review)
{
if (!ModelState.IsValid) return BadRequest("Enter required fields");
await _uReviewService.AddReview(review);
TempData["message"] = "success";
return RedirectToAction("Comments");
}

ASP.NET Core Model Binding from Route and Query String

I would like to perform a GET request such as https://localhost:12345/api/employees/1/calendar/2018/2019?checkHistoricalFlag=true
I have created this method in my controller which works as expected:
[AllowAnonymous]
[HttpGet("/api/employees/{clockNumber:int}/calendar/{yearFrom:int}/{yearTo:int}")]
public IActionResult Get(int clockNumber, int yearFrom, int yearTo, bool checkHistoricalFlag = false)
{
return Ok();
}
However I would prefer to use the following view model:
public class DetailsQuery
{
[Required]
public int? ClockNumber { get; set; }
[Required]
public int? YearFrom { get; set; }
[Required]
public int? YearTo { get; set; }
public bool CheckHistoricalFlag { get; set; } = false;
}
This binds the route parameters but ignores "checkHistoricalFlag" from the query string:
[AllowAnonymous]
[HttpGet("/api/employees/{clockNumber:int}/calendar/{yearFrom:int}/{yearTo:int}")]
public IActionResult Get([FromRoute]DetailsQuery query)
{
return Ok();
}
Removing [FromRoute] results in a 415 "Unsupported Media Type" error.
Is it possible to bind both the route parameters and query string values to a single view model or do I need to specify the query string values separately?
[AllowAnonymous]
[HttpGet("/api/employees/{clockNumber:int}/calendar/{yearFrom:int}/{yearTo:int}")]
public IActionResult Get([FromRoute]DetailsQuery query, bool checkHistoricalFlag = false)
{
return Ok();
}
The comment from Imantas pointed me to using [FromQuery] on the view model which now looks like:
public class DetailsQuery
{
[Required]
public int? ClockNumber { get; set; }
[Required]
public int? YearFrom { get; set; }
[Required]
public int? YearTo { get; set; }
[FromQuery]
public bool CheckHistoricalFlag { get; set; } = false;
}
The controller method is now:
[AllowAnonymous]
[HttpGet("/api/employees/{clockNumber:int}/calendar/{yearFrom:int}/{yearTo:int}")]
public ActionResult Get([FromRoute]DetailsQuery query)
{
return Ok();
}
Which works as expected.
Thanks for the pointer Imantas.

How to use mutiple models for one dbset

NET MVC expetrts!
I'm new in asp.NET MVC 4, so I got a simple problem not to know how to solve!
so this is my NotActivatedUsers model :
public class NotActivatedUser
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Required]
[DefaultValue(false)]
public bool isActive { get; set; }
[Required, DataType(DataType.EmailAddress)]
public string email { get; set; }
[Required]
public string activeCode { get; set; }
public DateTime createDate { get; set; }
}
and here is my SignUp model :
public class SignUpModel
{
[Key]
public int id { get; set; }
[EmailAddress(ErrorMessage = "Invalid Email!")]
public string email { get; set; }
}
and this in my dbset:
public class Context : DbContext
{
public DbSet<NotActivatedUser> notActivatedUser { get; set; }
}
My problem is " How to use my SignUp model to insert into NotActivatedUsers Dbset?
I tried this :
public class AccountController : Controller
{
private Context db = new Context();
[HttpPost]
[AllowAnonymous]
public ActionResult SignUp(SignUpModel signUpModel)
{
if (ModelState.IsValid)
{
db.notActivatedUser.Add(signUpModel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(signUpModel);
}
[AllowAnonymous]
public ActionResult SignUp()
{
return View();
}
}

ASP.NET MVC5 custom json model binder with html content

I used the FromJsonAttribute (created by Steve Sanderson), it's quite great, but sadly it doesn't pay attention to the AllowHtml attribute. I have the following model:
public class HKNewsPaperViewModel
{
public int Id { get; set; }
public string UserId { get; set; }
public string UserName { get; set; }
public string RPublisher { get; set; }
public string REditor { get; set; }
public string Title { get; set; }
public bool IsDraft { get; set; }
public bool IsNew { get; set; }
public List<HKNewsItemViewModel> NewsItems { get; set; }
public HKNewsPaperViewModel()
{
NewsItems = new List<HKNewsItemViewModel>();
}
}
public class HKNewsItemViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Link { get; set; }
[AllowHtml]
public string Body { get; set; }
}
In my controller I receive data this way:
[HttpPost]
public ActionResult New([FromJson] HKNewsPaperViewModel model)
{
return View();
}
FromJson attribute looks like this:
public class FromJsonAttribute : CustomModelBinderAttribute
{
private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();
public override IModelBinder GetBinder()
{
return new JsonModelBinder();
}
private class JsonModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
if (string.IsNullOrEmpty(stringified))
return null;
return serializer.Deserialize(stringified, bindingContext.ModelType);
}
}
}
My problem is that I can't pass html content where the AllowHtml attribute is there. Thanks a lot!

ASP.NET MVC 4 Code First Many to Many Adding to Collection

I am using ASP.NET MVC 4 code first pattern for database layer. I have a many to many relationship between UserProfile and Task. When I try to add a task to the the collection of tasks of a user, it's added but if I try to query it and see if it's there it's not showing up.
My model:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string SirName { get; set; }
public string Position { get; set; }
public string Email { get; set; }
public ICollection<TaskModels> Tasks {get; set; }
public bool? isActive { get; set; }
public UserProfile()
{
Tasks = new HashSet<TaskModels>();
}
}
public class TaskModels
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public ICollection<UserProfile> Employees { get; set; }
public int TimeNeeded { get; set; }
public int TimeWorked { get; set; }
public string Status { get; set; }
public bool isActive { get; set; }
public TaskModels()
{
Employees = new HashSet<UserProfile>();
}
}
public class WorkLogModels
{
public int Id { get; set; }
public UserProfile Author { get; set; }
public DateTime TimeBeganWorking { get; set; }
public int TimeWorkedOn { get; set; }
public TaskModels Task { get; set; }
public string Description { get; set; }
}
public class TimeTrackerDb : DbContext
{
public TimeTrackerDb() : base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<TaskModels> Tasks { get; set; }
public DbSet<WorkLogModels> WorkLogs { get; set; }
}
I try to check if a UserProfile already exists in a Task's Employees list and it's always empty.
[HttpPost]
public ActionResult Create(WorkLogModels worklogmodels)
{
var tasks = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).SingleOrDefault();
if (tasks == null)
{
return View(worklogmodels);
}
if (ModelState.IsValid)
{
var user = db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault();
var task = db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault();
WorkLogModels log = new WorkLogModels();
log.Description = worklogmodels.Description;
log.TimeBeganWorking = worklogmodels.TimeBeganWorking;
log.TimeWorkedOn = worklogmodels.TimeWorkedOn;
log.Author = user;
log.Task = task;
db.WorkLogs.Add(log);
if (!db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).First().Tasks.Any(x=> x.Name == worklogmodels.Task.Name))
{
db.UserProfiles.Where(x => x.UserId == WebSecurity.CurrentUserId).FirstOrDefault().Tasks.Add(task);
db.Tasks.Where(x => x.Name == worklogmodels.Task.Name).FirstOrDefault().Employees.Add(user);
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(worklogmodels);
}
I've been fighting with this for two days now.
Any help will be greatly appreciated
EDIT:
I am not sure if I made myself clear. In the Crate action for the WorkLog Controller I am trying to put the current user in the current task's collection and vice versa. It works correctly the first time, but then if I do it again it fails to skip the if statement and tries to add it once again and throws an exception : System.Data.SqlClient.SqlException. It's trying to add the same record to the intermediate table.

Resources