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

0belix 1 Reputation point
2022-02-23T16:28:21.263+00:00

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!!!

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,138 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Zhi Lv - MSFT 32,006 Reputation points Microsoft Vendor
    2022-02-24T03:23:25.773+00:00

    Hi @0belix ,

    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

    0 comments No comments