使用 Razor Pages 发送加载的对象以查看并从 POST 取回更改
Sending loaded object to view and getting back changes from POST using Razor Pages
执行 table 查询、加载具有属性的对象并将其发送回视图后,我想更新一些属性并将其 post 返回到蔚蓝 table.
我的 Razor 页面 cs 文件中有一个模型绑定,如下所示:
[BindProperty]
public TenantSettingsModel Settings { get; set; }
在我的 OnGetAsync
方法中,我按如下方式加载 Settings
对象:
public async Task<IActionResult> OnGetAsync()
{
Settings = _azureTableConn.GetTenantSettings(passSomeValue);
return Page();
}
在这个阶段我可以看到 Settings
正在加载 return 的属性到视图。我只挑选了几个要在表单中显示的属性,我想 post 将这两个更改(如果有的话)连同其他未更改的属性一起返回到 OnPostAsync
方法跟随并呈现一个视图:
public async Task<IActionResult> OnPostAsync()
{
var response = _azureTableconn.SetTenantSettings(Settings);
return Page();
}
当我检查 Settings
对象时,它有两个表单属性,但其他的为空。我可以简单地手动设置它们,但这似乎是一种浪费。
是否可以发送具有预定义属性的对象,然后在表单中更改其中两个,但从视图返回时保留未更改的属性?
我唯一的其他想法是创建隐藏的表单元素来保存模型的 [in] 绑定属性,但如果我必须这样做,我最好在我的 OnPostAsync
方法中设置它我认为.
我还没有看到您的页面或代码,但我只是向 CodeProject 做了一些 postings,可能会有帮助。看来您可能需要在 .cshtml 文件中使用表单元素。您的 [BindProperty] 属性将使您的 TenantSettingsModel 值可用于 UI 中的元素。你可能会看看 (ASP.NET Core Razor Pages Using EntityFramework Core with Enums as Strings - Part II)
我在这里使用 Entity Framework 核心。
在一个示例中,我在 Razor 页面上编辑了一个 Customer 对象,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");}
}
"code-behind",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 post(第 III 部分和第 IV 部分)中还有其他部分使用 Entity Framework 预加载以在 GET 中加载相关数据。 ([ASP.NET 核心 Razor 页面使用 EntityFramework 核心并将枚举作为字符串 - 第三部分和 ASP.NET Core Razor Pages Using EntityFramework Core with Enums as Strings - Part 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 对象的集合加载到 select/dropdown 中。所选项目通过表单传递给 OnPostAsync()。但是,只有一个隐藏控件指示目标项目。
我也遇到了类似的挑战,不确定我的方法是否正确。我没有在 DIV 中显示数据(待编辑),而是在 TABLE 中显示。我可以理解隐藏的 属性 是如何更新行的。就我而言,我在“编辑”页面上显示多行,但无法仅更新具有更新的行的数据库。
我的浏览页面是这样的
<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" asp-for=@item.ID /> </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>
后面的代码是这样的。字段在 OnPostAsync 方法中显示为 0。
[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");
}
执行 table 查询、加载具有属性的对象并将其发送回视图后,我想更新一些属性并将其 post 返回到蔚蓝 table.
我的 Razor 页面 cs 文件中有一个模型绑定,如下所示:
[BindProperty]
public TenantSettingsModel Settings { get; set; }
在我的 OnGetAsync
方法中,我按如下方式加载 Settings
对象:
public async Task<IActionResult> OnGetAsync()
{
Settings = _azureTableConn.GetTenantSettings(passSomeValue);
return Page();
}
在这个阶段我可以看到 Settings
正在加载 return 的属性到视图。我只挑选了几个要在表单中显示的属性,我想 post 将这两个更改(如果有的话)连同其他未更改的属性一起返回到 OnPostAsync
方法跟随并呈现一个视图:
public async Task<IActionResult> OnPostAsync()
{
var response = _azureTableconn.SetTenantSettings(Settings);
return Page();
}
当我检查 Settings
对象时,它有两个表单属性,但其他的为空。我可以简单地手动设置它们,但这似乎是一种浪费。
是否可以发送具有预定义属性的对象,然后在表单中更改其中两个,但从视图返回时保留未更改的属性?
我唯一的其他想法是创建隐藏的表单元素来保存模型的 [in] 绑定属性,但如果我必须这样做,我最好在我的 OnPostAsync
方法中设置它我认为.
我还没有看到您的页面或代码,但我只是向 CodeProject 做了一些 postings,可能会有帮助。看来您可能需要在 .cshtml 文件中使用表单元素。您的 [BindProperty] 属性将使您的 TenantSettingsModel 值可用于 UI 中的元素。你可能会看看 (ASP.NET Core Razor Pages Using EntityFramework Core with Enums as Strings - Part II)
我在这里使用 Entity Framework 核心。
在一个示例中,我在 Razor 页面上编辑了一个 Customer 对象,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");}
}
"code-behind",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 post(第 III 部分和第 IV 部分)中还有其他部分使用 Entity Framework 预加载以在 GET 中加载相关数据。 ([ASP.NET 核心 Razor 页面使用 EntityFramework 核心并将枚举作为字符串 - 第三部分和 ASP.NET Core Razor Pages Using EntityFramework Core with Enums as Strings - Part 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 对象的集合加载到 select/dropdown 中。所选项目通过表单传递给 OnPostAsync()。但是,只有一个隐藏控件指示目标项目。
我也遇到了类似的挑战,不确定我的方法是否正确。我没有在 DIV 中显示数据(待编辑),而是在 TABLE 中显示。我可以理解隐藏的 属性 是如何更新行的。就我而言,我在“编辑”页面上显示多行,但无法仅更新具有更新的行的数据库。
我的浏览页面是这样的
<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" asp-for=@item.ID /> </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>
后面的代码是这样的。字段在 OnPostAsync 方法中显示为 0。
[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");
}