Razor Page cshtml -
<body>
<div class="outerDivBlue">
<div id="AddCertHeader">
<span id="nameSearch">Certificates</span>
</div>
<div id="CertInfo">
<div style="padding-left:10px; width:800px" id="CertificatesGridDiv">
@(
Html.Kendo().Grid<CertificateDTO>().Name("CertificatesGrid").Size(ComponentSize.Medium)
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Columns(col =>
{
col.Bound(c => c.CertificateTypeDesc).Title("Type").Width(250);
col.Bound(c => c.NumberOrdered).Title("Ordered").Width(100).EditorTemplateName("QuantityEditor");
col.Bound(c => c.NumberIssued).Title("Issued").Width(100).EditorTemplateName("QuantityEditor");
})
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)//Here so all items are sent over together
.Read(r => r.Url(Url.Page("/CaseCreate/AddCertificates", "GetCertificateTypes")).Data("forgeryToken"))
.Update(u => u.Url(Url.Page("/CaseCreate/AddCertificates", "SaveCertificatesToSession")).Data("forgeryToken"))
//Note above - Update function gets called from pressing create file button outside of grid
.Model(m =>
{
m.Id(a => a.CertificateId);
m.Field(p => p.CertificateTypeDesc).Editable(false);
m.Field(p => p.NumberOrdered).Editable(true);
m.Field(p => p.NumberIssued).Editable(true);
}))
)
</div>
<form id="certificateForm" method="post" asp-page-handler="SaveCertificateInfoAndFile">
<div id="processTopRow">
<label asp-for="ProcessedBy" id="ProcessedByLabel">Processed By:</label>
<span><input asp-for="ProcessedBy" id="processedBy" name="ProcessedBy" style="width:215px;" /></span>
<span id="ProcessedDateLabel">Processed Date:</span>
<span id="processDate">
@Html.EditorFor(e => e.ProcessedDate)
</span>
</div>
<div>
<label asp-for="ProcessedLocation" id="ProcessedLocLabel">Processed Location:</label>
<span>
<input asp-for="ProcessedLocation" id="processedLocation" name="ProcessedLocation" style="width:540px;" />
</span>
</div>
</form>
</div>
</div>
<div class="solidLine"></div>
<div class="PrevNextButtons">
<span class="cancelbtn"><button id="textButton" data-role-"button" class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-base-cancel" type="button" role="button" aria-disabled="false" onClick="window.location.href='../admin/LandingPage.html'">Cancel</button></span>
<span class="PrevButtonWNext"><button id="textButton" data-role-"button" class="k-button k-button-md k-rounded-md k-button-solid k-button-solid-base" type="button" role="button" aria-disabled="false" onClick="window.location.href='@Url.Page("/CaseCreate/AddCertificates")'">Previous</button></span>
<span>
<button id="CertCreateBtn"
class="k-button-solid-base-create"
type="button"
role="button">
Create File
</button>
</span>
</div>
</body>
<script>
function forgeryToken() {
return kendo.antiForgeryTokens();
}
$("#CertCreateBtn").on("click", function () {
const grid = $("#CertificatesGrid").data("kendoGrid");
grid.closeCell();
alert(grid);
grid.dataSource.sync()
.done(function () {
document.getElementById("certificateForm").submit();
})
.fail(function (xhr) {
alert("Grid save failed: " + xhr.status + " " + xhr.responseText);
});
});
</script>cshtml.cs file:
public class AddCertificatesModel : PageModel
{
private readonly IDocumentService _documentService;
private readonly IMapper _mapper;
public DateOnly? ProcessedDate { get; set; }
public string ProcessedBy { get; set; }
public string ProcessedLocation { get; set; }
public CaseCreateSession curSession { get; set; }
public AddCertificatesModel(IDocumentService documentService, IMapper mapper)
{
_documentService = documentService;
_mapper = mapper;
}
public void OnGet()
{
curSession = HttpContext.Session.GetObjectFromJson<CaseCreateSession>("CaseCreateSession");
}
public async Task<IActionResult> OnPostGetCertificateTypes([DataSourceRequest] DataSourceRequest request)
{
var CertificateTypes = await _documentService.GetCertificateTypes();
return new JsonResult(CertificateTypes.ToDataSourceResult(request));
}
public async Task<IActionResult> OnPostSaveCertificatesToSession([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")] IEnumerable<CertificateDTO> CertificateList)
{
curSession = HttpContext.Session.GetObjectFromJson<CaseCreateSession>("CaseCreateSession");
curSession.CertificateGroup = new CertificateGroupDTO();
foreach(var certificate in CertificateList)
{
if (certificate.NumberOrdered > 0 || certificate.NumberIssued > 0)
{
curSession.CertificateGroup.CertificateList.Add(certificate);
}
}
HttpContext.Session.SetObjectAsJson("CaseCreateSession", curSession);
return new JsonResult(CertificateList.ToDataSourceResult(request, ModelState));
}
public async Task<IActionResult> OnPostSaveCertificateInfoAndFile()
{
if(!ModelState.IsValid)
{
return Page();
}
curSession = HttpContext.Session.GetObjectFromJson<CaseCreateSession>("CaseCreateSession");
foreach(var certificate in curSession.CertificateGroup.CertificateList)
{
certificate.ProcessedDate = ProcessedDate;
certificate.ProcessedLocation = ProcessedLocation;
certificate.ProcessedBy = ProcessedBy;
}
HttpContext.Session.SetObjectAsJson("CaseCreateSession", curSession);
return RedirectToPage("FileInfo", "SaveFileToDatabase");
}
}I am trying to make the Create File button call the grid's Update function and then submit the form through javascript. This is not working, it is giving me a "Grid Save failed 400 " error. And telling me bad request. Further looking into it its giving me these errors:
Exception thrown: 'Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException' in Microsoft.AspNetCore.Antiforgery.dll Exception thrown: 'Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException' in System.Private.CoreLib.dll
So its something with the antiforgery token. It is failing on the grid submit and never reaches the function on the backend.
I have worked for a long time with Copilot and is unable to provide me an answer and its likely a simple one line, but I do not
kknow what it looks like. Can you please assist?