question

0belix-1562 avatar image
0 Votes"
0belix-1562 asked ZhiLv-MSFT edited

Razor Pages PageRemote preventing asp-page-handler from being called

Hi,


I'm facing an odd issue here.


I have a page where i have setup a PageRemote attribute to validate a field, and on the same page, i have 2 buttons that each call a distinct handler using the asp-page-handler property (1 to update the content, the other to delete it).


If i remove the PageRemote validation, the handlers for both buttons are triggered as expected, but when i leave the PageRemote validation on the page, the buttons specific handlers are not called, although the PageRemote handler is correctly triggered.


Furthermore, when leaving the PageRemote validation on the page, if i force its validation to return false, then afterwards the buttons trigger their respective handler, but if i do not force it, then the behaviour is as described earlier, where the handlers are not triggered.


Can someone explain me if there is a catch on using these two things on the same page, and/or how to overcome this?


Below is a sample of the page code:


 public class EditModel : PageModel
 {
        
     private IConfiguration _configuration;

     [Required(ErrorMessageResourceType = typeof(ErrorMessages),
         ErrorMessageResourceName = nameof(ErrorMessages.SlugRequired))]
     [MinLength(3, ErrorMessageResourceType = typeof(ErrorMessages),
         ErrorMessageResourceName = nameof(ErrorMessages.SlugMinLength))]
     [MaxLength(128, ErrorMessageResourceType = typeof(ErrorMessages),
         ErrorMessageResourceName = nameof(ErrorMessages.SlugMaxLength))]
     [RegularExpression(@"^[0-9a-zA-Z_/-]*$", ErrorMessageResourceType = typeof(ErrorMessages),
         ErrorMessageResourceName = nameof(ErrorMessages.SlugAllowedCharacters))]
     [PageRemote(ErrorMessageResourceType = typeof(ErrorMessages),
         ErrorMessageResourceName = nameof(ErrorMessages.SlugDuplicate),
         AdditionalFields = "__RequestVerificationToken,GenericContentDTO.GenericContent.GenericContentId",
         HttpMethod = "post",
         PageHandler = "CheckSlug")]
     [Display(Name = "URL Title")]
     [BindProperty]
     public string Slug { get; set; }

     [TempData]
     public string FormResultMessage { get; set; }

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

     public EditModel(IConfiguration configuration)
     {
         _configuration = configuration;
     }

     public IActionResult OnGet(Guid genericContentId)
     {
         if (genericContentId.ToString() == "")
         {
             return NotFound();
         }

         ...
         Code to load content
         ...

         return Page();

     }

     public async Task<IActionResult> OnPostUpdate()
     {

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

         ...
         Code to update content
         ...

         return RedirectToPage(new { GenericContentId = GenericContentDTO.GenericContent.GenericContentId });

     }

     public IActionResult OnPostDelete()
     {

         ...
         Code to delete content
            

     }

     public JsonResult OnPostCheckSlug()
     {

         var token = HttpContext.Session.GetString("APIAuthorizationToken");

         CheckSlugDTO CheckSlug = new CheckSlugDTO
         {
             Slug = Slug,
             ContentId = GenericContentDTO.GenericContent.GenericContentId,
             Exists = true
         };

         CheckSlug = APICommunicationHelper.PostData<CheckSlugDTO>(CheckSlug, _configuration["AppConfigs:APIAddress"] + "api/CheckGenericContentSlugExistance", token);

         return new JsonResult(!CheckSlug.Exists);
     }
 }


And of the Razor Code:


 @page "{GenericContentId:Guid}"
 @model MyProject.Pages.Generic_Contents.EditModel
 @{
 }

 <form method="post" id="editForm" name="editForm" enctype="multipart/form-data">

 <h3>@TempData["FormResultMessage"]</h3>

 <ul class="nav nav-tabs">
     <li class="nav-item"><a class="nav-link active" data-toggle="tab" href="#main">Main</a></li>
     <li class="nav-item"><a class="nav-link" data-toggle="tab" href="#meta">Meta</a></li>
 </ul>

 <div class="tab-content">

     <div id="main" class="tab-pane active">
         <br />

         <div asp-validation-summary="ModelOnly" class="text-danger"></div>

         @Html.HiddenFor(model => model.GenericContentDTO.GenericContent.GenericContentId)

         <div class="form-group">
             <label asp-for="GenericContentDTO.GenericContent.Title" class="control-label"></label>
             <input asp-for="GenericContentDTO.GenericContent.Title" class="form-control" />
             <span asp-validation-for="GenericContentDTO.GenericContent.Title" class="text-danger"></span>
         </div>

         <div class="form-group">
             <label asp-for="Slug" class="control-label"></label>
             <input asp-for="Slug" class="form-control" />
             <span asp-validation-for="Slug" class="text-danger"></span>
         </div>

         <div class="form-group row">

             <div class="col-4">
                 <label asp-for="GenericContentDTO.MainImage" class="control-label"></label>
                 <input asp-for="GenericContentDTO.MainImage" type="file" class="form-control" />
             </div>

         </div>

         <div class="form-group">
             <label asp-for="GenericContentDTO.GenericContent.Summary" class="control-label"></label>
             @Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.Summary, new { @class = "form-control", @rows = 5 })
             <span asp-validation-for="GenericContentDTO.GenericContent.Summary" class="text-danger"></span>
         </div>

         <div class="form-group">
             <label asp-for="GenericContentDTO.GenericContent.ContentText" class="control-label"></label>
             @Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.ContentText, new { @class = "form-control editorHtml" })
         </div>

         <div class="form-group">
             <label asp-for="GenericContentDTO.GenericContent.IsActive" class="control-label"></label>
             @Html.CheckBoxFor(model => model.GenericContentDTO.GenericContent.IsActive)
         </div>

     </div>

     <div id="meta" class="tab-pane fade">
         <div class="form-group">
             <label asp-for="GenericContentDTO.GenericContent.MetaDescription" class="control-label"></label>
             @Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.MetaDescription, new { @class = "form-control", @rows = 5 })
             <span asp-validation-for="GenericContentDTO.GenericContent.MetaDescription" class="text-danger"></span>
         </div>

         <div class="form-group">
             <label asp-for="GenericContentDTO.GenericContent.MetaKeywords" class="control-label"></label>
             @Html.TextAreaFor(model => model.GenericContentDTO.GenericContent.MetaKeywords, new { @class = "form-control", @rows = 5 })
             <span asp-validation-for="GenericContentDTO.GenericContent.MetaKeywords" class="text-danger"></span>
         </div>
     </div>


     <div class="form-group text-right">
         <a asp-area="" asp-page="/Generic-Contents" class="btn btn-secondary">Cancel</a>
         <button type="submit" class="btn btn-danger" asp-page-handler="Delete">Delete Content</button>
         <button type="submit" class="btn btn-primary" asp-page-handler="Update">Update Content</button>
     </div>

 </div>

 </form>

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

I'm getting desperate with this.
I've already changed the Delete button to an Anchor, and subsequently to a Get request, and altered the Update button to call the default OnPost handler, and although this solves the issue, it actually just goes around it, and now that i need to add another Post action on the page, and have again the need to use the handlers, i'm back at square 1.
Please help!!!

dotnet-aspnet-core-generaldotnet-aspnet-core-razor
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

ZhiLv-MSFT avatar image
0 Votes"
ZhiLv-MSFT answered ZhiLv-MSFT edited

Hi @0belix-1562,

and altered the Update button to call the default OnPost handler,

What do you mean the default OnPost handler?

 <button type="submit" class="btn btn-primary" asp-page-handler="Update">Update Content</button>

Since you have set the asp-page-handler attribute, the html element should like this:

177374-image.png

After click the Update button, if the entered data is valid, it will redirect to the OnPostUpdate handler.

When, click the Update button, please make sure the PageRemote validation is valid,

[Note] Since this is the Edit page, perhaps there is not need to check whether the Slug is exist using PageRemote validation, because the data might be always exist. So, might be you just need to use a readonly or hidden field to store the primary key instead of using PageRemote validation to check it.

Generally, the PageRemote validation is used to create new entity and use to check whether the data is exist, check the following sample:

     public JsonResult OnPostCheckSlug(string slug, int GenericContentId)
     {
         var sluglist = new List<string>() { "Sslug1", "Sslug2" };

         var isexist = !sluglist.Contains(slug);
         return new JsonResult(isexist);
     }

If I the slug is "Sslug2", the isexist is false, and it will show the validation error in the page, prevent to go to the OnPostUpdate handler:

If I the slug is "Sslug3", the isexist is true, then, if I click the Update button, it will go to the OnPostUpdate handler:

177344-1.gif

i need to add another Post action on the page,

You can add a button, and use the asp-page-handler attribute to set the handler method, refer to the Update button.


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Best regards,
Dillion


image.png (5.3 KiB)
1.gif (1.3 MiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.