How to validate a duplicate post request from a form in MVC - asp.net-mvc

I am having an form which insert a record whenever a post request is made,but the problem is that if someone clicks submit button more than 1 times than duplicate post request are made and at the end same records are getting inserted. I dont want to check that the record is already present or not because the record would be different always. I tried using ValidateAntiForgeryToken filter in controller but it is failing to validate the requests, Below is my View Code.
#using (Html.BeginForm("Create", "Home",FormMethod.Post,new { onkeydown = "return event.keyCode!=13" }))
{
#Html.AntiForgeryToken()
<div class="right-col">
#Html.TextBoxFor(model => model.Name, new { placeholder = "Name", #class = "small-box" })
</div>
<div class="left-col">Email Id :</div>
<div class="right-col">
#Html.TextBoxFor(model => model.EmailId, new { placeholder = "Email Id", #class = "small-box",id="resumeemailid" })
#Html.ValidationMessageFor(model => model.EmailId)
</div>
<div class="left-col">Address :</div>
<div class="right-col">
#Html.TextAreaFor(model => model.Address, new { placeholder = "Address", #class = "small-box" })
</div>
<div class="buttons resume-threebutton">
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Upload", "Upload")" name="Command" />
<input type="submit" id="register-button" class="gradient-btn" value="#T("Account.Passport.Button.UploadandAdd", "Upload And Add New")" name="Command" />
<input type="button" id="register-button" class="gradient-btn" value="#T("Account.Passport.Register.Button.Cancel", "cancel")" name="register-button" onclick="location.href='#Url.Action("SelectTemplate", "CustomerTemplate")'" />
</div>
}
and below is my controller Post method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ProductModel model)
{
//To do add the product here...
}

Related

Model Data not binding to textboxfor after insertion in MVC

I'm facing a problem in mvc 4, i have create action method where i insert the data in db and then return model to View but the model data not bind to hidden Field like Id and Voucher number,
in other fields data binds properly but the issue is with these Id and VoucherNum, Id is primary key and VoucherNum is Unique.
I have mentioned the code and html.
Code:
[HttpPost]
public ActionResult Create(Payment payment)
{
payment.VoucherNum = db.Payments.Count() + 1;
Ledger ledger = new Ledger();
ledger.CusId = payment.CustomerId;
ledger.Date = payment.Date;
ledger.Remarks = payment.Remarks;
ledger.Type = payment.Type;
string negativeAmount;
negativeAmount = "-" + payment.Amount;
ledger.Amount = Convert.ToInt32(negativeAmount);
ledger.IsActive = true;
payment.IsActive = true;
db.Payments.Add(payment);
db.Ledgers.Add(ledger);
db.SaveChanges();
ViewBag.CustomerId = new SelectList(db.Customers.ToList()
.Select(x => new { Id = x.Id, CustomerCode = x.Name + "-" + x.CustomerCode }
), "Id", "CustomerCode", payment.CustomerId);
var model = db.Payments.Find(payment.Id);
return View(model);
}
<h2>Payments</h2>
<hr />
<div class="row">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Vocher#</label>
#Html.TextBoxFor(model => model.VoucherNum, new { #class = "form-control", #readonly="true"})
#Html.HiddenFor(model=>model.Id)
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Customer</label>
#Html.DropDownList("CustomerId", (IEnumerable<SelectListItem>)ViewBag.CusId, "--Select Customer--", new { #class = "form-control" })
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Date</label>
#Html.TextBoxFor(model => model.Date, new { #class = "form-control", #id = "date"})
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Amount</label>
#Html.TextBoxFor(model => model.Amount, new { #class = "form-control" })
</div>
<div class="form-group">
<label class="control-label">Type</label>
#Html.TextBoxFor(model => model.Type, new { #class = "form-control" })
</div>
</div>
<div class="col-md-8">
<div class="form-group">
<label class="control-label">Remarks</label>
#Html.TextAreaFor(model => model.Remarks, new { #class = "form-control", #rows = "5" })
</div>
<input type="submit" value="Payment Receive" class="btn btn-primary pull-right" />
</div>
}
</div>
Because the helper method will look in to the model state dictionary first to populate the value of the input. The model state dictionary currently has null value for the VoucherNum before you saved it, and the helper method will use this value to generate the value of the input field.
To fix this, you can explicitly clear the model state dictionary before returning to the view,
db.Payments.Add(payment);
db.SaveChanges();
ModelState.Clear();
var p = db.Payments.Find(model.Id);
return View(p);
Or even better, follow the PRG pattern. With the Post-Redirect-Get pattern, After successfully updating the database, you will return a Redirect Response back to the client and the client will issue a totally new GET request to the server.
In your case, You can use RedirectToAction to return a 302 response.
db.SaveChanges();
return RedirectToAction("Edit",new {id=payment.Id});
This will tell the browser to issue a new GET request for Edit action method with the new id in the request url. Your GET action method will use this id and get the entity from db and return it.
public ActionResult Edit(int id)
{
var model = db.Payments.Find(id);
return View(model);
}
I strongly recommend you using the PRG pattern.

ASP.NET MVC - A potentially dangerous Request.Form value was detected from the client

Am trying to click save button to update what I have in text editor using ckeditor but I got this error
A potentially dangerous Request.Form value was detected from the client (OPTION_VALUE="Welcome to the Na...").
The controller is shown below
Controller
public ActionResult EditRegistrationGuideline(long id)
{
OPTIONS options = _optionsService.GetOption(id);
return View(options);
}
//
// POST: /Product/Edit/5
[HttpPost]
public ActionResult EditRegistrationGuideline(long id, OPTIONS options)
{
try
{
// TODO: Add update logic here
if (ModelState.IsValid)
{
options.OPTION_ID = id;
options.ACTION_STATUS = 0;
options.CREATED_DATE = DateTime.Now;
_optionsService.AddOption(options);
return RedirectToAction("Index");
}
}
catch
{
//return View();
ModelState.AddModelError("", "We cannot edit this Option. Verify your data entries !");
}
return View();
}
and the view is here
View
#{
//ViewBag.Title = "CreateRegistrationGuideline";
}
<div class="content-header clearfix">
<h1 class="pull-left">
<i class="fa fa-plus"> </i> Edit Registration Guideline
</h1>
<div class="col-xs-3 pull-right">
<input type="button" class="btn btn-block btn-warning" value="Back" onclick="location.href='#Url.Action("IndexRegistrationGuideline", "Options")'" />
</div>
<div class=" box box-body box-primary">
#using (Html.BeginForm("EditRegistrationGuideline", "Options", FormMethod.Post, new { #class = "form-horizontal", #enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#*<h4>OPTIONS</h4>
<hr />*#
#*#Html.ValidationSummary(true)*#
#Html.ValidationSummary(false, null, new { #class = "text-danger" })
<div class="row .col">
<div style="margin-top:20px" class="mainbox col-md-12 col-md-offset-0 col-sm-8 col-sm-offset-2">
<div class="panel panel-info">
<div class="panel-heading">
<div class="panel-title">Edit Option</div>
</div>
<div class="panel-body">
#*<div class="form-group">
#Html.LabelFor(model => model.OPTION_NAME, new { #class = "control-label col-md-2" })
<div class="col-md-10">*#
#*#Html.LabelFor(model => model.OPTION_NAME, new { #class = "control-label col-md-2" })
<div class="col-md-10">*#
#*#Html.EditorFor(model => model.OPTION_NAME)*#
#*#Html.HiddenFor(model => model.faculty_activation_date, new { #Value = System.DateTime.Now })*#
#Html.HiddenFor(model => model.OPTION_NAME)
#Html.ValidationMessageFor(model => model.OPTION_NAME)
<div class="form-group">
#*#Html.LabelFor(model => model.OPTION_VALUE, new { #class = "control-label col-md-2" })*#
<div class="col-md-10">
#Html.LabelFor(model => model.OPTION_VALUE, "Option Value")
#*<textarea class="form-control" placeholder="Enter Option Value" name="OPTION_VALUE" id="editor1"></textarea>*#
#Html.TextAreaFor(model => model.OPTION_VALUE, new { #class = "form-control", #id = "editor1" })
#Html.ValidationMessageFor(model => model.OPTION_VALUE, "", new { #class = "text-danger" })
</div>
</div>
#*<div>
#Html.LabelFor(model => model.OPTION_VALUE, "Option Value")
#Html.TextAreaFor(model => model.OPTION_VALUE, new { #type = "textarea", #id="editor1", #class = "form-control", #placeholder = "Enter Option Value", #autocomplete = "on" })
#Html.ValidationMessageFor(model => model.OPTION_VALUE, null, new { #class = "text-danger" })
</div>*#
#*<div class="form-group">
#Html.LabelFor(model => model.ACTION_STATUS, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ACTION_STATUS)
#Html.ValidationMessageFor(model => model.ACTION_STATUS)
</div>
</div>*#
</div>
<div class="panel-footer">
<div class="panel-title">
<div class="form-actions no-color">
<input type="submit" value="Save" class="btn btn-success" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
}
#*<div>
#Html.ActionLink("Back to List", "Index")
</div>*#
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery-3.1.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="https://cdn.ckeditor.com/4.5.7/standard/ckeditor.js"></script>
<script>
$(function () {
CKEDITOR.replace('editor1');
});
</script>
}
Please what do I do.
I use CKEDITOR
XSS error ("A potentially dangerous Request.Form value was detected from the client(...)").
Solution:
[ValidateInput(false)]
Differnce b/w them
AllowHtml:
The AllowHtml attribute can be applied to a Model property and it will disable the validation by ASP.Net MVC only for that particular property
Advantages
The AllowHtml attribute is developed for Model class.
The Scope is limited to specific property of the Model class.
It is the safe and recommended solution.
ValidateInput
The ValidateInput attribute can be applied to a Controller’s Action method and it will disable the validation by ASP.Net MVC only for that particular Action method.
Advantages
The Scope is limited to specific Action method of the Controller class.
If you have multiple properties accepting HTML content, then this method will reduce redundancy.
When Model class is not used for designing Form elements then this attribute is needed.For complete details Link
Just place ValidateInput(false) attribute on controller's action.
[HttpPost]
[ValidateInput(false)]
public ActionResult EditRegistrationGuideline(long id, OPTIONS options)
The other option is to place [AllowHtml] attribute on Model Property, have a look on SO post to get difference between them
ValidateInput(false) vs AllowHtml
I was experiencing a similar issue with the following error message A potentially dangerous Request.Form value was detected from the client.
As an alternative to the previous answers, I found encoding the value passed back to the controller worked. CKEditor allows you to do this by setting the config config.htmlEncodeOutput = true;.
The documentation for this can be found at: https://docs-old.ckeditor.com/ckeditor_api/symbols/CKEDITOR.config.html#.htmlEncodeOutput
I got this error while testing XSS on my site.
This is a very good feature that the model gives us that prevents XSS, CSRF from penetrating your site.
Do not disable it as much as possible.

MVC parial view going to get method rather than post on submit

I have a partial view which shows a search box with a couple of options
model PatientSearchViewModel
#using (Html.BeginForm("Index", "Patient", FormMethod.Post, new { #class = "form-inline" }))
{
<form class="form-inline">
<label style="padding-right:20px;">Search for a patient</label>
#Html.EditorFor(model => model.SearchText, new { htmlAttributes = new { #class = "form-control", placeholder = "Search...", autocomplete = "off" } })
<div class="checkbox">
<div class="checkbox" style="padding-left:20px; padding-right:20px;">
<label>#Html.EditorFor(model => model.ShowOnlyOpenClients) Show only open clients</label>
</div>
</div>
<button type='submit' name='seach' id='search-btn' class="btn btn-primary"><i class="fa fa-search"></i>Search</button>
</form>
}
When the submit button is hit I want it to go to my method below with the search content already complete, however instead it goes to the HttpGet method which is bringing back a null for the PatientSearchViewModel.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(PatientSearchViewModel patient)
{
PatientSearchViewModel patientVM = GetSearchResults(patient);
return View(patientVM);
}
Can anyone explain how I can get this to work?
I have executed the code snippet you pasted here and found that
As you are making the use of the [ValidateAntiForgeryToken]
attribute so you need to add the #Html.AntiForgeryToken(); this
statement in your partial view inside the
#using(Html.BeginForm()){ } block.
One more thing make sure that your action method will be inside the
PatientController.
For your reference (this is my code)
#model WebApplication.Models.PatientSearchViewModel
#using (Html.BeginForm("Index", "Patient", FormMethod.Post, new { #class = "form-inline" }))
{
#Html.AntiForgeryToken();
<label style="padding-right:20px;">Search for a patient</label>
#Html.EditorFor(model => model.SearchText, new { htmlAttributes = new { #class = "form-control", placeholder = "Search...", autocomplete = "off" } })
<div class="checkbox">
<div class="checkbox" style="padding-left:20px; padding-right:20px;">
<label>#Html.EditorFor(model => model.ShowOnlyOpenClients) Show only open clients</label>
</div>
</div>
<button type='submit' name='seach' id='search-btn' class="btn btn-primary"><i class="fa fa-search"></i>Search</button>
}
Suggestion: As you have used the #using(Html.BeginForm()) which will any way going to convert to <form> tag so instead of using another <form class="form-inline"> inside it is creating the confusion please you may remove it.
I hope this will solve your problem.

Retrieving dropdown values from partial view during post method

I need to get the selected dropdown value from partial view and included in the CategoryID in the Book class...
[Authorize]
public PartialViewResult GetAllCategory()
{
ProcessSVC.Category newCategory = new ProcessSVC.Category();
newCategory.ChildCategories = obj1.GetAllCategories(String.Empty);
return PartialView(newCategory);
}
GetAllCategory.cshtml (PartialView)
#model MvcAdminTemplate.ProcessSVC.Category
#Html.DropDownListFor(m => m.ParentID, new SelectList(Model.ChildCategories, "ID", "DisplayName"), new { #class = "form-control" })
Create View:
[Authorize]
[HttpPost]
public ActionResult Create()
{
MvcAdminTemplate.ProcessSVC.Book oBook = new ProcessSVC.Book();
return View(oBook);
}
Create.cshtml
#model MvcAdminTemplate.ProcessSVC.Book
#{
ViewBag.Title = "Create";
}
#Html.Partial("_LeftMenu")
<!-- content -->
<h2>Create</h2>
<div class="col-md-10">
#using (Html.BeginForm("Create", "Books", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="row">
<div class="bootstrap-admin-no-table-panel-content bootstrap-admin-panel-content collapse in">
<form class="form-horizontal">
<fieldset>
<legend>Add Book</legend>
<div class="form-group">
<div class="col-lg-2">
#Html.LabelFor(m => m.BookName, new { #class = "control-label" })
</div>
<div class="col-lg-10">
#Html.TextBoxFor(m => m.BookName, new { #class = "form-control", type = "text" })
<p class="help-block"> </p>
</div>
</div>
<div class="form-group">
<div class="col-lg-2">
#Html.LabelFor(m => m.Description, new { #class = " control-label" })
</div>
<div class="col-lg-10">
#Html.TextBoxFor(m => m.Description, new { #class = "form-control ", type = "text" })
<p class="help-block"> </p>
</div>
</div>
<div class="form-group divCategory">
<div class="col-lg-2">
#Html.Label("Parent Category", new { #class = " control-label" })
</div>
<div class="col-lg-10">
#Html.HiddenFor(m => m.BookId, new { #class = "hdn-id" })
#Html.Action("GetAllCategory","Books")
<span class="help-block"> </span>
</div>
<button type="submit" class="btn btn-primary">Save changes</button>
<button type="reset" class="btn btn-default">Cancel</button>
</div>
</fieldset>
</form>
</div>
</div>
}
After submission of the above form i need to get Book attributes and Category "Selected Category".
[Authorize]
[HttpPost]
public ActionResult Create(ProcessSVC.Book oBook)
{
oBook.LanguageID = 1;
_service.AddBooks(oBook.ActualPrice,oBook.ActualPriceString, oBook.Author, oBook.BookId, oBook.BookName, oBook.CategoryID, oBook.Currency, oBook.CurrentPrice, oBook.CurrentPriceString,
oBook.Description, oBook.DiscountPercentage, oBook.DiscountValue, oBook.LanguageID,
oBook.NativeLanguageName, oBook.Publisher);
TempData.Add("SuccessMessage", " New book " + oBook.BookName + " Added !");
return RedirectToAction("Index");
}
Please suggest me.
To correctly bind your model, you need to create the dropdown in the main view. This line in you partial view
#Html.DropDownListFor(m => m.ParentID, ....
will render a select
<select name="ParentID" ...
but you model is expecting a property named CategoryID
In you Create() method, generate the SelectList and assign to a view model property or to ViewBag and then (instead or #Html.Action("GetAllCategory","Books") use
#Html.DropDownListFor(m => m.CategoryID, ....
use this line in your GetAllCategory.cshtml file
#Html.DropDownList("CategoryID", new SelectList(Model.ChildCategories, "ID", "DisplayName"), new { #class = "form-control" })

Validation stopped working on use of formmethod.post

I am trying to post external URL for eg. (www.msn.com) on press of submit button.But when I do that none of my valdation works...it simply make an entry without any data in my external url
2. Also its not going to controller when i press submit button.
I don't know if I am doing anything wrong...
Here is my code for View:
#model n.Models.PopupDemoModel
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm("Demo","Home", FormMethod.Post, new { #action = "https://www.msn.com?encoding=UTF-8/post" }))
{
#Html.ValidationSummary(true)
<fieldset>
<input type=hidden name="oid" value="">
<input type=hidden name="retURL" value = "test" />
<input type="hidden" name="debug" value=1 />
<input type="hidden" name="debugEmail" value = "a#test.com" />
<div class="editor-label grid_2">
#Html.LabelFor(model => model.first_name)
</div>
<div class="editor-field grid_3">
#Html.TextBoxFor(model => model.first_name, new { #class = "demo-field-longer" })
</div>
<div class="grid_3 error long" style="margin-left:250px">
#Html.ValidationMessageFor(model => model.first_name)
</div>
<div class="clear"></div>
<div class="editor-label grid_2">
#Html.LabelFor(model => model.email)
</div>
<div class="editor-field grid_3">
#Html.TextBoxFor(model => model.email, new { #class = "demo-field-longer" })
</div>
<div class="grid_3 error long" style="margin-left:250px">
#Html.ValidationMessageFor(model => model.email)
</div>
<div class="clear"></div>
<div class="editor-label grid_2">
#Html.LabelFor(model => model.phone)
</div>
<div class="editor-field grid_3">
#Html.TextBoxFor(model => model.phone, new { #class = "demo-field-longer" })
</div>
<div class="grid_3 error long" style="margin-left:250px">
#Html.ValidationMessageFor(model => model.phone)
</div>
<div class="clear"></div>
<div class="editor-label grid_2">
#Html.LabelFor(model => model.company)
</div>
<div class="editor-field grid_3">
#Html.TextBoxFor(model => model.company, new { #class = "demo-field-longer" })
</div>
<div class="grid_3 error long" style="margin-left:250px">
#Html.ValidationMessageFor(model => model.company)
</div>
<div class="clear"></div>
<div class="clear"></div>
<div class="grid_2 sub-spacer"> </div>
<div class="editor-field grid_2 submit">
<input type="submit" value="Submit" id="demo-submit-button"/><br />
#ViewData["DemoMessage"]
</div>
</fieldset>
Here is my model:
public class PopupDemoModel
{
[Required]
[Email]
[DisplayName("Email address")]
public string email { get; set; }
[Required]
[DisplayName("Phone number")]
public string phone { get; set; }
[Required]
[DisplayName("Contact name")]
public string first_name { get; set; }
[Required]
[DisplayName("Company name")]
public string company { get; set; }
public string MessageSent
{
get { return "We'll contact you shortly."; }
}
}
It's doing exactly what you told it to.
The HTML <form> tag sends a POST request to the URL in the action attribute.
Html.BeginForm() creates a <form> tag with an action attribute that points to your controller.
When you set the action attribute explicitly, you replace the value from MVC and make it go directly to that URL.
If you want to do something with your data on server side before posting to another website, remove the action attribute so you will be posting to the same URL as at the beggining. In the action that is handling the POST from this form and doing the validation prepare your data. When you're ready, use WebRequest class to send this data to another website using POST method.

Resources