Resource not found when calling ActionResult from Controller from multiple submit buttons - asp.net-mvc

link text
I am following the answer in this link, I have done this...
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>
<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>
With this in the controller...
public class MyController : Controller {
public ActionResult MyAction(string submitButton) {
switch(submitButton) {
case "Send":
// delegate sending to another controller action
return(Send());
case "Cancel":
// call another action to perform the cancellation
return(Cancel());
default:
// If they've submitted the form without a submitButton,
// just return the view again.
return(View());
}
}
private ActionResult Cancel() {
// process the cancellation request here.
return(View("Cancelled"));
}
private ActionResult Send() {
// perform the actual send operation here.
return(View("SendConfirmed"));
}
}
But I keep getting a Resource not found error - Cannot find MyController\MyAction

Don't specify "Controller" in the Form parameter:
<% Html.BeginForm("MyAction", "My", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
Link will be /My/MyAction if you want it to be MyController, the Controller class must be called MyControllerController (not tested though)

You may need to ensure you have a route that MVC can match to your Controller/Action. Something like:
routes.MapRoute(
"MyRoute",
"{controller}/{action}/{submitButton}",
new { controller = "MyController", action = "MyAction", submitButton = "Default" }
);

Related

Delete Action does not activate/trigger ASP.NET Core MVC

HttpPost on delete action does not trigger, however HttpGet seems working fine as i get the content displayed. However I have little confusion in the following route address generated when I click on HttpGet on delete action:-
https://localhost:44394/9
shouldn't it generates link like this: https://localhost:44394/Post/DeletePost/9
Controller:-
[HttpPost, ActionName("DeletePost")]
public async Task<IActionResult> ConfirmDelete(int id)
{
await _repository.DeletePostAsync(id);
return RedirectToAction(nameof(GetAllPosts));
}
[HttpGet("{id}")]
public async Task<IActionResult> DeletePost(int id)
{
var post = await _repository.GetPostById(id);
if(post == null)
{
return NotFound();
}
return View(post);
}
Razor View for HttpGet:-
<div class="btn btn-outline-danger delete">
<a href="#Url.Action("DeletePost", "Post", new { id = p.Id })">Delete
</a>
</div>
Razor Page HttpPost:-
<div class="container">
<div class="row">
<div class="col-9">
<p>
#Model.Topic
</p>
<p class="timeStampValue" data-value="#Model.Published">
#Model.Published
</p>
<p>
#Model.Author
</p>
<section>
<markdown markdown="#Model.Content" />
</section>
</div>
</div>
<form asp-action="DeletePostAsync">
<input type="hidden" asp-for="Id" />
<button type="submit" class="btn btn-outline-danger">Delete</button>
</form>
Cancel
</div>
Routing:-
app.UseMvc(routes =>
{ routes.MapRoute(
name: "KtsPost",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Post", action = "Index" },
constraints: new { id = "[0-9]+" });
});
Your action name is wrong in the form. Your code should be instead:
<form asp-action="DeletePost">
<input type="hidden" asp-for="Id" />
<button type="submit" class="btn btn-outline-danger">Delete</button>
</form>
The default method of an HTML form is GET not POST. You need to tell your form to POST. Also, the action name should be ConfirmDelete:
<form asp-action="ConfirmDelete" method="post">
<input type="hidden" asp-for="Id" />
<button type="submit" class="btn btn-outline-danger">Delete</button>
</form>

How to link HTML5 form action to Controller ActionResult method in ASP.NET MVC 4

I have a basic form for which I want to handle buttons inside the form by calling the ActionResult method in the View's associated Controller class. Here is the following HTML5 code for the form:
<h2>Welcome</h2>
<div>
<h3>Login</h3>
<form method="post" action= <!-- what goes here --> >
Username: <input type="text" name="username" /> <br />
Password: <input type="text" name="password" /> <br />
<input type="submit" value="Login">
<input type="submit" value="Create Account"/>
</form>
</div>
<!-- more code ... -->
The corresponding Controller code is the following:
[HttpPost]
public ActionResult MyAction(string input, FormCollection collection)
{
switch (input)
{
case "Login":
// do some stuff...
break;
case "Create Account"
// do some other stuff...
break;
}
return View();
}
you make the use of the HTML Helper and have
#using(Html.BeginForm())
{
Username: <input type="text" name="username" /> <br />
Password: <input type="text" name="password" /> <br />
<input type="submit" value="Login">
<input type="submit" value="Create Account"/>
}
or use the Url helper
<form method="post" action="#Url.Action("MyAction", "MyController")" >
Html.BeginForm has several (13) overrides where you can specify more information, for example, a normal use when uploading files is using:
#using(Html.BeginForm("myaction", "mycontroller", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
< ... >
}
If you don't specify any arguments, the Html.BeginForm() will create a POST form that points to your current controller and current action. As an example, let's say you have a controller called Posts and an action called Delete
public ActionResult Delete(int id)
{
var model = db.GetPostById(id);
return View(model);
}
[HttpPost]
public ActionResult Delete(int id)
{
var model = db.GetPostById(id);
if(model != null)
db.DeletePost(id);
return RedirectToView("Index");
}
and your html page would be something like:
<h2>Are you sure you want to delete?</h2>
<p>The Post named <strong>#Model.Title</strong> will be deleted.</p>
#using(Html.BeginForm())
{
<input type="submit" class="btn btn-danger" value="Delete Post"/>
<text>or</text>
#Url.ActionLink("go to list", "Index")
}
Here I'm basically wrapping a button in a link. The advantage is that you can post to different action methods in the same form.
<a href="Controller/ActionMethod">
<input type="button" value="Click Me" />
</a>
Adding parameters:
<a href="Controller/ActionMethod?userName=ted">
<input type="button" value="Click Me" />
</a>
Adding parameters from a non-enumerated Model:
<a href="Controller/ActionMethod?userName=#Model.UserName">
<input type="button" value="Click Me" />
</a>
You can do the same for an enumerated Model too. You would just have to reference a single entity first. Happy Coding!

ASP.NET MVC2, can I use a model field as an html id?

I am a newbie in ASP.NET and html.
I want to upload a file, so I have a model with a HttpPostedFileBase field, and a strongly-typed view that gets the model in order to get the value of the file.
My question is, how can I send to the controller the value of the file?
This is my html code, I'd like to send the value of File to Model.File, but placing <%:Model.File:> instead of file1 does not work :(
<label for="file1">File: </label>
<input type="file" name="file1" id="file1" size="40">
P.S.: I've also tried using the asp:FileUpload but I don't what how to send the result to the controller.
EDIT:
Ok, I go for posting my code, thank you very much ZeNo.
Here is the Model:
public class AddProductModel
{
[...]
public HttpPostedFileBase File { get; set; }
}
This is my View:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Application.Models.AddProductModel>" %>
<form id="form1" runat="server">
<% using (Html.BeginForm()) { %>
<% Html.EnableClientValidation(); %>
<fieldset>
[...]
<div>
<label for="file1">File: </label>
<input type="file" name="file1" id="<%: Model.File %>" size="40">
<br />
</div>
<br />
<p>
<input type="submit" value="Add!" />
</p>
</fieldset>
<% } %>
</form>
Here is my controller, I use the debugger here and it says that model.File is empty:
[HttpPost]
public ActionResult AddProduct(AddProductModel model)
{
if (model.ProductName != null && model.ProductDescription != null)
objRepository.addToProducts(model);
return RedirectToAction("/AddProduct");
}
Use <%:Model.File %> instead.
put you file control inside a form tag
<form action="/Home/GetFile" id="myform">
<input type="file1" id="file1"/>
</form>
<script type="text/javascript" language="javascript">
var form = $("#myform");
form .submit();
</script>
controller:
[HttpPost]
public ActionResult GetFile(HttpPostedFileBase file) {
if (file.ContentLength > 0) {
var fileName = Path.GetFileName(file.FileName);
}
}
Change your view to:
<form action ="/AddProduct" id="myform">
<% Html.EnableClientValidation(); %>
<fieldset>
<div>
<label for="file1">File: </label>
<input type="file" name="file1" id="<%: Model.File %>" size="40">
<br />
</div>
<br />
<p>
<input type="submit" value="Add!" />
</p>
</fieldset>
</form>
notice I have removed form runat="server".. also there were nested forms..
add this Javascript snippet:
<script type="text/javascript" language="javascript">
var form = $("#myform");
form .submit();
</script>
in the controller make following changes:
[HttpPost]
public ActionResult AddProduct(HttpPostedFileBase file)
{
if (file.ContentLength > 0) {
var fileName = Path.GetFileName(file.FileName);
}
return RedirectToAction("/AddProduct");
}

Why doesn't my List<string> bind to a series of hidden fields when using Html.Hidden()?

I'm trying to use the default model binder in asp.net mvc to bind a list of hidden fields
<input id="entity" name="entity" type="hidden" value="/string/one/here" />
<input id="entity" name="entity" type="hidden" value="/another/string/here" />
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
To a List<string> like this:
[HttpPost]
public ActionResult Move(List<string> entity)
{
return View(entity);
}
When I post the form, the view displays the contents of the list like this:
<%foreach (string item in Model)
{%>
<%: Html.Hidden("entity", item)%>
<!--binding not working correctly -->
<%} %>
And the generated content is this:
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
I'm confuseled. I tried changing the initial hidden field to this:
<input id="entity__" name="entity[]" type="hidden" value="/string/one/here" />
<input id="entity__" name="entity[]" type="hidden" value="/another/string/here" />
<input id="entity__" name="entity[]" type="hidden" value="/last/string/here" />
But when I tried posting that I got this error:
System.NullReferenceException: Object reference not set to an instance of an object.
on this line of code in the view:
<%foreach (string item in Model)
I've been able to bind list of strings before... without using an index in the name. I don't understand why this isn't working correctly. Maybe a fresh set of eyes could help me out with this?
Thanks
edit
In continuing to expirement. I ditched the HtmlHelper and hardcoded a hidden field inside the foreach loop like this:
<%foreach (string item in Model)
{%>
<input id="entity" name="entity" type="hidden" value="<%:item %>" />
<%} %>
This worked. I have no idea what the difference is between the Html helper's code and this so I put the two side by side and tried to match them up.
<input id="entity" name="entity" type="hidden" value="//Content/files/NewDirectory/Aesculuparviflora011cm.jpg" />
<input id="entity" name="entity" type="hidden" value="//Content/files/NewDirectory/Aesculuparviflora011cm.jpg" />
They are identical. But the binding works when I hardcode tags and it doesn't work when i use the html helper. What gives?????????
Why are you using loops and non-strongly typed helpers in a strongly typed view? Things could be so simple with editor templates:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new[]
{
"/string/one/here", "/another/string/here", "/last/string/here"
});
}
[HttpPost]
public ActionResult Index(List<string> items)
{
return View(items);
}
}
and the corresponding view (~/Views/Home/Index.aspx):
<%# Page
Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<string>>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm()) { %>
<%: Html.EditorForModel() %>
<input type="submit" value="OK" />
<% } %>
</asp:Content>
and the corresponding editor template (~/Views/Home/Index/EditorTemplates/string.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<%: Html.HiddenFor(x => x) %>
Now you no longer need to worry about values not properly binding, writing loops in your views, ... you can finally concentrate on the real business logic of the application.
try:
<input id="entity" name="entity0" type="hidden" value="/last/string/here" />
<input id="entity" name="entity1" type="hidden" value="/last/string/here" />
<input id="entity" name="entity2" type="hidden" value="/last/string/here" />
I actually cannot recreate your problem:
This is my code, I tried fiddling with it and I cannot get it to malfunction.
perhaps check so that your view inherits the right type. Please post all of your code neccessary to make it malfunction.
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
var strings = new string[] { "test1", "test2", "test3" };
return View(strings);
}
[HttpPost]
public ActionResult Index(List<string> strings)
{
return View(strings);
}
aspx page
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<string>>" %>
<%using (Html.BeginForm()) { %>
<% foreach (var item in Model) { %>
<%:Html.Hidden("strings", item)%>
<% } %>
<input type="submit" value="Submit" />
<% } %>

View issue - multiple 'delete forms'

I have a really strange ‘bug’. I use this in my view:
<% foreach (var QualitativeGlobalFeatureValue in Model.PossibleValues)
{ %>
<% using (Html.BeginForm("DeleteQualitativeGlobalFeatureValue", "Features", FormMethod.Post, new { #class = "deleteForm" }))
{ %>
<%= QualitativeGlobalFeatureValue.Value %>
<%= Html.ActionLink("Edit", "QualitativeGlobalFeatureValueForm", new { FeatureId = Model.Id, Id = QualitativeGlobalFeatureValue.Id })%>
<%= Html.Hidden("QualitativeGlobalFeatureValueId", QualitativeGlobalFeatureValue.Id)%>
<%= QualitativeGlobalFeatureValue.Id %>
<%= Html.Hidden("FeatureId", Model.Id)%>
<input type="submit" value="Delete" class="link_button" />
<% } %>
<% } %>
This produces a bunch of forms which post to an action which then redirect to an action which in turn produces this view.
Here is some HTML:
<form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">b
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="3004" type="hidden">
3004
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form><form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">aa
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="9010" type="hidden">
9010
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form>
Now if I delete the value with the Id 9010 the resulting HTML is as follows:
<form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">b
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="9010" type="hidden">
3004
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form>
For some unexplainable reason it contains value="9010" rather than value="3004" although it uses the code QualitativeGlobalFeatureValue.Id
It just does not make sense. Is this some browser/caching issue? – I am using Firefox. Thanks!
Best wishes,
Christian
PS:
Actions:
[MembersOnlyAttribute]
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult GlobalQualitativeFeature(string Id)
{
QualitativeGlobalFeature QualitativeGlobalFeature = null;
if (TempData["ViewData"] != null)
{
ViewData = TempData["ViewData"] as ViewDataDictionary;
}
try
{
QualitativeGlobalFeature = FeatureService.GetQualitativeGlobalFeature(Id);
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
}
return View("GlobalQualitativeFeature", QualitativeGlobalFeature);
}
[MembersOnlyAttribute]
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult DeleteQualitativeGlobalFeatureValue(string QualitativeGlobalFeatureValueId, string FeatureId)
{
try
{
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.BeginTransaction();
FeatureService.DeleteQualitativeGlobalFeatureValue(QualitativeGlobalFeatureValueId);
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.CommitTransaction();
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.RollbackTransaction();
}
TempData["ViewData"] = ViewData;
return RedirectToAction("GlobalQualitativeFeature", new { Id = FeatureId });
}
I suspect the following. You click on the delete button for the 9010. The form is posted and the POST request contains QualitativeGlobalFeatureValueId=9010. In the controller action the same view is rendered. Here's the gotcha. When you write this:
<%= Html.Hidden(
"QualitativeGlobalFeatureValueId",
QualitativeGlobalFeatureValue.Id)
%>
The HTML helper (and not only this one) will first look if there's a request parameter with the same name as the name of the field (QualitativeGlobalFeatureValueId) and will use this value instead of the one you specified as the second argument (that's the way it is, don't ask my why, it's by design). So to fix this the only way is to manually render the hidden field:
<input
id="QualitativeGlobalFeatureValueId"
name="QualitativeGlobalFeatureValueId"
value="<%= QualitativeGlobalFeatureValue.Id %>"
type="hidden"
/>
You can put breakpoints in the markup and debug as it renders through, though it doesn't allow putting breakpoints on client markup or <% lines, so you need to find a line continuation.
Are you sure that it isn't a sort reordering or something like that, maybe the results aren't sorted, and that result is later on?
HTH.

Resources