Matthew Miller
Matthew Miller

Reputation: 605

Why are my Razor Pages forms not posting to the correct handlers?

I'm building a web application using ASP.NET Core 3.0. I have a model called Article. I am having problems in two parts of my application where neither editing nor deleting an article are calling the correct POST method handlers.

My Article class is defined as follows in the namespace Models:

Models/Articles.cs

public class Article
{
  public int Id { get; set; }

  [Required]
  [StringLength(32)]
  public string Title { get; set; }

  [StringLength(512)]
  public string Description { get; set; }

  public string Content { get; set; }
}

Editing

I have a shared partial view called _Editor.cshtml. It is defined as follows:

Pages/Articles/_Editor.cshtml

@model Models.Article

<div class="form-group">
    <label asp-for="Title" class="control-label col-xs-4 col-md-2"></label>
    <input asp-for="Title" class="form-control col-xs-8 col-md-10" />
    <span asp-validation-for="Title" class="text-danger col"></span>
</div>

<div class="form-group">
    <label asp-for="Description" class="control-label col-xs-4 col-md-2"></label>
    <textarea asp-for="Description" class="form-control col-xs-8 col-md-10" style="height:4em"></textarea>
    <span asp-validation-for="Description" class="text-danger col"></span>
</div>

<hr />

<div class="form-group">
    <label asp-for="Content" class="control-label col-xs-4 col-md-2"></label>
    <textarea asp-for="Content" class="form-control col-xs-8 col-md-10" style="height:16em"></textarea>
    <span asp-validation-for="Content" class="text-danger col"></span>
</div>

I use this partial view from inside both the Edit.cshtml and Create.cshtml files as follows:

Pages/Articles/Edit.cshtml

@page
@model Pages.Articles.EditModel

<form method="post">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <input type="hidden" asp-for="Article.Id" />
    <partial name="_Editor" model="Model.Article" />

    <div class="form-group">
        <input type="submit" value="Save" class="btn btn-primary" />
    </div>
</div>

</form>

Pages/Articles/Create.cshtml

@page
@model Pages.Articles.CreateModel

<form method="post">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <partial name="_Editor" model="Model.Article" />

    <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary" />
    </div>
</form>

Both of these Razor pages have standard scaffolded code-behind (.cshtml.cs) files. The create page works successfully but the edit page does not actually save the edits.


Deleting

On my View.cshtml Razor Page, I want to have an article delete dialog that can be used in other pages throughout the project. I use the Delete.cshtml partial view for this. It's code is as follows:

Pages/Articles/Delete.cshtml

@model Models.Article

<div class="modal" tabindex="-1" role="dialog" id="deletionModal">
    <form id="deletionModalForm" asp-page="Articles/Delete" method="post">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Delete Article</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p>Are you sure you want to delete the article "@Model.Title"?</p>

                    <input type="hidden" asp-for="@Model.Id" />
                </div>
                <div class="modal-footer">
                    <button type="submit" class="btn btn-danger">Delete</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </form>
</div>

It is referenced in the View.cshtml Razor page as follows:

Pages/Articles/View.cshtml

@page
@model Comprehension.Pages.Articles.ViewModel

<partial name="Delete" model="Model.Article" />

<div class="row mb-4">
    <h2 class="col">@Model.Article.Title</h2>
    <p class="col-auto">
        <a asp-page="./Edit" asp-route-id="@Model.Article.Id" class="text-primary">Edit</a>
    </p>
    <p class="col-auto">
        <a class="text-danger" data-toggle="modal" data-target="#deletionModal">Delete</a>
    </p>
</div>

These two pages have code-behind (.cshtml.cs) files that were scaffolded in the usual way. Whenever the submit button is pressed in Delete.cshtml, the OnPost method in View.cshtml.cs is called rather than the OnPost method in Delete.cshtml.cs.

I've tried adding @page to the Delete.cshtml to no avail. I've also tried everything as suggested by @Xing Zou.


It seems to me that these two issues originate from the same mistake but I'm not sure what that mistake is. Any help would be greatly appreciated.

For context, here is a screenshot of my project structure.

Directory structure of my ASP.NET Razor Pages Project

Upvotes: 0

Views: 1911

Answers (1)

Ryan
Ryan

Reputation: 20116

My understanding is that , you click a button (named Delete) firstly, then a shared dialog pop up, you could see Title in the dialog to confirm .Finally, click the Delete button in the dialog to call the actual post handler to delete the article.

Below is my simple demo:

1._Delete.cshtml

Add id for the model and add <form> tag to submit to your delete handler

@model Models.Article
<div class="modal" tabindex="-1" role="dialog" id="myModal">
    <form id="myForm" method="post">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Delete Article</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p>Are you sure you want to delete the article "@Model.Title"?</p>

                    @*Pass current article ID*@
                    <input type="hidden" asp-for="@Model.Id" />
                </div>
                <div class="modal-footer">
                    <button type="submit" asp-page="Articles/Delete"  class="btn btn-danger">Delete</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
     </form>
</div>

2.Index.cshtml:

<partial name="_Delete" model="@Model.Article" />
<button type="button" class="btn btn-primary myButton" data-toggle="modal" data-target="#myModal">
    Delete
</button>

3.Pages/Articles/Delete.cshtml(Delete.cshtml.cs) Razor Page

public async Task<IActionResult> OnPostAsync(int? id)
{
 //your delete logic
}

enter image description here

Edit 12/24/2019

Do not put partial view as razor pages, you just need to submit to a post hanlder behind one razor page.

Besides,asp-page should use correct path, if you put your partial view in the same Articles folder,then it will change to asp-page="Delete"

Demo:

1.Create a partial view as Pages/Articles/MyDeletePartilaView.cshtml:

@model Models.Article

<div class="modal" tabindex="-1" role="dialog" id="deletionModal">
    <form id="deletionModalForm" asp-page="Delete" method="post">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Delete Article</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p>Are you sure you want to delete the article "@Model.Title"?</p>

                    <input type="hidden" asp-for="@Model.Id" />
                </div>
                <div class="modal-footer">
                    <button type="submit" class="btn btn-danger">Delete</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
                </div>
            </div>
        </div>
    </form>
</div>

2.Pages/Articles/View.cshtml

 <partial name="MyDeletePartilaView.cshtml" model="Model.Article" />

3.Pages/Articles/Delete.cshtml

@page
@model RazorpagesCore.Pages.Movies.DeleteModel

4.Pages/Articles/Delete.cshtml.cs

public class DeleteModel : PageModel
{
   public async Task<IActionResult> OnPostAsync(int? id)
    {
       //your delete logic         

    }
}

Upvotes: 1

Related Questions