0

I have an Exercise controller and two methods with the same name

[HttpGet]
public async Task<IActionResult> Update(int exerciseId)
{
    Exercise exercise = (await this.exerciseService.GetExercises(exercise => exercise.Id == exerciseId)).FirstOrDefault();
    return View(exercise);
}

[HttpPut]
public async Task<IActionResult> Update(Exercise exercise)
{
    if (ModelState.IsValid)
    {
        await this.exerciseService.EditExercise(exercise);
        return RedirectToAction("some-view-which-doesnt-matter-in-my-case");
    }
    return View(exercise);
}

I want to use the similar name in order to render validation errors in the respective view. But the problem I'm facing at the moment is the Error 405 at the HttpPut method. How can I fix it in my case? I have read some articles on editing/adding web.config with things like "remove name="WebDAVModule"" but 1) these articles are on previous versions of .NET core 2) even if I add web.config with content such as

<system.webServer>
  <modules runAllManagedModulesForAllRequests="false">
    <remove name="WebDAVModule" />
  </modules>
</system.webServer>

...the project can't launch at all with some references to exceptions thrown by IIS Express. So what do I have to do? My "Update" view is:

@model DomainModels.Exercise
@{
    ViewData["Title"] = "Update";
}

<h1>Update @Model.Name</h1>
<div>
    <form method="put" asp-controller="Exercise" asp-action="Update">
        <div asp-validation-summary="ModelOnly">

        </div>
        <div>
            <h3>Exercise settings:</h3>
            <input hidden asp-for="Id" />
            <div>
                <label asp-for="Name"></label><br />
                <input asp-for="Name" />
                <span asp-validation-for="Name"></span>
            </div>
            <div>
                <label asp-for="FractureFixNumber"></label><br />
                <input asp-for="FractureFixNumber" />
                <span asp-validation-for="FractureFixNumber"></span>
            </div>
            <div>
                <label asp-for="DislocationFixNumber"></label><br />
                <input asp-for="DislocationFixNumber" />
                <span asp-validation-for="DislocationFixNumber"></span>
            </div>
            <div>
                <label asp-for="SprainFixNumber"></label><br />
                <input asp-for="SprainFixNumber" />
                <span asp-validation-for="SprainFixNumber"></span>
            </div>
        </div>
        <div>
            <h3>Exercise analysis range settings:</h3>
            <input hidden asp-for="ExerciseAnalysisRange.ExerciseId" />
            <div>
                <label asp-for="ExerciseAnalysisRange.MinAnalysis1"></label><br />
                <input asp-for="ExerciseAnalysisRange.MinAnalysis1" />
                <span asp-validation-for="ExerciseAnalysisRange.MinAnalysis1"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MaxAnalysis1"></label><br />
                <input asp-for="ExerciseAnalysisRange.MaxAnalysis1" />
                <span asp-validation-for="ExerciseAnalysisRange.MaxAnalysis1"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MinAnalysis2"></label><br />
                <input asp-for="ExerciseAnalysisRange.MinAnalysis2" />
                <span asp-validation-for="ExerciseAnalysisRange.MinAnalysis2"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MaxAnalysis2"></label><br />
                <input asp-for="ExerciseAnalysisRange.MaxAnalysis2" />
                <span asp-validation-for="ExerciseAnalysisRange.MaxAnalysis2"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MinHighPressure"></label><br />
                <input asp-for="ExerciseAnalysisRange.MinHighPressure" />
                <span asp-validation-for="ExerciseAnalysisRange.MinHighPressure"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MaxHighPressure"></label><br />
                <input asp-for="ExerciseAnalysisRange.MaxHighPressure" />
                <span asp-validation-for="ExerciseAnalysisRange.MaxHighPressure"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MinLowPressure"></label><br />
                <input asp-for="ExerciseAnalysisRange.MinLowPressure" />
                <span asp-validation-for="ExerciseAnalysisRange.MinLowPressure"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MaxLowPressure"></label><br />
                <input asp-for="ExerciseAnalysisRange.MaxLowPressure" />
                <span asp-validation-for="ExerciseAnalysisRange.MaxLowPressure"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MinHeartBeats"></label><br />
                <input asp-for="ExerciseAnalysisRange.MinHeartBeats" />
                <span asp-validation-for="ExerciseAnalysisRange.MinHeartBeats"></span>
            </div>
            <div>
                <label asp-for="ExerciseAnalysisRange.MaxHeartBeats"></label><br />
                <input asp-for="ExerciseAnalysisRange.MaxHeartBeats" />
                <span asp-validation-for="ExerciseAnalysisRange.MaxHeartBeats"></span>
            </div>
            <input type="submit" value="Update exercise" />
        </div>
    </form>
</div>
el_nektarin
  • 343
  • 1
  • 14
  • https://stackoverflow.com/questions/9552761/get-and-post-methods-with-the-same-action-name-in-the-same-controller – MartW Dec 22 '19 at 20:17

2 Answers2

1

You can't have two methods with the same name on the same controller in Asp.Net Core.

You should change the name of one of this methods and use the [ActionName()] attribute to makes the method route be the same for the two methods.

[HttpGet]
public async Task<IActionResult> Update(int exerciseId)
{
    Exercise exercise = (await this.exerciseService.GetExercises(exercise => exercise.Id == exerciseId)).FirstOrDefault();
    return View(exercise);
}

[HttpPut]
[ActionName("Update")]
public async Task<IActionResult> UpdatePut(Exercise exercise)
{
    if (ModelState.IsValid)
    {
        await this.exerciseService.EditExercise(exercise);
        return RedirectToAction("some-view-which-doesnt-matter-in-my-case");
    }
    return View(exercise);
}
Lutti Coelho
  • 2,134
  • 15
  • 31
  • Did he not specifically ask for two the same method names? – MartW Dec 22 '19 at 20:47
  • In the question he said: "I want to use the similar name in order to render validation errors in the respective view. ". I n my answer I keep it clear that the method can not have the same name, but with ActionName Attribute it will respond in the same route. Differing only by http verb. I believe it answer the quastion correctly. If you disagree, please point whats is wrong and I will fix it asap. – Lutti Coelho Dec 22 '19 at 20:52
  • No problem. Sometimes I misunderstood the question. Is always good have someone to review it. – Lutti Coelho Dec 22 '19 at 20:57
  • [docs](https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md) according to Microsoft guidelines your endpoint should not consist of get, create, update, delete words, actions is specified by HTTP verb – Dmytro Shabanov Dec 22 '19 at 21:12
  • This one doesn't work at all, after submitting form it goes to `[HttpGet]Update(int exerciseId)` method – el_nektarin Dec 22 '19 at 22:11
  • @el_nektarin are you sure that your request was made under HTTP PUT verb? You can insure that looking into network tab on developers tools. – Lutti Coelho Dec 23 '19 at 00:26
0

The solution was quite simple: just throw away HttpPut, change the action name and manully set the redirect view . The final code is:

public async Task<IActionResult> UpdateExercise(Exercise exercise)
        {
            if (ModelState.IsValid)
            {
                await this.exerciseService.EditExercise(exercise);

                return RedirectToAction("UpdateIndex");
            }
            return View("Update", exercise);
        }

and consequently, chenge the PUT action name in the view...

<form method="put" asp-controller="Exercise" asp-action="UpdateExercise">

By the way, the same goes for the HttpDelete methods: just get rid of HttpDelete

el_nektarin
  • 343
  • 1
  • 14