ActionMethod I just created cannot be found - asp.net-mvc

So I've created a table to hold extra information for all authenticated users. This table also links up to the many others in my db. This table is hooked up to asp.net identity through the user id although there are multiple fields which share the same information as the membership tables (email and username as well). Unfortunately there was a bug that erased some of this membership data from the users table I added and not the identity tables themselves. The bug itself has been since been fixed, however I am trying to create a way to retrieve this lost information from the membership tables. The way I went about doing so was by adding a button to the edit screen of the users (Not the usersadmin page but the users table I added). My code for the button taking me to the action looks like this:
Button to action
The UserReset Action code looks like this:
UserReset Action Code
The trouble I am having currently is actually being able to call to this action (or even open the edit page at this point). Every time I try to load the page it throws a "Public Action Method not found in controller" error. I feel it's a rookie mistake on my end but can anyone please tell me what I am doing wrong?

I'm going to hold my tongue on the backstory and just answer the question:
So, you have two major things I found. The first is the CSHTML (but not the direct cause of your current specific error). See farther below for the CSHTML suggestions (especially if you run into more problems after the C# Action fixes)
First, your controller. If you look at your UserReset action, you'll notice you decorated it with [HttpPost]. As you said, you can't open the edit page. This is because the edit page action doesn't exist (e.g., the [HttpGet] action at the requested Url). This is what you need:
public class TSTUsersController : IController
{
...
//You need this action to process the get request
[HttpGet]
public ActionResult UserReset()
{
return View("UserReset"); //return the edit form html to the user
}
//this method will handle the button click
[HttpPost]
public ActionResult UserReset( String email )
{
if(ModelState.IsValid)
{
//save the information to the database
//direct the user to some sort of confirmation page
return RedirectToAction("Index", "Home");
}
//return the form with the error messages
return View("UserReset", email);
}
...
}
From what I can tell, you are completely misunderstanding HTML form submission.
The <form></form> element has two main parameters you are missing:
<form
method="POST"
action="#Url.Action("UserReset", 'TSTUsers")" //e.g. POST /TSTUsers/UserReset
... >
...
<button>Submit</button>
</form>
Or, using helpers:
#using( Html.BeginForm( "UserReset", "TSTUsers", FormMethod.Post ) )
{
<button>Submit</button>
}
Now, this would post to the specified action. To add parameters, in your case, your using a non-changing parameter (e.g., the user can't enter an email), so you have two options. You can modify your action parameter to instead designate the parameter (please note, that the user would see this Url upon a non-ajax post, if that matters to you), like so:
<form
action="#Url.Action("UserReset", 'TSTUsers", new { email = Model.Email })"
//e.g. POST /TSTUsers/UserReset?email=example#example.com
... >
...
<button>Submit</button>
</form>
Or, using helpers:
#using( Html.BeginForm( "UserReset", "TSTUsers", FormMethod.Post, new { email = Model.Email } ) )
{
<button>Submit</button>
}
Now, if you would prefer to hide the Url parameter from the request (for whatever reason), then you would instead add a input, with the type of hidden:
<form
action="#Url.Action("UserReset", 'TSTUsers")" //e.g. "POST /TSTUsers/UserReset
... >
<input type="hidden" name="email" value="#Model.Email"
<button>Submit</button>
</form>
Or, using helpers:
#using( Html.BeginForm( "UserReset", "TSTUsers", FormMethod.Post ) )
{
#Html.Hidden("email", Model.Email )
<button>Submit</button>
}

Related

mvc5 Additional information: 'object' does not contain a definition for 'Action'

I get:
'object' does not contain a definition for 'Action'
excepiton in my "_ExternalLoginsListPartial" view but I don't understand why because in Login view I call:
#Html.Partial("_ExternalLoginsListPartial", new { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl })
And when I look into the Model in debugger it definaltely contains "Action".
Can anyone help me understand that?
Actually my site was running but today I started to edit "ManageUserViewModel" so that I can store some user specific settings in it. After that I always get this exception although I already reverted my changes...
The code below makes my website run again:
//string action = Model.Action;
//string returnUrl = Model.ReturnUrl;
string action = "ExternalLogin";
string returnUrl = "/myTime/en/Manage";
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
{
#Html.AntiForgeryToken()
<div id="socialLoginList">
<p>
#foreach (AuthenticationDescription p in loginProviders)
{
<button type="submit" class="btn btn-default" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
}
</p>
</div>
}
UPDATE:
I'm able to reproducte the problem. As mentioned above I tried to change "ManageUserViewModel" so that the user can set some settings. Since I only use Google login I removed the password stuff for the model. To reproduce the exception comment out everything in ManageUserViewModel (make it an empty class).
Then comment out everything in Manage:
//
// POST: /Account/Manage
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
// If we got this far, something failed, redisplay form
return View(model);
}
and then comment in:
app.UseGoogleAuthentication();
in StartupAuth.cs
And you get the exception when you click the google login button.
You can use the default MVC5 template and just do the steps described above to reproduce this...
I'm not sure if it is the wrong place to let my user store his settings. However, the screenshot below is definately giving me wrong information...
UPDATE2:
You don't have to edit Manage function in AccountController. It is enough to make “ManageUserViewModel” empty.
Cheers,
Stefan
The fact that it exists in the debugger is meaningless. The debugger exposes the object and all it's properties without knowing or caring about it's type. The problem you're having in your view is that you don't have a model definition, and because of that, your "model" is an object. The Object type truly does not have a property or method named Action, so you get the error.
The best solution is to simply specify your model as the actual type you're working with. Then you get intellisense and all the other goodness that comes from being strongly-typed. The alternative, is to cast Model to dynamic, but that's really nasty.
I encountered this exact error on this exact line because I had enabled Twitter as an authorization source with bogus key and secret values.
When I commented that section out in StartupAuth.cs, the application worked as expected.

View form calls on postback all controllers' actions with [HttpPost] from different controllers

I know that maybe the title sounds a bit weird but I believe that my problem is weird indeed. I have an ASP.NET MVC 4 application (this is my first MVC real-world application) with Razor view-engine.
I have a layout view where I'm rendering two partial views like this:
<!-- Login -->
#Html.Action("RenderLoginPopup", "Login")
<!-- Registration -->
#Html.Action("RenderRegisterPopup", "Login")
Each of those actions from the Login controller just renders a partial view:
[ChildActionOnly]
public ActionResult RenderLoginPopup()
{
return PartialView("Partial/_LoginPopupPartial");
}
Just for exemplification sake (both are built the same way), the login partial view contains an ajax form like this:
#using (Ajax.BeginForm("Login", "Login", new AjaxOptions()
{
HttpMethod = "POST",
OnSuccess = "loginResponseReceived"
}, new { #id = "loginForm" }))
The Login action from the Login controller (the target of the form) is signed with the following attributes (worth to mention and notice the HttpPost one):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public JsonResult Login(LoginModel model)
{ }
So far, so good... Everything works perfect - both the login and the register actions are working without any issues.
The issue that I want to speak about shows-up when I have a #Html.BeginForm() in a view that is loaded along with the main layout. For example, if I have a pure and simple form like this:
#using (Html.BeginForm())
{
<input type="hidden" name="name"/>
<input type="submit" value="Send"/>
}
along with the controller CaptionExtendedController:
[HttpPost]
public ActionResult Index(string nume)
{
return View();
}
So, in the end, in my final html generated file I will have 3 forms - 2 for login and register (ajax) and one simple form generated from the last view. Please keep in mind that all three forms are independent (meaning that they are not one in another).
The issue is that everytime I'm pressing the button "Send" from the last form all controllers that are signed with the [HttpPost] attribute from my view (Login, Register from LoginController and Index from CaptionExtendedController) gets called.
WHY??? In order to have a temporary fix, I've removed the [HttpPost] attribute from the Login and Register actions and now it's working but I don't think this is correct.
Please, there is someone who can explain me why this is happening and eventually point me to the right direction in fixing this issue?
Thank you in advance.
Try specifying the controller and action with your Html.BeginForm and we can start from there. Also, you can utilize #Html.RenderPartial to render your partials which would get rid of some of your unneeded actions/controllers, making it a bit more manageable.
This doesn't address the root problem, but might be a work-around which is all you need anyway. :)
You could write some jQuery which catches the button click and then submits the form directly by name. For example, if you add the id below:
#using (Html.BeginForm())
{
<input type="hidden" name="name"/>
<input type="submit" id="regularSubmitButton" value="Send"/>
}
Then you could write:
$(document).ready(function() {
$("#regularSubmitButton").click(function(e) {
e.preventDefault();
$(this).parent("form").submit();
return false;
});
});
I'm not sure it would work without seeing everything, but seems to be worth a try.
Cheers,
Michael
It doesn't make sense anymore... Starting from the comments and answers, I've mapped 3 functions to the submits on those tricky forms: login, register and index (also I've put back the HttpPost attribute to the Login and Register actions). In those jquery functions I've just put an alert with a string (name of the form); in order to be able to write a jquery id-based selector, I've declared also the last form with an id (it didn't had it; only login and register had one), like this (an example taken from another form with the same issue):
#using (Html.BeginForm("Index", "PersonalizeCard", new {data = Model.EncryptedDataQueryStringValue}, FormMethod.Post, new {#id = "personalizeCardForm"})) { }
(what has been added - last two parameters - form method and html id).
After this, I've run the application and no exception anymore... I've put breakpoints on the login and register actions - nothing... I've even removed those 2 extra parameters from the BeginForm - still nothing...
WHY???? Again, why??? I mean, I'm not upset that it's fixed but I don't understand why it's fixed by itself...
THANK YOU FOR ALL YOUR TIME AND COMMENTS / ANSWERS.

MVC controls not working properly without page refresh

I've got an MVC controller that can be called via form submission in a couple different places. The controller then renders a view whose primary purpose is to allow the user to send the document or post it to an external site, as well as fill in text fields that will be used in the notification email.
I am performing validation on these fields - the user can enter custom subject/body text. If they do not, they will receive a popup alert and can either return to the form or submit it using default text indicated in the placeholder value.
The problem is that when the user first reaches this page and clicks the send button, no input in the textboxes is actually registering and it gives the empty string notification regardless of what is actually in the fields; however, if I hit F5 and try again, the input works perfectly.
I feel like this has something to do with the form submissions that initially call this controller being done via POST action, whereas it seems to work fine with the GET on page refresh. I just can't figure out how to either get the content to respond properly when the controller is called via POST, or how to submit the form without posting the data.
Thanks in advance for reading and any help.
Here is the calling controller:
public ActionResult Index(FormCollection collection)
{
//modelbuilding code
return View (Model);
}
The code that calls the controller always uses this format: (in this case, it would be called from the Recipients/Index view.
#using(Html.BeginForm("Index", "Distribution", FormMethod.Post )) {
//form values
<input type="submit" data-role="button" value="Done"/>
}
Here is the relevant part of the view and the JS validation function:
<div id="SubjectTemplate">
<p>Subject: <input id="emailSubjectTextBox" name="EmailSubject" placeholder="#EmailSubject" /></p>
</div>
Send Notification
<script>
function validateInput() {
var possibleErrors = [];
if (!(document.getElementById('emailSubjectTextBox').value)) {
possibleErrors.push('#incompleteEmailSubject' + '\n');
}
//more validation that works the same way and has the same problem
if (possibleErrors.length > 0) {
if (confirm(possibleErrors))
{
window.location.href = '#Url.Action("Send")'
}
}
else {
window.location.href = '#Url.Action("Send")'
}
}
</script>
I'm not sure I fully understand your question, but generally speaking you should not use the same action for POST and GET.
Even more importantly, you should not be using POST if your action does not have some kind of side effect. If all you are doing with your form submission is making some kind of choice then you should be using GET.
See the following post for more information and examples of how to perform ajax GET requests using jQuery: http://www.jquery4u.com/ajax/key-differences-post/
Regardless of what you are trying to do, it is very good practice that POST calls perform some action, and then redirect to a GET action which returns to the user.
[HttpPost]
public ActionResult Index(FormCollection collection)
{
//do whatever you need to save the record
return RedirectToAction("Index")
}
[HttpGet]
public ActionResult Index()
{
//modelbuilding code
return View (Model);
}
Not only does this help your controller adhere to a RESTful methodology, it also stops the user getting that annoying 'Are you sure you want to resubmit this page' if they happen to press f5
Hope this helps.
I found the problem resulted from jQueryMobile automatically utilizing AJAX to post forms. I solved this by including new {data_ajax = "false"} to the Html.BeginForm statements.

Generating URL through routing, using ID from a form field (ASP.NET MVC)

Say I want to display user details like so:
http://www.mysite.com/user/1
I set a route up like so:
routes.MapRoute("UserDetails", "user/"{id}",
new { controller = "User", action = "Details" });
Then my controller:
public ActionResult Details(int id)
{
User currentUser = _userRepository.GetUser(id);
if (currentUser == null) return View("NotFound");
return View(currentUser);
}
So far so good. Everything works like I expect. Now I also want a form where one can enter the ID to look up then click Submit to get the same result. eg:
<% Html.BeginForm("Details","User",FormMethod.Post); %>
<input type="text" value="" name="id" id="userid" />
<%= Html.Button("Search For User","submit","searchforuser"; %>
<% Html.EndForm(); %>
This is where I'm currently lost. I don't want to just have [AcceptVerbs(HttpVerbs.Post)] and use a RedirectToAction if possible. I just want to take whatever number they input - say 38 - and go to www.mysite.com/user/38
Is this even possible with straight MVC? I'm sure there are jQuery-related ways but so far have had no luck getting anything beyond a basic jQuery alert working so don't really want to waste any more time on it for now.
MVC will automatically match by name query parameters (for GET) or form input files (for POST) to the action parameters by name. Unfortunately, your id does not match the action parameter name, so MVC can't match them. To fix this, you can:
change the id on the <input type="text" value="" name="id" id="userid" /> from userid to id
change the parameter name of the Details action from id to userid (and don't forget to update your route as well)
I just confirmed that at least the first one fixes the issue on MVC2 RC. I don't have MVC1, so I can't check if it works there as well, but as far as I know there are no major differences in how MVC1 and MVC2 match parameters.

asp.net mvc actionlink shows address in FF, cannot get button to function

I'm currently in the process of learning ASP MVC and am running into a few issues.
First, when I use
<%=Http.ActionLink("Add / Modify", "AddModify" %>
it will show as Add / Modify (/Home/AddModify) in Firefox and Add / Modify in IE. It is doing that to all links in FF and none in IE. Anyone know what reasoning is for that?
Edit: What is displayed in the browser (FF in this case) is "Add / Modify (/Home/AddModify)" while in IE shows just "Add / Modify".
Here is a screenshot of what I see on my site in FireFox: http://img6.imageshack.us/img6/1331/19748435.png
You can see how it shows the text and the appropriate link afterwards (only populated in Database with /).
Also, I am trying to have buttons (both standard and image) on my site which will link to new pages, while also performing hidden tasks (saving data, etc...). Anyways, When I do the following:
<form method="post" action="/Home">
<input type="submit" value="AddModify">
</form>
and the controller has a simple
[ActionVerbs(HttpVerbs.Post)]
public ActionResult AddModify()
{
return View();
}
And I still cannot get that function to call, yet when I do http://localhost:port/Home/AddModify, the function calls and I can get to that page. I am doing it this way because there may be code that has to execute before redirecting to that page, rather than just a direct link to that page. I have tried with and without the ActionVerbs line, I have tried this form of the Html Form:
<% using (Html.BeginForm()) { %> ... <%}%>
and still nothing. I have also tried no form and still nothing, but here's something that may affect this...I am using a master page with everything inside a content place holder inside a form that uses runat="server". Would that matter? So its Master Page -> form (masterform runat server) -> ContentPlaceHolder -> form (for postback and action) -> submit button. Any help would be greatly appreciated.
If I am thinking correctly, your form action should be calling the name of the action method:
<form method="post" action="/Home/AddModify">
<input type="submit" value="AddModify">
</form>
The ActionLink would be the same way.
Otherwise you will need to modify your routes to go to that action method by default.
Let's do this in two parts
1 I think your ActionLink should be:
<%=Http.ActionLink("Add / Modify", "AddModify", "Home")
...to force routes.
First parameter: text shown
Second parameter: action name
Third parameter: controller name
2 Change your submit button to: (I assume we're currently looking at your "index" action from your "Home" controller)
<form method="post" action="/Home">
<input type="submit" value="AddModify" name="ModifyBtn" >
</form>
Then in your Home controller:
edit:
//GET
public ActionResult Index()
{
return View();
}
/edit
[ActionVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection form, string ModifyBtn, string OtherBtn)
{
if (ModifyBtn!=null)
{
//do stuff
return RedirectToAction("AddModify");
}
if (OtherBtn!=null)
{
//do stuff
return RedirectToAction("OtherAction");
}
return View();
}
edit:
I think you're trying to submit directly to another Action. The best way is to handle the POST method inside your code then redirect to another action. That way, you can use
<% using (Html.BeginForm()) { %>
without trouble.
<form method="post" action="/Home">
Will create a form with a href of /Home, this will only call the AddModify action if the AddModify action is default on that route.

Resources