1
votes

Sélectionnez Tag Helper dans ASP.NET Core MVC est vide après la publication lorsque vous devez revenir en arrière pour afficher

Eh bien, comme indiqué dans la description, lorsque je passe des données de l'obtention de ma méthode à la vue, tout va bien, mais, lorsque je clique sur le bouton Enregistrer et qu'il va au serveur pour valider si le modèle est valide, s'il est certainement valide tout va bien, mais, si le modèle n'est pas valide, il revient à la même vue (comme on suppose de le faire), mais il a perdu la collection quand il va au serveur, je considère que c'est tellement stupide de le remplir à nouveau, alors Existe-t-il un moyen de remplir le modèle d'un seul tyme pour la liste de sélection?.

J'ai ces actions

    public class EventViewModel
    {
        [Required]
        [FutureDate]
        public string Date { get; set; }

        [Required]
        [ValidTime]
        public string Time { get; set; }

        [Required]
        public byte TypeId { get; set; }

        [Required]
        [StringLength(5)]
        public string Venue { get; set; }

        public DateTime GetDateTime()
        {
            return DateTime.Parse($"{Date} {Time}");
        }

        public IEnumerable<SelectListItem> Types { get; set; }
    }

Ceci est mon point de vue

@model EcCoach.Web.ViewModels.EventViewModel
@{
    ViewData["Title"] = "Create";
}

<h1>Create</h1>
<form asp-action="Create">
    <p class="alert alert-info">
        All fields are <strong>required</strong>
    </p>

    <div class="form-group">
        <label asp-for="Venue"> </label>
        <input asp-for="Venue" class="form-control" placeholder="Enter a 
        venue" autofocus="autofocus">
        <span asp-validation-for="Venue"></span>
    </div>
    <div class="form-group">
        <label asp-for="Date"> </label>
        <input asp-for="Date" class="form-control" placeholder="eg 
        15/12/2017">
    </div>
    <div class="form-group">
        <label asp-for="Time"> </label>
        <input asp-for="Time" class="form-control">
    </div>
    <div class="form-group">
        <label asp-for="TypeId"> </label>
        <select asp-for="TypeId" asp-items="@Model.Types" class="form- 
            control">
            <option value="0">Choose One</option>
        </select>          
    </div>
    <button type="submit" class="btn btn-primary">
        Save
    </button>

</form>

Et enfin, voici mon ViewModel

public IActionResult Create()
{
    var types = _context.Types;

    var vm = new EventViewModel
    {
        Types = new SelectList(types, "Id", "Name")
    };

    return View(vm);
}

[Authorize]
[HttpPost]
public IActionResult Create(EventViewModel vm)
{
    //when it enter here **Types** comes empty  
    //if is not valid
    if (!ModelState.IsValid)
    {
            //var types = _context.Types;
            //**I WANT TO AVOID THIS**
            //vm.Types = new SelectList(types, "Id", "Name", vm.TypeId);
            return View(vm);
    }

    var ev = new Event
    {
        DateTime = vm.GetDateTime(),
        TypeId = vm.TypeId,
        Venue = vm.Venue,
        CoachId = User.FindFirstValue(ClaimTypes.NameIdentifier)
    };

    _context.Add(ev);

    _context.SaveChanges();
    return RedirectToAction("Index", "Home");

}


0 commentaires

3 Réponses :


0
votes

Il existe plusieurs façons de procéder. Le pire moyen est de stocker ces valeurs sur l'interface utilisateur dans les entrées masquées du formulaire, de sorte qu'elles seront ajoutées à la demande POST et vous les recevrez en tant que partie de la machine virtuelle dans votre méthode de publication. C'est mauvais parce que tout le monde peut les changer et cela peut être source de vulnérabilité. Vous ne devez jamais faire confiance aux commentaires des utilisateurs. La deuxième méthode consiste à stocker la machine virtuelle d'origine dans la session. Si vous n'êtes pas obligé d'être sans état, c'est la meilleure solution. Ainsi, dans l'action GET, vous devez stocker la machine virtuelle dans la session avant de retourner au client. Dans la demande de publication, vous recevrez la requestVM comme paramètre de méthode (à partir du message). Il ne contiendra que l'entrée utilisateur. Ensuite, vous devez obtenir la sessionVM à partir de la session, mapper l'entrée utilisateur de requestVM à sessionVM. Enfin, dans la sessionVM, vous aurez toutes les valeurs que vous aviez sur les champs GET + mis à jour à partir de l'entrée utilisateur. Ensuite, vous devez valider la sessionVM et utiliser ses valeurs pour mettre à jour la base de données. Si la validation échoue, vous devez renvoyer la vue avec la sessionVM comme modèle.


0 commentaires

0
votes

Essayez d'utiliser IMemoryCache pour enregistrer la liste des types dans le cache.

1.Dans startup.cs

public class MyController : Controller
{
    private readonly ApplicationDbContext _context;

    private IMemoryCache _cache;


    public MyController(ApplicationDbContext context, IMemoryCache memoryCache)
    {
        _context = context;
        _cache = memoryCache;

    }


    public IActionResult Create()
    {           
        var types = _context.Types.AsNoTracking().ToList();

        var vm = new EventViewModel
        {
            Types = new SelectList(types, "Id", "Name")
        };

        _cache.Set("types",types);//cache data
        return View(vm);
    }


    [HttpPost]
    public IActionResult Create(EventViewModel vm)
    {
        if (!ModelState.IsValid)
        {

           var types = _cache.Get<List<Type>>("types");//get cached data

           vm.Types = new SelectList(types, "Id", "Name", vm.TypeId);
           return View(vm);
        }


        return RedirectToAction("Index", "Home");

    }
}

2.ApplicationDbContext:

public DbSet<Type> Types {get;set;}

3.Contrôleur:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMemoryCache();
  services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}


2 commentaires

Dans ce cas, je ferai la même chose que je veux éviter, que de retourner à la base de données, donc, ce n'est pas applicable pour moi


@sgrysoft Salut, je connais votre considération maintenant.J'ai changé ma réponse qui utilise un IMemoryCache pour stocker les données.



0
votes

Ce cas peut également être vu dans la documentation de Microsoft.

Documentation

Une partie de l'exemple:

if (await TryUpdateModelAsync<Instructor>(
  newInstructor,
  "Instructor",
  i => i.FirstMidName, i => i.LastName,
  i => i.HireDate, i => i.OfficeAssignment))
{
  _context.Instructors.Add(newInstructor);                
  await _context.SaveChangesAsync();
  return RedirectToPage("./Index");
}
PopulateAssignedCourseData(_context, newInstructor);
return Page();

Si la validation échoue (ou autre chose), la méthode PopulateAssignedCourseData (_context, newInstructor); qui recrée les données est appelée à nouveau.

p >


0 commentaires