Why won't my controller just hand back the model unchanged? - asp.net-mvc

I have had this problem before and it annoys the hell out of my but I just cannot for the life of me remember what the problem was.
I have a controller...
public ActionResult SubmitApplication(ApplicationModel model)
{
return View("Index", model);
}
And the view
#model ApplicationModel
#using (Html.BeginRouteForm(null, null, FormMethod.Post, new { action = "/apply/SubmitApplication" }))
#Html.TextBoxFor(model => model.Email)
<input type="submit" text="submit"/>
}
I stick a break on the action method and the email entered is being passed to the action method no problem. BUT.....No matter what happens the controller clears the email down at some point I end up with an empty email box when its delivered to the page. But I want to preserve it so the user doesn't HAVE to enter ALL of the information again. What am I missing here?
Thanks
EDIT:
Sorry guys I had a faulty watermarking tool that was masking the response, however there is a still a strange problem.....When I do....
[HttpPost]
public ActionResult Apply(ApplicationModel model)
{
return View("Index",new ApplicationModel(){FullName = "newValue"});
}
Instead of getting the "newValue" on the page, I still get the original posted value. Can anybody explain this? Is is to do with model state?

The view helpers check, if there is a matching item in the model state and use this value if it exists. This value is in most cases the value the user typed before posting. If you want to force the view helpers to use your passed model you should clear the model state.

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.

ASP.NET MVC 4 didn't refresh model properties in #Html.TextBoxFor()

I have some strange errors in displaying model. I am creating something like chat. Users sending messages between yourself. When user selected one message in his inbox, and has clicked on the button "Answer", for example, form send submit(). Then information about selected message is displaying.
And in this moment I have a problem. If fields, that's displaying message properties are #Html.DisplayFor(), all works fine. Info of the message refreshed with change of selected message. But if properties displaying with #Html.TextAreaFor or Html.TextBoxFor it didn't happend with changing selected message.
And, if user clicked on "view" button, which display model in #Html.DisplayFor()
model displaying refresh, and refresh in #Html.DisplayFor() many many times. And as soon as click on "Answer" button, ie dipaly model in #Html.TextBoxFor(), model stopped to refresh display on changing selected message.
I drawed an image, for easier understanding. :)
Many Many Thanks!
I guess you are modifying the value you have bound the TextBoxFor on the HttpPost action:
[HttpPost]
public ActionResult SomeAction(MyViewModel model)
{
model.SomeProperty = "some new value";
return View(model);
}
and in the view you have:
#Html.TextBoxFor(x => x.SomeProperty)
If so, then this is by design. The HTML input helpers (such as TextBoxFor, TextAreaFor, CheckBoxFor, ...) are first looking in the ModelState when rendering their values and only after that in the model itself. So if you intend to modify some of the model properties in your POST action make sure that you remove it from the ModelState:
[HttpPost]
public ActionResult SomeAction(MyViewModel model)
{
ModelState.Remove("SomeProperty");
model.SomeProperty = "some new value";
return View(model);
}

umbraco mvc surface controller, can't return view from HttpPost Action

Overview of the problem:
I've created a Surface controller with an action that is called using #Html.Action(...).
The #Html.Action call is done within a Macro partial view and the macro is included within the content of a page using the rich text editor.
(I'm new to this so if i'm going about things the wrong way then please let me know.)
The Surface controller has a GET and a POST action but it's the get action called within the macro partial.
Get action renders fine, entering no data into the form will invalidate the model state (which is what i'm currently testing).
submitting the form (with no entered data) means i can step into my POST action, ModelState.IsValid is set to false and CurrentUmbracoPage() is returned.
All fine... No Exceptions encountered when debugging...
It's at this point that the error text "Error loading Partial View script" appears on the page.
All I'm trying to do is return the same page with the validation messages showing.
Details:
Umbraco v6.0.5
The Controller I'm currently working on is used to reset a user's password. I also have a login conroller that is getting around this issue by using RedirectToCurrentUmbracoPage().
to access the page that contains the macro i use the address http://{testhost}/Reset-Password
the error text returned reads: Error loading Partial View script (file: ~/Views/MacroPartials/ResetPassword.cshtml)
code is within a seperate solution and views and bin directories are copied accross.
nuget package UmbracoCMS.Scaffolding is used.
Controller code:
public class ResetPasswordSurfaceController : SurfaceController {
[ChildActionOnly]
[HttpGet]
public ActionResult Reset(string token, string email) {
// Validation Code Omited
var user = Membership.GetUser(username);
return PartialView("Reset", new ResetPasswordSurfaceModel { UserID = user.ProviderUserKey.AsInt() });
}
[HttpPost]
public ActionResult PostReset(ResetPasswordSurfaceModel model) {
if (ModelState.IsValid) {
//Password reset code omited
return RedirectToCurrentUmbracoPage();
}
//works but only partial view content is rendered
// return PartialView("Reset",model);
return CurrentUmbracoPage();
}
}
View - ~\Views\ResetPasswordSurface\Reset.cshtml:
#model UmbracoExt.Models.ResetPasswordSurfaceModel
#using (Html.BeginUmbracoForm("PostReset", "ResetPasswordSurface")) {
#Html.EditorForModel()
<input type="submit" value="Submit" />
}
Macro Partial View - ~\Views\MacroPartials\ResetPassword.cshtml:
#inherits Umbraco.Web.Macros.PartialViewMacroPage
#Html.Action("Reset", "ResetPasswordSurface")
Any help is appreciated.
Edit:
Removing the [HttpGet] attribute from the Reset Action has revealed that after the PostReset action is called the Reset action is also called.
Renaming PostReset to Reset and re-adding the httpget attribute to the original Reset Action results in the post action being called twice.
the second time it is called causes the exception:
Can only use UmbracoPageResult in the context of an Http POST when using a SurfaceController form
I have reverted the changes so i'm back at Reset ([HttpGet]) being called after the PostReset action.
So the problem still stands. How can i get around this issue?
I need to return the result from the PostReset Action.
This is how I solved this problem:
I created extension method for model:
public static class ExtensionMethods
{
public static void MapModel<T>(this WebViewPage<T> page) where T : class
{
var models = page.ViewContext.TempData.Where(item => item.Value is T);
if (models.Any())
{
page.ViewData.Model = (T)models.First().Value;
page.ViewContext.TempData.Remove(models.First().Key);
}
}
}
Controller code:
[HttpPost]
public ActionResult Index(MyModel model)
{
TempData.Add("MyModel", model);
return RedirectToCurrentUmbracoPage();
}
Partial view code:
#using UmbracoTest.Extension
#using UmbracoTest.Models
#model MyModel
#{
this.MapModel<MyModel>();
}
#using (Html.BeginUmbracoForm("Index", "Home", FormMethod.Post))
{
<div>
#Html.TextBox("Text", Model.Text )
</div>
<input type="submit" name="submit" value="Submit" />
}
The Answers were given to me here
All credit goes to Shannon Deminick
The post action does not return anything for the response (that bit was new to me).
After the post when the Reset action is run the second time, since the modelstate is maintained, by passing a newly instantiated model, this model will inherit the model state of the model processed in the POST action (PostReset).
During the second time the Reset action was called, the validation logic meant it never gets to the point where it returns the partial view.
i temporarily bypassed the validation logic and sure enough the model validation messages were displayed.
I fixed this error by resolving a naming conflict:
Make sure that the GET and POST methods are named differently
Make sure the controller name doesn't conflict with any document types

Html.HiddenFor sporadically not getting set w/ model information

We're having an issue with Html.HiddenFor in MVC3 occasionally not getting bound properly. We can't reproduce it at all, but we're seeing nullrefs come through in our logging and it's driving us absolutely nuts.
We have the following model and controller structure:
public class DummyController
{
[HttpGet]
public ActionResult ReturnAPage(int NumericID)
{
//NumericID should never be 0 or negative, but let's check to make sure
if (NumericID < 1)
{
return RedirectToAction("TracyJordanStabbingRobot");
}
return View("DummyView", new DummyViewModel(NumericID));
}
[HttpPost]
public ActionResult TakePageSubmission(DummyViewModel model)
{
//AnObject relies on having a non-zero ID
ComplexObject AnObject = new ComplexObject(model.NumericID);
AnObject.UseMe();
}
}
public class DummyViewModel
{
public DummyViewModel() {}
public DummyViewModel(int ID)
{
NumericID = ID;
}
public int NumericID { get; set; }
}
... and the following view structure:
DummyView.cshtml
#model DummyViewModel
<html>
<head></head>
<body>
<p>THIS IS A VIEW!</p>
<form id="DummyViewForm" action="/RouteTo/TakePageSubmission" method="post">
#Html.Partial("_PartialDummyView", Model)
<input type="submit" value="Submit This!" />
</form>
</body>
</html>
_PartialDummyView.cshtml
#model DummyViewModel
<p>Heard you like views...</p>
#Html.HiddenFor(model => model.NumericID)
Considering we're checking for less-than-zero values in the initial controller action, it stands to reason that #Html.HiddenFor(model => model.NumericID) should never have a less-than-zero value.
That being said, when we get to using AnObject in the TakePageSubmission action, we're getting null reference errors.
When we dug into logging the model.NumericID value, we're seeing it come through as zero, which shouldn't be possible considering the DummyView can only be accessed with a non-zero value.
We're a little stumped and since we can't reliably reproduce the issue, we have no idea what could possibly be causing it. Has anyone run into something like this before?
Edit: We are doing ModelState validation on the form post, but we're not checking to see if the NumericID coming through is 0. When we did check for that, the model came through as invalid, which just proves that the HiddenFor is getting set improperly. Furthermore, the route to the page actually includes the NumericID, so for example, we've seen this happen on:
http://our.site.com/RouteToReturnAPage/1736/
...where the parameter for the action is clearly set, the model is constructed correctly, but for some unknown reason the HiddenFor NumericID value is 0. It's really baffling.
Your default 0 value bindings are from MVC View'ing to the same page after post, thinking it is reloading the same view due to an error during the post. The correct binding will occur on a load/action call to a different Action call.
There is a hack workaround, to ModelState.Clear(); before you reload the View.
Also, not using the Helpers to create the hidden fields at all, something like:
<input type="hidden" value="#Model.NumericID" id="NumericID" name="NumericID" />
Reference:
http://blogs.msdn.com/b/simonince/archive/2010/05/05/asp-net-mvc-s-html-helpers-render-the-wrong-value.aspx
First you are missing default constructor in your model. Without it applicaiton throws exception when binding.
You can reproduce the error by editing the hidden field on client side. So user can change id to 0 or any other value. If you aren't running you application on distributed enviroment then use TempData to pass the id between actions. This way you will keep id safe from data tampering.
TempData["NumericID"] = NumericID;

Why is a value that I update in my model inside an MVC3 controller not rendered on the client?

I have a controller action UpdateCustomer(CustomerDto customer) that returns a PartialViewResult with a model that is also a CustomerDto:
[HttpPost]
public PartialViewResult UpdateCustomer(CustomerDto customer)
{
CustomerDto updatedCustomer = _customerService.UpdateCustomer(customer);
updatedCustomer.Name = "NotThePostedName";
return PartialView("CustomerData", updatedCustomer);
}
In my view, I have the following line:
#Html.TextBoxFor(model => model.Name)
So far, so good. In my view I do an asynchronous post to this action method, the model binder does its work and I can update a customer in the database. Then I want to render the updated customer to the client. For example, I'd like to change the customer name in my controller. However, what gets rendered is always the properties from the posted customer, not the properties from updatedCustomer.
I decided to include the MVC3 source code in my project to see what really happens. It appears to be a feature (bug?) of MVC3 that it always takes the value from ViewData.ModelState instead of the value from ViewData.Model.
This happens at lines 366-367 of System.Web.Mvc.Html.InputExtensions:
string attemptedValue =
(string) htmlHelper.GetModelStateValue(fullName, typeof(string));
tagBuilder.MergeAttribute("value",
attemptedValue ?? ((useViewData)
? htmlHelper.EvalString(fullName)
: valueParameter), isExplicitValue);
As you can see, attemptedValue comes from ModelState. It contains the old value for CustomerDto.Name (the value that was posted to the controller action).
If this is a feature, why does it work this way? And is there a way to work around it? I would expect that if I update my model, the update gets rendered, not the old value I posted.
Well yes it's a feature (ModelState is always checked before actual Model), you can clear the ModelState, or update just the value you need:
ModelState["Name"].Value = updatedCustomer.Name;

Resources