Как я могу сохранить свою модель в моем представлении после OnPost? - PullRequest
0 голосов
/ 03 мая 2018

Я работаю над проектом с .Net Core и использую ASP Razor Pages. В моей модели у меня есть OnGet, который загружает все данные, которые мне нужны в моем представлении.

public IList<Projet> Projets { get; set; }
public ActionResult OnGet()
{
    Projets = _serviceSelect.getProjets();
    return Page();
}

Затем в моем OnPost, который активируется при отправке формы.

<form method="post">
    <div asp-validation-summary="All" class="text-danger"></div>
    <input type="radio" value="1" asp-for="LoginData.TypeCompte" />choice<br />
    Username: <input asp-for="LoginData.Username" /><br />
    Password: <input asp-for="LoginData.Password" /><br />
    Remember me: <input asp-for="LoginData.RememberMe" type="checkbox" /><br />
    <input asp-page-handler="connexion" type="submit" value="Login" />
    @Html.AntiForgeryToken()
</form>

Я хотел бы отобразить ошибку в своем представлении, используя мой ModelState.

public ActionResult OnPostConnexion()
{
    if (ModelState.IsValid)
    {
       // Do stuff 
    }
    else
    {
        ModelState.AddModelError("", "username or password is blank");
        return Page();
    }
}

Но когда я возвращаю Page (), это похоже на перезагрузку модели, и когда я пытаюсь получить доступ к моим данным, мои объекты равны нулю.

 Object reference not set to an instance of an object.
@foreach (var item in Model.Projets)

Как я могу обновить свое представление, не теряя свои данные, содержащиеся в модели?

Ответы [ 6 ]

0 голосов
/ 18 апреля 2019

Я решил эту проблему, заменив return Page(); на return this.OnGet(); в public ActionResult OnPostConnexion()

Таким образом любая логика в OnGet, которая заполняет свойства PageModel, используется повторно.

Итак, мой полный пример выглядит так:

    public IEnumerable<SelectListItem> CompanyListing { get; private set; }

    public async Task<IActionResult> OnGet()
    {
        if (!string.IsNullOrEmpty(this.ErrorMessage))
        {
            this.ModelState.AddModelError(string.Empty, this.ErrorMessage);
        }

        this.CompanyListing = await this.PopulateCompanyList();
        return this.Page();
    }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!this.ModelState.IsValid)
        {
            // Something failed. Redisplay the form.
            return await this.OnGet();
        }

        return this.RedirectToPage("/");
    }
0 голосов
/ 23 октября 2018

Я столкнулся с той же проблемой, и никто из предложенного решения не сработал. Я решил это простым использованием класса помощи, который сохраняет модель для меня. Решение не элегантное, но эффективное:)

public interface ISessionHelper
    {
        void AddRenewItem(string key, object item);
        object GetItem(string key);
    }
public class SessionHelper : ISessionHelper
{
    private readonly Dictionary<string, object> _sessionBag;

    public SessionHelper()
    {
        _sessionBag = new Dictionary<string, object>();
    }

    public void AddRenewItem(string key, object item)
    {
        if (_sessionBag.Keys.Contains(key)) _sessionBag.Remove(key);
        _sessionBag.Add(key, item);
    }

    public object GetItem(string key)
    {
        if (_sessionBag.Keys.Contains(key))
        {
            return _sessionBag[key];
        }
        return null;
    }
}

В моем методе get я добавляю элемент в словарь:

 public async Task<IActionResult> OnGetAsync(int? id)
    {
      ...
        _sessionHelper.AddRenewItem(this.ToString(), this);
        ...

    }

В своем методе записи я беру модель из словаря и назначаю необходимые свойства для текущей модели:

 public async Task<IActionResult> OnPostApplyGuess(int itemId)
    {
        GameModel model = (GameModel) _sessionHelper.GetItem(this.ToString());
        MyProp1= model.MyProp1;
        MyProp2 = model.MyProp2 ;
        MyProp3= model.MyProp3;

        if (!ModelState.IsValid)
        {
            return Page();
        }

        return Page();
    }

Не забудьте добавить сервис как Singleton:

services.AddSingleton<ISessionHelper, SessionHelper>();

Надеюсь, это кому-то помогло:)

0 голосов
/ 04 мая 2018

Вам нужно исправить две вещи в вашем коде:

Сначала необходимо пометить свойство Projets с помощью [BindProperty], например:

[BindProperty]
public IList<Projet> Projets { get; set; }

Затем вам нужно перекодировать страницу, чтобы поля Projets находились внутри тега form, чтобы они возвращались на страницу, а затем вам нужно переписать способ их вывода:

<form method="post">
    <div asp-validation-summary="All" class="text-danger"></div>
    <input type="radio" value="1" asp-for="LoginData.TypeCompte" />choice<br />
        Username: <input asp-for="LoginData.Username" /><br />
        Password: <input asp-for="LoginData.Password" /><br />
        Remember me: <input asp-for="LoginData.RememberMe" type="checkbox" /><br />
    <input asp-page-handler="connexion" type="submit" value="Login" />
    @Html.AntiForgeryToken()

    <!-- SEE REMARK BELOW! -->
    @{
        for (int i = 0; i < Model.Projets.Count; i++)
        {
            <input asp-for="@Model.Projets[i].FieldOne" />
            <br />
            <input asp-for="@Model.Projets[i].FieldTwo" />
        }
    }

</form>

ЗАМЕЧАНИЕ Вам необходимо отобразить поля в списке таким образом, чтобы они получили уникальные идентификаторы, чтобы ModelBinder мог получить их в Post. В моем случае я назвал одно поле FieldOne, и вот как оно отображается:

<input type="text" id="Projets_0__FieldTwo" name="Projets[0].FieldTwo" value="one">
0 голосов
/ 03 мая 2018

Попробуйте использовать TempData.

enter image description here


Подробнее: http://www.tutorialsteacher.com/mvc/tempdata-in-asp.net-mvc

0 голосов
/ 03 мая 2018

Когда вы вызываете «Page ()», это запрашивает новый объект Page, когда вы возвращаете этот объект, он будет пустым. Страницы и представления отличаются, как правило, с ASP вы будете использовать представления, на MSDN есть несколько хороших статей о различиях и причинах, но сейчас, только если вы измените Page () на View (), это должно решить проблему.

0 голосов
/ 03 мая 2018

Причина, по которой вы получаете ошибку ссылки на объект, заключается в том, что Model.Projects не был заполнен при возврате представления и поэтому не может повторяться в цикле foreach.

Исходя из существующего кода, вы можете заполнить модель еще раз, прежде чем вернуться на страницу.

public ActionResult OnPostConnexion()
{
    if (ModelState.IsValid)
    {
       // Do stuff 
    }
    else
    {
        Projets = _serviceSelect.getProjets();

        ModelState.AddModelError("", "username or password is blank");
        return Page();
    }
}

Лучшее решение будет:

public ActionResult OnPostConnexion(viewModel model)
{
    if (!ModelState.IsValid)
    {
       return View(model);
    }
    else
    {
        //do stuff
    }
}
...