MVC razor form ONLY submits when last DropDown is populated - c#

I actually found a solution. It was trying to run validation. But only the last validation was added. The message for validation was not displaying.
I can NOT figure this out. I have a form that is created using razor like this
#using (Html.BeginForm("Search", "WellSearch", FormMethod.Post))
{
#Html.Partial("_DropDownList_Operator", Model)
#Html.Partial("_DropDownList_Lease", Model)
<input type="submit" id="buttonClearAllFields" class="btn btn-small submit" name="Command" value="ClearAllFields" />
<input type="submit" id="buttonSearch" class="btn btn-small submit" name="Command" value="Search" />
}
What is wired is this I can ONLY submit form when the last DropDown is populated with a value. If I leave both drop downs blank can't post to a controller. Also if I switch the order of the drop downs around make Operator last it is the same thing.
I my actual code I have 10 total drop down boxes the same thing only the last one is populated. I know MVC pretty well but not an expert.
My question is this what should I check to troubleshoot this behavior. I check everything no errors, no exceptions. Not sure how to troubleshoot this need an advice what to be aware of or maybe someone was in a same situation.
This is a code for a partial view
#model [removed].Models.[removed]
#Html.TextBoxFor(a => a.[removed].LeaseKey, new { id = "lease"})
[removed] - removed those because it contains personal information

I actually found a solution. It was trying to run validation. But only validation for lease drop down was added. The message for validation was not displaying.

Related

Html.CheckBoxFor not functioning correctly and generating different html then mirrored copies

I've looked around for similar issues, but couldn't find this particular problem. I suspect it's something easy to solve, but I've not seen it before and everything I've tried doesn't resolve it.
Using MVC 5, C# models and a Razor view. I have a model with roughly 20 or so bool entities that I use for checkboxes. A user initially selects their checkboxes as part of an initial form insert. The problem rests when doing an update.
18 out of the 20 checkboxes update like they should. Here is an example of one that works correctly. All 20 look exactly like this except the model names are different of course.
<div class="form-group ">
<label class="d-inline-flex customcheckPsNp pb-1">
#Html.CheckBoxFor(model => model._GetCompleteGroup1.MvrInFile)
<span class="checkmarkPsNp"></span>
</label>
<label for="MvrInFile" class="lblPolicyServiceList ml-1">MVR In File</label>
</div>
Here is the generated html for that.
<label class="d-inline-flex customcheckPsNp pb-1">
<input data-val="true" data-val-required="The MvrInFile field is required." name="_GetCompleteGroup1.MvrInFile" type="checkbox" value="true">
<input name="_GetCompleteGroup1.MvrInFile" type="hidden" value="false">
<span class="checkmarkPsNp"></span>
</label>
These checkboxes get sent to the controller and updated whether true or false. All but two of them.
Here is one of the offending Checkboxfors and the generated HTML. I suspect this is where the problem sits and the part I don't quite understand. The generated HTML is different from the others.
<div class="form-group ">
<label class="d-inline-flex customcheckPsNp pb-1">
#Html.CheckBoxFor(model => model._GetCompleteGroup1.LocInFile)
<span class="checkmarkPsNp"></span>
</label>
<label for="LocInFile" class="lblPolicyServiceList ml-1">LOC In File</label>
</div>
Now the generated HTML found in the console elements
<label class="d-inline-flex customcheckPsNp pb-1">
<input name="_GetCompleteGroup1.LocInFile" type="checkbox" value="true">
<input name="_GetCompleteGroup1.LocInFile" type="hidden" value="false">
<span class="checkmarkPsNp"></span>
</label>
As you can see the difference in the generated HTML is different. Does anyone know why and how to resolve this? I've tried manually creating the same html from above in place of this one, but that still doesn't work. I've looked at the model it all aligns. I would get an error if these bools weren't there. The controller accounts for bools within the model as well.
I suspect that these two check boxes are not being correctly sent with the model to the controller. Possibly due to the way the HTML is being generated. I could be way off, but it's the only clear thing that's different amongst the check boxes.
Grateful for the help.
I was just going to delete the question, but felt worthy a good lesson for others and some humble pie for myself. I had actually done everything right in my models, controllers, and my view. Except one important thing. I had tripled the times I was using the same model entity. After looking in the console > network, I could see how many times the checkboxfor name was actually used. I had a different label so I didn't realize I fat fingered and chose the same model entity multiple times. My mistake. Always check the easiest first. :)

Form POST not doing anything

I have a webapplication made in ASP.NET Core (latest version) which needs to use a pop-up form where 1 value has to be filled in and then send it back to the controller to later use that value.
So the process is like this: Button > Click on button > Pop-up form pops up (Image: pop-up form which is a partial view) > Fill in value > Submit > Send result back to controller.
But whenever I press the submit button it sends me to a 400 error not found page. What could go wrong?
Here is the partial view pop-up form code:
#model IEnumerable<ApplicationName.Models.Moederblad>
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper *, AuthoringTagHelpers
#Html.AntiForgeryToken()
<div id="element_to_pop_up">
<a class="b-close">x</a>
//Actionresult > Controller
#using (Html.BeginForm("Incassodatum", "Moederblads", FormMethod.Post))
{
<br />
<div class="row">
<div class="col-md-6">
<label for="Incassodatum">Incassodatum</label>
<input class="form-control" placeholder="Bijvoorbeeld: 19-02-2020" type="text" data-val="true" data-val-regex="Dat is geen geldige datum" data-val-regex-pattern="^(0[1-9]|[12][0-9]|3[01])[/](0[1-9]|1[012])[/](19|20)[0-9]{2}$, " id="Incassodatum" name="Incassodatum">
</div>
</div>
<div class="row">
</div>
<br>
<input name="__RequestVerificationToken" type="submit" class="btn btn-primary submit" value="Toevoegen" id="submit">
}
</div>
Here is the corresponding controller:
[HttpGet]
public ActionResult Incassodatum()
{
return View();
}
//Automatisch de datum van vandaag in het Incassodatum veld zetten nadat er op een knop is gedrukt
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Incassodatum(string Incassodatum)
{
string date= "";
if (ModelState.IsValid)
{
date = Incassodatum;
}
else
{
date = "Something went wrong.";
}
TempData["Incassodatum"] = $"{Incassodatum}";
return RedirectToAction("Index");
}
Then later I can use the tempdata to read out the value but its not working at all so that is actually useless for now.
I tried adding the [Route("Moederblads/Incassodatum")] property above the post.
I tried it in a normal view (So not a partial view) and there I could see the value with F12.
Tried changing object names as I thought it might conflict with other names.
Don't know what to do now. Any of you have a guess?
But whenever I press the submit button it sends me to a 400 error not found page.
A 400 error is a Bad Request. A 404 is a Not Found. As such, I'm not sure which you're actually getting here. However, based on the fact that you have an input with __RequestVerificationToken as the name, and you're using it wrong at that, I'm leaning towards the 400.
Since you're trying to use this input as a button, you've set a value on it to apply that text to the button. However, that's going to actually post that value for __RequestVerificationToken, and it's not a valid token. As such, you're going to always get a 400 Bad Request because of the failed request verification.
The request verification token should be on a hidden input, so the simplest solution is to remove the name from that button and add a hidden input specifically for the request verification token: #Html.AntiForgeryToken().
Even better would be to use the built-in FormTagHelper instead, which automatically takes care handling antiforgery tokens:
<form asp-action="Incassodatum" asp-controller"Moederblads" method="post">
...
</form>
Finally, while it doesn't technically effect anything, using input for buttons is an anti-pattern that should be avoided. Use <button type="submit"> instead.
Was something very easy in the end: I just had to delete the: [HttpPost] tag above the method and the [HttpGet] method as it did nothing in the end. After that it hit my break point and could verify that the value is coming through fine :)

Proper way to update a model in .net core 2.2 without having any security issues through hidden fields

When creating a scaffolded item (CRUD) Visual Studio creates multiple pages, I have a question in regards to the editing page. Here it creates the default layout to update your model which can be modified to meet your needs. The problem I see is that it creates a hidden input field for your Id. Isn't this a security issue since the input control can be edited? If this is edited, when you save by theory it would update a different item (hence a security issue)? Also What if I have a second field that shouldn't be edited for example "CreatedBy" should I just be creating another hidden field? If this field is also edited i will lose my original CreatedBy user.
Also if I remove these hidden input boxes to remove the security threat the issue I face is that the automatic validation will fail because it won't retain my Id or CreatedBy user on the model. This is also an issue when updating because the Id would also be lost. Whats the best and the proper way to handle this?
Below is a sample of the automatic code created by visual studio when you create a scaffolded item (CRUD):
...
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Test.Id" />
<div class="form-group">
<label asp-for="Test.Created" class="control-label"></label>
<input asp-for="Test.Created" class="form-control" />
<span asp-validation-for="Test.Created" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Test.CreatedBy" class="control-label"></label>
<input asp-for="Test.CreatedBy" class="form-control" />
<span asp-validation-for="Test.CreatedBy" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Test.Blahblah" class="control-label"></label>
<input asp-for="Test.Blahblah" class="form-control" />
<span asp-validation-for="Test.Blahblah" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
...
Anyhow I know this is something basic and I have been looking online for an answer to this but haven't been able to find one. I have found ways to check specific properties during validation, but this still will not ensure that I don't lose the Id and CreatedBy fields assuming I remove the hidden inputs.
It seems as if my only option is to have a security issue but I refuse to believe this is the correct method. Anyhow thank for the help!
There are 2 different things:
The Id to update.
There is no way to prevent sending the Id to a server when updating a dataset, because HTTP is stateless. Using workarounds with things like Session or TempData might prevent that, but may introduce different problems for users that work with multiple tabs (e.g. user loads object A, then in new tab loads object B, then saves object A in tab 1, which causes B to be overwritten since that's the last Id loaded in the session).
The solution here is validation and authorization (e.g. Resource-based authorization).
Over-binding/"mass assignment"
This is the issue when a client sends more information than it should (e.g. CreatedBy).
The solution for this is either a dedicated ViewModel containing only the editable fields or using attributes like [Editable] and [BindNever]. That way the Modelbinding won't bind fields that should be read-only. Here is a blogpost explaining that issue.
So the best way is to remove the hidden fields not used(e.g. CreatedBy) before sending to the client (unless you want to show it somewhere). Then to update the model you load the data from your database with the Id, update the posted editable properties (and other fields you want to set, e.g. a last updated date set in code) then save the model.

CSHTML displaying user inputs

My web assignment has asked me to create a dating site login page and display the information, i have completed the HTML to a point and am now beginning with the C#. I have began this but have come to a standstill as I dont know what is going wrong to display the information.
My question is: How do I get the "fName" to display itself in the "message" as when I submit it, the text comes up but there is no name when I type it into the textbox and submit it.
C#
#{
string message = "";
string fName;
fName = Request.Form["fName"];
string daySelect = Request.Form["submit"];
message = String.Format("Your first name is: {0}", Request.Form["fName"]);
}
HTML
<form method="post">
<label for="fName"></label>
First Name: <input type="text" name="fName" id="fName"
#(Request.Form["fName"]) /> <br/>
<br/><br/><input type="button" value="submit" />
<p>#message</p>
I recommend to look into ASP.NET MVC and how are models passed from controller to their views. This makes things you are doing here a lot of easier and less error prone. There are several tutorials out there.
Just looking at your HTML code a missing value attribute in the input field may be the cause. Please try
First Name: <input type="text" name="fName" id="fName" value="#(Request.Form["fName"])" /> <br/>
I found the problem.
Here is the submit that I have in:
<br/><br/><input type="button" value="submit" />
As you can see the type is button, for this code it should be of type "submit", tiny error in lots of code.
Thanks to rboe for the assistance.

Does ASP.NET MVC swallow submit values?

I have a single form in ASP.NET MVC (v1) that has 2 input buttons. Each submit button has to be contained within this single form and I need to know which one the user pressed.
I know about the trick to check the FormCollection values which will be returned based on the button pressed. For example, if I have and and the user clicks Button2, I should be able to say Request.Form["Button2"] != null and that will evaluate to true in which case I know that the user clicked that button.
However, this is not working for me. The values of all my buttons is null as non of them are contained within the Request.Form values. Is there a bug in ASP.NET MVC which swallows these values?
Here is my form code:
<% using (Html.BeginForm()) {%>
<% Html.RenderPartial( "EditAreaControl", Model ); %>
<div class="form-layout-command-container">
<div class="form-layout-command-area-alpha"><button type="submit" name="submit1" value="Save">Save</button></div>
<div class="form-layout-command-area-alpha"><button type="submit" name="submit2" value="SaveAndCopy">Save and Create Copy</button></div>
<div class="form-layout-command-area-beta"><%= Html.ActionLink("Cancel", "list") %></div>
</div>
<% } %>
Here is my controller code:
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult Add(FormCollection values )
{
if (values["submit1"] != null)
// always false
if (values["submit2"] != null)
// always false as well
}
From w3schools:
Important: If you use the button element in an HTML form, different browsers will submit different values. Internet Explorer will submit the text between the and tags, while other browsers will submit the content of the value attribute. Use the input element to create buttons in an HTML form.
It seems that this is not standardized. You should stick to
<input type="submit" name="submitButton" value="Save" />
<input type="submit" name="submitButton" value="Cancel" />
I would use inputs of type submit instead of buttons. Non-inputs may not passed back in a form post or at least can be passed back inconsistently. Note that they can have the same name with different values so that you can use the same parameter for any button that submits the form.
<input type="submit" name="submitButton" value="Save" />
<input type="submit" name="submitButton" value="SaveAndCopy" />
public ActionResult Save( string submitButton, ... )
{
if (submitButton == "Save")
{
...
}
else if (submitButton == "SaveAndCopy")
{
...
}
....
}
Using Firebug, I found that the submit buttons were not being sent in the response and because of that, there isn't much I can do on the MVC side. I decided to use a client side hack to populate a hidden input field on the client side which would be passed to the controller values.
I changed the input buttons to be:
<input type="submit" value="Save" onclick="actions.copyValues($(this), $('#submitAction'));" />
<input type="submit" value="Save and Copy" onclick="actions.copyValues($(this), $('#submitAction'));" />
<input type="hidden" id="submitAction" name="submitAction" />
The jquery script simply copies the values:
Actions.prototype.copyValues = function(from, to) {
$(to).val($(from).val());
};
The controller action then looks for the hidden input values:
var request = HttpContext.Request;
return request.Form["submitAction"];
This solves the issue from above but I realize it is not that clean.
Put them in two different forms and you will know which one submitted based on which action was called on the controller.

Categories

Resources