Отправка загруженного объекта для просмотра и получение изменений из POST с помощью Razor Pages

После выполнения табличного запроса, загрузки объекта со свойствами и отправки его обратно в представление я хотел бы обновить некоторые свойства и опубликовать их обратно в таблицу Azure.

У меня есть привязка модели в моем CS-файле страницы Razor следующим образом:

[BindProperty]
public TenantSettingsModel Settings { get; set; }

В моем методе OnGetAsync я загружаю объект Settings следующим образом:

public async Task<IActionResult> OnGetAsync()
{
    Settings = _azureTableConn.GetTenantSettings(passSomeValue);
    return Page();
}

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

public async Task<IActionResult> OnPostAsync()
{
    var response = _azureTableconn.SetTenantSettings(Settings);
    return Page();
}

Когда я проверяю объект Settings, он имеет два свойства формы, но остальные равны нулю. Я мог бы просто установить их вручную, но это кажется пустой тратой.

Можно ли отправить объект с предопределенными свойствами, а затем изменить два из них в форме, но сохранить неизменные свойства, когда он вернется из представления?

Моя единственная другая мысль - создать скрытые элементы формы, чтобы удерживать связанные свойства модели, но если мне нужно это сделать, мне лучше установить это в моем методе OnPostAsync, я думаю.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
2 450
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я не видел ваших страниц или кода, но я только что сделал несколько сообщений в CodeProject, которые могут помочь. Похоже, вам может потребоваться использовать элемент формы в файле .cshtml. Атрибут [BindProperty] сделает ваши значения TenantSettingsModel доступными для элементов в вашем пользовательском интерфейсе. Вы можете посмотреть (Страницы Razor ASP.NET Core с использованием EntityFramework Core с перечислениями в виде строк - Часть II)

Здесь я использую Entity Framework Core.

В одном примере я редактирую объект Customer на странице Razor, Edit.cshtml ([Примечание: я использую скрытый ввод для передачи Customer.CustomerId методу PostAsync ()]):

@page
@model QuantumWeb.Pages.Customers.EditModel

@{
    ViewData["Title"] = "Edit";
}

<h2>Edit</h2>

<h4>Customer</h4>
<hr />
<div class = "row">
    <div class = "col-md-4">
        <form method = "post">
            <div asp-validation-summary = "ModelOnly" class = "text-danger"></div>
            <input type = "hidden" asp-for = "Customer.CustomerId" />
            <div class = "form-group">
                <label asp-for = "Customer.CustomerName" class = "control-label"></label>
                <input asp-for = "Customer.CustomerName" class = "form-control" />
                <span asp-validation-for = "Customer.CustomerName"
                    class = "text-danger"></span>
            </div>
            <div class = "form-group">
                <label asp-for = "Customer.CustomerContact"
                    class = "control-label"></label>
                <input asp-for = "Customer.CustomerContact" class = "form-control" />
                <span asp-validation-for = "Customer.CustomerContact"
                    class = "text-danger"></span>
            </div>
            <div class = "form-group">
                <label asp-for = "Customer.CustomerPhone"
                    class = "control-label"></label>
                <input asp-for = "Customer.CustomerPhone" class = "form-control" />
                <span asp-validation-for = "Customer.CustomerPhone"
                    class = "text-danger"></span>
            </div>
            <div class = "form-group">
                <label asp-for = "Customer.CustomerEmail"
                    class = "control-label"></label>
                <input asp-for = "Customer.CustomerEmail" class = "form-control" />
                <span asp-validation-for = "Customer.CustomerEmail"
                    class = "text-danger"></span>
            </div>
            <div class = "form-group">
                <input type = "submit" value = "Save" class = "btn btn-default" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page = "./Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Код программной части Edit.cshtml.cs:

using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using QuantumWeb.Data;
using QuantumWeb.Model;

namespace QuantumWeb.Pages.Customers
{
    public class EditModel : PageModel
    {
        private readonly QuantumDbContext _context;

        public EditModel(QuantumDbContext context)
        {
            _context = context;
        } // end public EditModel(QuantumDbContext context)

        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            } // endif (id == null)

            Customer =
                await _context.Customers
                    .FirstOrDefaultAsync(m => m.CustomerId == id);

            if (Customer == null)
            {
                return NotFound();
            } // endif (Customer == null)
            return Page();
        } // end public async Task<IActionResult> OnGetAsync(int? id)

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            } // endif (!ModelState.IsValid)

            _context.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            } // end try
            catch (DbUpdateConcurrencyException)
            {
                if (!CustomerExists(Customer.CustomerId))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                } // endif (!CustomerExists(Customer.CustomerId))
            } // end catch (DbUpdateConcurrencyException)

            return RedirectToPage("./Index");
        } // end public async Task<IActionResult> OnPostAsync()

        private bool CustomerExists(int id)
        {
            return _context.Customers.Any(e => e.CustomerId == id);
        } // end private bool CustomerExists(int id)

    } // end public class EditModel : PageModel

} // end namespace QuantumWeb.Pages.Customers

Надеюсь, это поможет.

У меня есть другие части в моем сообщении CodeProject (части III и IV), которые используют Entity Framework для загрузки связанных данных в GET. ([Страницы Razor ASP.NET Core с использованием EntityFramework Core с перечислениями в виде строк - Часть III и Страницы Razor ASP.NET Core с использованием EntityFramework Core с перечислениями в виде строк - Часть IV)

В части IV у меня есть страница CustomerProjectSkillAssign.cshtml:

@page "{id:int?}"
@model QuantumWeb.Pages.Customers.CustomerProjectSkillAssignModel
@{
    ViewData["Title"] = "Customer Project Skill Assignment";
}

<h2>Customer Project Skill Assignment</h2>
<hr />
<dl class = "dl-horizontal">
    <dt>
        @Html.DisplayNameFor(model => model.Project.ProjectId)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.Project.ProjectId)
    </dd>
    <dt>
        @Html.DisplayNameFor(model => model.Project.ProjectName)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.Project.ProjectName)
    </dd>
    <dt>
        @Html.DisplayNameFor(model => model.Customer.CustomerId)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.Customer.CustomerId)
    </dd>
    <dt>
        @Html.DisplayNameFor(model => model.Customer.CustomerName)
    </dt>
    <dd>
        @Html.DisplayFor(model => model.Customer.CustomerName)
    </dd>
</dl>
<div class = "row">
    <div class = "col-md-4">
        <form method = "post">
            <div asp-validation-summary = "ModelOnly" class = "text-danger"></div>
            <input type = "hidden" asp-for = "Project.ProjectId" />
            <div class = "form-group">
                <label asp-for = "SkillTitle.SkillCode" class = "control-label"></label>
                <select asp-for = "SkillTitle.SkillCode" class = "form-control" asp-items = "ViewBag.SkillCode"></select>
            </div>
            <div class = "form-group">
                <a asp-page = "./CustomerProjectSkills" asp-route-id = "Project.ProjectId">Project Skills</a> |
                <input type = "submit" value = "Assign" class = "btn btn-default" />
            </div>
        </form>
    </div>
</div>

Обратите внимание, что у меня есть только один скрытый элемент управления с Project.ProjectId. CustomerProjectSkillAssign.cshtml.cs:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using QuantumWeb.Data;
using QuantumWeb.Model;

namespace QuantumWeb.Pages.Customers
{
    public class CustomerProjectSkillAssignModel : PageModel
    {
        private readonly QuantumDbContext _context;

        public CustomerProjectSkillAssignModel(QuantumDbContext context)
        {
            _context = context;
        } // end public CustomerProjectSkillAssignModel(QuantumDbContext context)


        [BindProperty]
        public Project Project { get; set; }
        [BindProperty]
        public Customer Customer { get; set; }

        [BindProperty]
        public SkillTitle SkillTitle { get; set; }

        public async Task<IActionResult> OnGet(int? id)
        {
            if (id == null)
            {
                return NotFound();
            } // endif (id == null)

            Project = await _context.Projects
                .Include(p => p.Customer)
                .Include(p => p.ProjectSkills)
                    .ThenInclude(ps => ps.SkillTitle)
                    .FirstOrDefaultAsync(p => p.ProjectId == id);

            if (Project == null)
            {
                return NotFound();
            } // endif (Project == null)

            Customer = Project.Customer;

            ViewData["SkillCode"] = new SelectList(_context.SkillTitles, "SkillCode", "Title");

            return Page();
        }// end public async Task<IActionResult> OnGet(int? id)

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            } // endif (!ModelState.IsValid)

            ProjectSkill projectSkill = new ProjectSkill()
            {
                ProjectId = Project.ProjectId,
                SkillCode = SkillTitle.SkillCode
            };

            _context.ProjectSkills.Add(projectSkill);
            await _context.SaveChangesAsync();

            return RedirectToPage("./CustomerProjectSkills", new { id = Project.ProjectId });
        } // end public async Task<IActionResult> OnPostAsync()

    } // end public class CustomerProjectSkillAssignModel : PageModel

} // end namespace QuantumWeb.Pages.Customers

Активная загрузка извлекает объект Project и его объект Customer, а также его коллекцию ProjectSkills. У каждого ProjectSkill есть SkillTitle. Кроме того, я загружаю коллекцию доступных объектов SkillTitle в выпадающий список. Выбранный элемент передается в OnPostAsync () через форму. Однако есть только один скрытый элемент управления, указывающий на целевой проект.

Да, похоже, если вы дадите странице скрытое свойство для каждого входящего элемента, вы можете вытащить их в методе post, обратившись к объекту по имени.

Jason Shave 28.10.2018 17:27

У меня аналогичная проблема, и я не уверен, что мой подход правильный. Вместо того, чтобы отображать данные (подлежащие редактированию) в DIV, я показываю их в ТАБЛИЦЕ. Я могу понять, как скрытое свойство обновляет строку. В моем случае я показываю несколько строк на странице редактирования, но не могу обновить базу данных только для тех строк, которые имеют обновления.

Моя страница просмотра такая

<form method = "post">
    <div asp-validation-summary = "ModelOnly" class = "text-danger"></div>        
    <table class = "table">
        <thead>
            <tr>
                <th> @Html.DisplayNameFor(model => model.Fields[0].Name) </th>
                <th> @Html.DisplayNameFor(model => model.Fields[0].Value) </th>
                <th> @Html.DisplayNameFor(model => model.Fields[0].Confidence) </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model.Fields)
            {
                <tr>
                    <td> <input type = "hidden" [email protected] /> </td>
                    <td> @Html.DisplayFor(modelItem => item.Name) </td>
                    <td contenteditable='true'> @Html.DisplayFor(modelItem => item.Value) </td>
                    <td> @Html.DisplayFor(modelItem => item.Confidence) </td>
                </tr>
            }
        </tbody>
    </table>
    <div class = "form-group">
        <input type = "submit" value = "Save" class = "btn btn-primary" />
    </div>
</form>

И код, стоящий за этим, таков. Поля показывают 0 в методе OnPostAsync.

[BindProperty]
    public IList<FieldInfo> Fields { get; set; }
    public async Task<IActionResult> OnGetAsync(string id)
    {
        if (id == null)
        {
            return NotFound();
        }
        Fields = await _context.FieldInfo.Where(m => m.GUID == id).ToListAsync();

        if (Fields == null)
        {
            return NotFound();
        }
        return Page();
    }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        foreach (var p in Fields) // In this approach Fields shows as count=0
        {
            _context.Attach(p.Value).State = EntityState.Modified;
        }

        _context.Attach(Fields).State = EntityState.Modified; // In this approach Exception: The entity type 'List<FieldInfo>' was not found.

        await _context.SaveChangesAsync();            
        return RedirectToPage("./Index");
    }

Другие вопросы по теме