Ajax.beginform with captcha fails when captcha input is invalid - asp.net

Im using CaptchaMvc.Mvc4 1.5.0 in a form with #Ajax.BeginForm in my Asp.net MVC4 application. when input is valid it works fine. but when captcha input is invalid. dispose method is called and i cant resubmit the message. and the captcha image dosnt change.
This is my View:
#using CaptchaMvc.HtmlHelpers;
#using CaptchaMvc;
#model Web.Models.Message
#using (Ajax.BeginForm("Contact", "Home", new AjaxOptions
{
HttpMethod = "post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "Sent"
}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
#Html.LabelFor(model => model.Message1)
#Html.TextBoxFor(model => model.Message1)
#Html.ValidationMessageFor(model => model.Message1)
#Html.MathCaptcha()
<input type="submit" value="Create" />
</fieldset>
<div id="Sent">
</div>
}
And this is my Action method:
[HttpPost]
public ActionResult Contact(Message message)
{
if(this.IsCaptchaValid("error"))
if (ModelState.IsValid )
{
db.Messages.Add(message);
db.SaveChanges();
return RedirectToAction("SuccessfullySent");
}
ModelState.AddModelError("", "there is some error");
return Content("there is some error");
}
ps: I tested it with #htmal.Beginform and it worked fine. some how problem is related to #Ajax.Beginform.

the trick is create a partial view and put code for generate captcha on it :
#using CaptchaMvc.HtmlHelpers
#using CaptchaMvc;
<div>
#Html.MathCaptcha()
</div>
<div>
#ViewBag.CaptchaInvalid
</div>
<div>
#ViewBag.Successfully
</div>
and in the main form where the ajax.beginform is put rendering this parcial view on the updateTargetId div "Sent":
<div id="Sent">
#{Html.RenderPartial("~/Views/Shared/CaptchaGenerate.cshtml");}
</div>
and in the action method make this changes:
[HttpPost]
public ActionResult Contact(Message message)
{
if(this.IsCaptchaValid("error"))
if (ModelState.IsValid )
{
db.Messages.Add(message);
db.SaveChanges();
ViewBag.CaptchaInvalid = "";
ViewBag.Successfully = "successfully sent";
return PartialView("~/Views/Shared/CaptchaGenerate.cshtml");
}
ModelState.AddModelError("", "there is some error");
ViewBag.CaptchaInvalid = "";
ViewBag.Successfully = "";
return PartialView("~/Views/Shared/CaptchaGenerate.cshtml");
}

Related

ASP.NET MVC – Use Html.BeginForm to pass model data and non-model hidden field value

I’m using BeginForm to pass model data (i.e. last_coffe_time) which works fine. However I also wanted to pass to controller ClientDateTime value stored in hidden field which is not a part of the model.
I don’t know how do do it, at best I can pass ClientDateTime as static string but I can't figure out how to dynamically read hidden field for value and pass that value to controller.
Someone please help. Thank you
View:
#model SleepNotes.Models.Diary
#using (Html.BeginForm("Edit", "Diary", new { ClientDateTime = "ClientDateTime" }, FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.Hidden("ClientDateTime", new { id = "ClientDateTime" })
<div class="form-group">
#Html.LabelFor(model => model.last_coffe_time, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.last_coffe_time, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.last_coffe_time, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<!--Set ClientDateTime-->
<script>
var a = new Date()
var month = a.getMonth() + 1;
document.getElementById('ClientDateTime').value = a.getDate() + "/" + month + "/" + a.getFullYear() + " " + a.getHours() + ":" + a.getMinutes() + ":" + a.getSeconds();
</script>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "id,last_coffe_time")] Diary Diary, string ClientDateTime)
{
if (ModelState.IsValid)
{
//ClientDateTime from view ...do something here
db.Entry(Diary).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index", "Dashboard");
}
return View(Diary);
}
Remove the new { ClientDateTime = "ClientDateTime" } from the BeginForm() method so the vale is not added as a route parameter (and therefore not bound to your string ClientDateTime parameter in the Edit() method.
Side note: since your wanting to submit a DateTime value, your parameter should be DateTime ClientDateTime (not string) and your script can be simplified to
document.getElementById('ClientDateTime').value = new Date().toISOString();
There are some solutions,
I suggest you to have a ModelView between your Model and View. That
modalview should have the ClientDateTime.
You can use ajax post and send 2 parameters (yourmodal, string) to controller or you
can pass the ClientDateTime as querystring. There are lots of
examples about it.
Hope helps.

How to pass model from one partial view to another partial view

I have a model called Result. Suppose this has 4 fields, like student_id, marks, status, remarks.
Now I have a view in which student listing is shown. In front of each student, there is a button for enter marks of exam. On clicking on button a pop-up will open and there will be 2 fields student_id, marks and 2 buttons 'pass' and 'fail'.
On clicking on fail button another pop-up will appear for enter remarks only.
Now my question is that, how can I retain values of first pop-up on second pop-up, As on clicking on 'submit' button of second pop-up, I will save all the details.
I know a way to do this using hidden fields in second pop-up. Is there any other way to do this?
Model classes are:
1. User (id, name, f_name, address...)
2. Result (student_id, marks, grade, remarks)
Student List view
#{
List<User> Student = (List<User>)ViewData["Student"];
}
<table id="table_id">
<tr>
<th class="dbtc">S.No.</th>
<th class="dbtc">Student Name)</th>
<th style="width: 110px">Operate</th>
</tr>
#foreach (User usr in Student)
{
int index = Student.IndexOf(usr);
<tr>
<td class="dbtc">
#(Student.ToList().IndexOf(usr) + 1)
</td>
<td>
#Html.ActionLink(usr.FirstName + " " + usr.LastName, "Details", "User", new { id = usr.Id }, null)
</td>
<td>
#Ajax.ActionLink("Examine", "Result", new { id = Model.Id, userId = usr.Id }, new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "divPopup",
InsertionMode = InsertionMode.Replace,
OnSuccess = "openPopup('Examine Content')"
})
</td>
</tr>
First Partial view of examine
#model ComiValve.Models.Result
#using (Html.BeginForm("ExamPass", "Student", new { #id = (int)ViewBag.id, userId = (int)ViewData["UserId"] }, FormMethod.Post))
{
<div id="divExamAdvice"></div>
<div class="editor-label">
#Html.DisplayNameFor(model => model.Name)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Marks)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Grade)
</div>
<div class="login_submit_div">
<input type="submit" value="Pass" />
#Ajax.ActionLink("Fail", "ExamAdvice", new { id = (int)ViewBag.id, userId = (int)ViewData["UserId"] }, new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "divPopup",
OnSuccess = "openPopup('Exam Advice')"
})
</div>
}
Second partial view for remaks (when user click on fail, then this view will open.)
#model ComiValve.Models.ExamContent
#using (Html.BeginForm("ExamFail", "Student", new { id = Model.id }, FormMethod.Post))
{
<div id="divExamAdvice"></div>
<div class="editor-label">
#Html.DisplayNameFor(model => model.Remarks)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Remarks)
</div>
<div class="left">
<input type="submit" value="Confirm Fail" />
</div>
}
Methods of Controller
public virtual ActionResult ExamContent(int id, int userId)
{
ViewBag.IsApprove = true;
ViewBag.UserId = userId;
ViewBag.id = id;
return PartialView("ExamContent");
}
public virtual ActionResult ExamAdvice(int id, int userId)
{
ViewBag.IsApprove = true;
if (Request.IsAjaxRequest())
{
Result result = new Result();
result.id = id;
result.User = db.Users.Find(userId);
return PartialView("ExamAdvice", result);
}
else
{
return RedirectToAction("Index");
}
}
Why are you passing the model between partial views. You can create a single Model and use it on both the views. In case of having two different tables, create the two different "Lists" of "Table" type. Like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;
namespace LearningMVCapp.Models
{
public class Data
{
public List<tbl_Dept> lstDepatrment;
public List<tbl_employees> lstEmployees;
//other properties
}
}
You can also use session instead of hidden fields, refer this link http://www.dotnet-tricks.com/Tutorial/mvc/906b060113-Controlling-Session-Behavior-in-Asp.Net-MVC4.html.

Ajax.Beginform + Partial view + Model state are not working together

I have the following Create action method inside my ASP .NET MVC :-
public ActionResult CreateVMNetwork(int vmid)
{
VMAssignIps vmips = new VMAssignIps()
{
TechnologyIP = new TechnologyIP() { TechnologyID = vmid},
IsTMSIPUnique = true,
IsTMSMACUnique = true
};
return PartialView("_CreateVMNetwork",vmips);
}
Which will render the following partial view:-
#model TMS.ViewModels.VMAssignIps
#using (Ajax.BeginForm("CreateVMNetwork", "VirtualMachine", new AjaxOptions
{
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "networktable",
LoadingElementId = "loadingimag",
HttpMethod= "POST"
}))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model=>model.TechnologyIP.TechnologyID)
<div>
<span class="f">IP Address</span>
#Html.EditorFor(model => model.TechnologyIP.IPAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.IPAddress)
<input type="CheckBox" name="IsTMSIPUnique" value="true" #(Html.Raw(Model.IsTMSMACUnique ? "checked=\"checked\"" : "")) /> |
<span class="f"> MAC Address</span>
#Html.EditorFor(model => model.TechnologyIP.MACAddress)
#Html.ValidationMessageFor(model => model.TechnologyIP.MACAddress)
<input type="CheckBox" name="IsTMSMACUnique" value="true" #(Html.Raw(Model.IsTMSMACUnique ? "checked=\"checked\"" : "")) />
</div>
<input type="submit" value="Save" class="btn btn-primary"/>
}
Inside the following main view, after clicking on the Ajax.actionlink:-
#Ajax.ActionLink("Add Network Info", "CreateVMNetwork","VirtualMachine",
new { vmid = Model.VirtualMachine.TMSVirtualMachineID },
new AjaxOptions {
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "AssignNetwork" ,
LoadingElementId = "progress"
}
)
</p>
<p><img src="~/Content/Ajax-loader-bar.gif" class="loadingimage" id="progress" /></p>
<div id ="AssignNetwork"></div>
Then when clicking on the “Save” button it will call the following action method:-
[HttpPost]
public ActionResult CreateVMNetwork(VMAssignIps vmip)
{
if (ModelState.IsValid)
{
try
{
repository.InsertOrUpdateVMIPs(vmip.TechnologyIP,User.Identity.Name);
repository.Save();
return PartialView("_networkrow",vmip);
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, "Error occurred: " + ex.InnerException.Message);
}}
return PartialView("_CreateVMNetwork", vmip);
}
When will render the following partial view _networkrow:-
#model TMS.ViewModels.VMAssignIps
<tr id="#Model.TechnologyIP.ID">
<td> #Model.TechnologyIP.IPAddress</td>
<td>#Model.TechnologyIP.MACAddress</td>
<td>#Ajax.ActionLink("Delete",
"DeleteNetworkInfo", "VirtualMachine",
new { id = Model.TechnologyIP.ID },
new AjaxOptions
{ Confirm = "Are You sure You want to delete (" + Model.TechnologyIP.IPAddress + ")" + "( " + Model.TechnologyIP.MACAddress + ").",
HttpMethod = "Post",
OnSuccess = "deletionconfirmation",
OnFailure = "deletionerror"
})</td>
</tr>
All the above will work fine unless a model state error or an exception occurred , then in this case the table will be updated with the partial view and the model state will be displayed under the table with the fields. But I need to display the model state error on the same original view. So that I need the Ajax.begin form to update the table only if no exception or model state errors occured, and to display an error message inside the original partial view, not under the table.
Can anyone advice on how to solve this issue?
I don't get your question clearly, however I think you should place a <div> into your view where you want to show errors.
Then, if you got some errors on your processing, push some error messages through ViewBag to the model.
So, your action method will become like this:
[HttpPost]
public ActionResult CreateVMNetwork(VMAssignIps vmip)
{
if (ModelState.IsValid)
{
try
{
repository.InsertOrUpdateVMIPs(vmip.TechnologyIP,User.Identity.Name);
repository.Save();
return PartialView("_networkrow",vmip);
}
catch (Exception ex)
{
ViewBag.ErrorMessage = "Some messages...";
// also any other info you like
}
}
return PartialView("_CreateVMNetwork", vmip);
}
And that in your view like this:
<div>
<p>#ViewBag.ErrorMessage</p>
</div>
So, if you you got some errors, they'll be shown in that
Where is networktable defined? Remember that even if there is an exception (since you have caught it) or ModelState error, the ajax response will come back with status 200 and the OnSuccess will be executed. In the case of the save button, the returned response from the server will be inserted after the html of whatever networktable contains already. If you want special action to be taken when there is a failure, you have to change the response status on the server and catch it through a function on the client side called by OnFailure on the ajax form.

Recognize particular id in ajax form mvc3 from several hyperlink

I am currently working on a MVC3 project. I currently stuck on this portion.
I have this Ajax form which contains several hyperlink
#using (Ajax.BeginForm("Click", new AjaxOptions { UpdateTargetId = "showpage" }))
{
<a href="#" id="0" onclick='document.forms[0].submit()'>Link 0</a>
<a href="#" id="1" onclick='document.forms[0].submit()'>Link 1</a>
}
I have this function called "Click" in a controller to fire whenever there'a link clicked.
public ActionResult Click(String id)
{
// Action here
}
However, Whenever I click one of the hyperlinks, the click function receive id as "null". I want the function to know which hyperlink is click when enter the controller. Help needed :(
From my understanding, I think you're after something like this:
HTML:
<div id="showpage">
</div><br />
#using (Ajax.BeginForm("Click", "", new AjaxOptions { UpdateTargetId = "showpage" },
new { #id = "myAjaxForm" }))
{
#Html.ActionLink("Link 0", "Click", null, new { #id = "Link0", #data_val = "0", #class = "links" })
#Html.ActionLink("Link 1", "Click", null, new { #id = "Link1", #data_val = "1", #class = "links" })
#Html.Hidden("id", "");
}
SCRIPT:
<script>
$(function () {
$('a[class=links]').click(function (e) {
e.preventDefault();
$("input#id").val($(this).attr("data-val"));
$('form#myAjaxForm').submit();
});
});
</script>
CONTROLLER:
public ActionResult Click()
{
var m = new MyModel();
return View(m);
}
[HttpPost]
public ActionResult Click(string id)
{
return Content("ID = " + id, "text/html");
}
Hope this helps
I would recommend you to use a separate forms per button (which contrary to classic WebForms is something that you should not be afraid of in ASP.NET MVC) and of course use submit buttons instead of hyperlink which are the semantically correct element to submit a form:
#using (Ajax.BeginForm("Click", new { id = "0" }, new AjaxOptions { UpdateTargetId = "showpage" }))
{
<button type="submit" value="Link 0" />
}
#using (Ajax.BeginForm("Click", new { id = "1" }, new AjaxOptions { UpdateTargetId = "showpage" }))
{
<button type="submit" value="Link 1" />
}
Now inside your Click action you will get the correct id.
Instead of hyperlinks you can use submit buttons with the name property.
#using (Ajax.BeginForm("Click", new AjaxOptions { UpdateTargetId = "showpage" }))
{
<input type="submit" name="action" value="0" />
<input type="submit" name="action" value="1" />
}
public ActionResult Click(string action, ... )
{
// Action here
}

Cannot Uploading Image in MVC3 when I press the submit button and it does not go to POST action method

This is my Controller:
public ActionResult Create()
{
ViewBag.CategoryID = new SelectList(db.Categories, "CategoryID", "CategoryName");
return View();
}
//
// POST: /ManagePhotos/Create
[HttpPost]
public ActionResult Create(Photo photo, HttpPostedFile file)
{
if (ModelState.IsValid)
{
if (file != null && file.ContentLength > 0)
{
// save as original size of image
var newfileName = Guid.NewGuid().ToString() + "_"
+ Path.GetFileName(file.FileName);
var bigImagePath = Path.Combine(Server.MapPath("~/Content/PublicPhotos/BigImages"), newfileName);
file.SaveAs(bigImagePath);
// save as thumbnail image
var photoUploaded = new WebImage(bigImagePath);
photoUploaded.Resize(width: 200, height: 150, preserveAspectRatio: true, preventEnlarge: true);
var thumbImagePath = Path.Combine(Server.MapPath("~/Content/PublicPhotos/ThumbImages"), newfileName);
photoUploaded.Save(thumbImagePath);
}
db.Photos.Add(photo);
db.SaveChanges();
return RedirectToAction("Index");
}
This is my View:
#using (Html.BeginForm("Create","ManagePhotos", FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Photo</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CategoryID, "Category")
</div>
<div class="editor-field">
#Html.DropDownList("CategoryID", String.Empty)
#Html.ValidationMessageFor(model => model.CategoryID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.Label("File name: ")
</div>
<div class="editor-field">
<input type="file" name="file"/>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
My Question: When I press "Create" button , the webpage show me below:
The connection was reset.
The connection to the server was reset while the page was loading.
The site could be temporarily unavailable or too busy. Try again in a few moments.
If you are unable to load any pages, check your computer's network connection.
If your computer or network is protected by a firewall or proxy, make sure that Firefox is permitted to access the Web.
I try to debug in Razor View , and lookup on this website and I did exactly the website showed me but I cannot figure at out. Please help me.
Your action is expecting HttpPostedFile but you should be using HttpPostedFileBase
Also as stated in the comments you need to verify the size isn't too large you can do that in Javascript
function onSelectImage(e) {
if (e.files[0].size > 256000) {
alert('The file size is too large for upload');
e.preventDefault();
return false;
}
...
return true;
}
This ensures an image is only 256K or less as an example

Resources