chmorgan
chmorgan

Reputation: 89

TryValidateModel returning false despite a valid model

I have a controller which retrieves data from a form using model binding. I need to make some edits to the model before validating, so I use TryValidateModel as the docs suggest. But for some reason "Author" is always invalid even though "user" is not null. Really confused as to what's going on here, any help would be very much appreciated.

Debugger showing a valid model: valid model

Controller:

    [Authorize]
    [HttpPost]
    public async Task<IActionResult> Create([Bind("Id, Title, Content")] Post post)
    {
        var user = await userManager.GetUserAsync(User);
        post.Author = user;
        post.UpvotedBy.Add(user);

        if (post.Title != null && post.Content != null)
        {
            post.Title = post.Title.Trim();
            post.Content = post.Content.Trim();
        }

        if (TryValidateModel(post))  // Never true
        {
            context.Add(post);
            context.SaveChanges();

            return RedirectToAction("Details", new { id = post.Id });
        }
        else return View(post);
    }

Model:

public abstract class Entry
    {
        public Entry()
        {
            DateCreated = DateTime.Now;
            Upvotes = 1;
            Downvotes = 0;
            VoteScore = 1;

            Replies = new List<Comment>();
            SavedBy = new List<ApplicationUser>();
            HiddenBy = new List<ApplicationUser>();
            UpvotedBy = new List<ApplicationUser>();
            DownvotedBy = new List<ApplicationUser>();
        }

        public int Id { get; set; }

        [Required, StringLength(40000)]
        public string Content { get; set; }

        [Required, DataType(DataType.DateTime)]
        public DateTime DateCreated { get; set; }

        [Required]
        public int Upvotes { get; set; }
        [Required]
        public int Downvotes { get; set; }
        [Required]
        public int VoteScore { get; set; }

        [Required]
        public ApplicationUser Author { get; set; }
        [Required]
        public ICollection<Comment> Replies { get; set; }
        [Required]
        public ICollection<ApplicationUser> SavedBy { get; set; }
        [Required]
        public ICollection<ApplicationUser> HiddenBy { get; set; }
        [Required]
        public ICollection<ApplicationUser> UpvotedBy { get; set; }
        [Required]
        public ICollection<ApplicationUser> DownvotedBy { get; set; }
    }

    public class Post : Entry
    {
        [Required, StringLength(300, MinimumLength = 1)]
        public string Title { get; set; }
    }

Form:

@model Post
@{
    ViewData["Title"] = "New post";
}

<div class="container">
    <form asp-action="Create">
        <div class="form-group mb-3">
            <h3>Title</h3>
            <input asp-for="Title" class="form-control bg-dark text-white border-secondary" 
                   placeholder="Make it descriptive!"/>
            <span asp-validation-for="Title" class="text-danger"></span>
        </div>
        <div class="form-group mb-3">
            <h3>Content</h3>
            <textarea asp-for="Content" class="form-control bg-dark text-white border-secondary" 
                      placeholder="What do you have to say?" rows="5"></textarea>
            <span asp-validation-for="Content" class="text-danger"></span>
        </div>

        <a href="javascript:history.go(-1)" class="btn btn-outline-danger" role="button">
            <i class="fas fa-ban me-1"></i> Cancel
        </a>
        <button type="submit" class="btn btn-outline-primary">
            <i class="fas fa-save me-1"></i> Submit
        </button>
    </form>
</div>

Upvotes: 4

Views: 1023

Answers (1)

Guru Stron
Guru Stron

Reputation: 142253

Try clearing ModelState before calling TryValidate:

// your model update code
ModelState.Clear();
if (TryValidateModel(post))
{
    ....
}

Another option is to implement custom model binder to bind Author via UserManager before the validation happens.

Upvotes: 4

Related Questions