c# - ASP.NET Core 5.0 - POST en modelo personalizado

CorePress2024-01-25  10

Lo hice según el tutorial de YouTube, pero desafortunadamente para mí se comporta de manera extremadamente extraña.

Escenario simple: agregar un comentario a una publicación.

    public class CommentViewModel
    {
        public Post Post { get; set; }
        public Comment Comment { get; set; }
    }
<p>@Model.Post.Title</p>
<p>@Model.Post.Body</p>

<form method="post" asp-action="NewComment">
    <input asp-for="Post.Id" hidden />
    <div class="border p-3">
        @*<div asp-validation-summary="ModelOnly" class="text-danger"></div>*@
        <div class="form-group row">
            <h2 class="text-info pl-3">Write new comment</h2>
        </div>
        <div class="form-group row">
            <label asp-for="Comment.Body"></label>
            <textarea asp-for="Comment.Body" class="form-control"></textarea>
            <span asp-validation-for="Comment.Body" class="text-danger"></span>
        </div>
    </div>
    <div class="form-group row">
        <div class="col-8 offset-2 row">
            <div class="col">
                <input type="submit" class="btn btn-info w-100" value="Create" />
            </div>
            <div class="col">
                <a asp-action="Index" class="btn btn-success w-100"><i class="fas fa-sign-out-alt"></i> Back</a>
            </div>
        </div>
    </div>
</form>
[HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult NewComment(CommentViewModel model)
        {
            if (ModelState.IsValid)
            {
                _service.AddNewComment(new Guid(), model.Post.Id, model.Comment.Body);
                return RedirectToAction("Index");
            }
            return View();
        }

Modelos:

public class Post
    {
        [BsonElement("id")]
        public Guid Id { get; set; }
        [BsonElement("title")]
        [Required]
        [MaxLength(64)]
        public string Title { get; set; }
        [BsonElement("post_body")]
        [Required]
        [Display(Name = "Post")]
        [MaxLength(256)]
        public string Body { get; set; }
    }

    public class Comment
    {
        [BsonElement("id")]
        public Guid Id { get; set; }
        [BsonElement("post_id")]
        public Guid PostId { get; set; }
        [BsonElement("comment_body")]
        [Required]
        [Display(Name = "Comment")]
        [MaxLength(128)]
        public string Body { get; set; }
    }

Cuando los campos no están completos, aparece una notificación roja, como debería. Pero una vez que se completan los campos y el usuario hace clic en crear, ModelState.IsValid sigue siendo falso y, por alguna razón, la aplicación intenta recargar la vista, pero devuelve una excepción en <p>@Model.Post.Title</p> Excepción de referencia nula.

Es un comportamiento extremadamente extraño. Agregar una nueva publicación es casi idéntico excepto <input asp-for="Post.Id" oculto /> (ya que no hay relaciones con nada más) y funciona perfectamente. Aquí las cosas están fallando.

Eliminar if (ModelState.IsValid) y devolver Vvista(); soluciona absolutamente el problema. Tanto la validación como la POST funcionan. Pero debería funcionar incluso con eso.

¿Alguna pista? Todas las leyes de la lógica dicen que debería funcionar. De lo contrario, me veré obligado a mantenerlo de la forma extraña.

¿Puedes mostrar la publicación y la clase de comentarios?

-mj1313

29 de marzo de 2021 a las 2:01

@mj1313 sí. Los comentarios deben tener al menos 15 c.caracteres largos, así que ahora estoy escribiendo cosas irrelevantes.

usuario15339955

29/03/2021 a las 9:30



------------------------------------

No veo nada extraño aquí. Funciona según su código. Pero puedes corregir un error:


  if (ModelState.IsValid)
    {
     _service.AddNewComment(new Guid(), model.Post.Id, model.Comment.Body);
   return RedirectToAction("Index");
   }
  return View(model);

en este caso no tendrás una excepción de referencia nula.

y por cierto estoy usando este código para encontrar qué no es válido en un ModelState:

public static string ValidModelState(ModelStateDictionary modelState)
        {
        var errorMessage = "";

            if (!modelState.IsValid)
            {
                foreach (var item in modelState.Values)
                {
                    foreach (var modelError in item.Errors)
                    {
                        errorMessage += "\n" + "Error: " + modelError.ErrorMessage;
                    }
                }
            }
            return errorMessage;
        }

Y usando esto en lugar de if (ModelState.IsValid):

var errorMessage = ValidModelState(ModelState);
if( !string.IsNullOrEmpty(errorMessage)).... errorMessage;

6

Pero en este caso la POST nunca sucederá, porque por razones desconocidas Model.State siempre no es válido, incluso cuando los datos de entrada están bien y pueden ir a la base de datos.

usuario15339955

28 de marzo de 2021 a las 8:44

Ok, tal vez esto me diga qué no es válido en el modelo. Pero si no es así, simplemente no dejaré ninguna protección dentro del controlador y rezaré para que no se rompa.

usuario15339955

28 de marzo de 2021 a las 9:53

Vale, estoy un paso más cerca de la solución. Tengo [Required] en ciertas propiedades en Post, y me asustó que no se usaran, incluso si no las necesito. Simplemente presione más <input asp-for="Post.Property" oculto /> y los errores desaparecieron. Excepto el último. Dice que el campo Publicar es obligatorio, excepto que la propiedad no existe.

usuario15339955

28/03/2021 a las 10:01

Usar depuradordentro de la utilidad. En el peor de los casos, simplemente busque una solución alternativa si (errormsg=="post...) está bien.

- Serge

28/03/2021 a las 10:05

Lo estoy intentando pero el campo Publicar simplemente no existe. Estoy preparando una solución. Si nadie publica una mejor solución directa, marcaré la suya como solución, ya que ayudó, pero tal vez haya una mejor manera.

usuario15339955

28/03/2021 a las 10:14



------------------------------------

Dice que el campo Publicar es obligatorio, excepto que la propiedad no existe.

Tienes un [Display(Name = "Post")] en la propiedad Post.Body, y creo que el modelo en la vista no tiene valor para el cuerpo de la publicación, por lo que la validación falló y aparece el mensaje de error. porque es El campo Publicación es obligatorio. Ve y compruébalo.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare