I have feedback form on my mvc site, it looks like
I created model for my form
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ComponentTrading.Web.Models
{
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Message { get; set; }
}
}
I created view for my form
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "contact-form" }))
{
<fieldset>
#Html.TextBoxFor(model => model.Name, new { #Value = "Name" })
#Html.TextBoxFor(model => model.Email, new { #Value = "E-mail" })
#Html.TextBoxFor(model => model.Phone, new { #Value = "Phone" })
#Html.TextAreaFor(model => model.Message, new { #class = "img-shadow"})
<input class="form-button" data-type="reset" value="Clear" />
<input class="form-button" data-type="submit" type="submit" value="Send" />
}
and now i try to do a sending a letter to email, but it doesn work, when I push "send-button" it happens nothing and I dont get email
my controller
[HttpGet]
public ActionResult Contacts()
{
FeedbackForm temp = new FeedbackForm();
temp.Message = "Message";
return View(temp);
}
[HttpPost]
public ActionResult Contacts(FeedbackForm Model)
{
string Text = "<html> <head> </head>" +
" <body style= \" font-size:12px; font-family: Arial\">"+
Model.Message+
"</body></html>";
SendEmail("mironny#inbox.ru", Text);
FeedbackForm temp = new FeedbackForm();
return View(temp);
}
public static bool SendEmail(string SentTo, string Text)
{
MailMessage msg = new MailMessage();
msg.From = new MailAddress("Test#mail.ru");
msg.To.Add(SentTo);
msg.Subject = "Password";
msg.Body = Text;
msg.Priority = MailPriority.High;
msg.IsBodyHtml = true;
SmtpClient client = new SmtpClient("smtp.mail.ru", 25);
client.UseDefaultCredentials = false;
client.EnableSsl = false;
client.Credentials = new NetworkCredential("TestLogin", "TestPassword");
client.DeliveryMethod = SmtpDeliveryMethod.Network;
//client.EnableSsl = true;
try
{
client.Send(msg);
}
catch (Exception)
{
return false;
}
return true;
}
what's wrong?
Use
// if you dont pass any parameter
// BeginForm posted to the action that
// has name as view name.
// so no need to write any parameters
#using (Html.BeginForm())
{
...
<input type="submit" value="Send">
}
OR
#using (Html.BeginForm("Contacts", "SomeController", FormMethod.Post, new { id = "contact-form" }))
{
...
<input type="submit" value="Send">
}
You have a few question about mvc and there is more important thing of them is incorrect overload methods. My suggestion, first, you should learn html-helpers overload methods. And MVC model binding strategies...
Related
New to ASP.NET MVC and I've come across this before, however I feel I've gone about fixing it in an incorrect way. I was hoping someone could point me in the direction of the correct way of doing it.
I have a page which the user selects a dropdown value and clicks next. Now, if they don't select an item and select the default value ("Select..."), there is a validation error. The controller seems to lose information about the dropdownlist even though the model is returned to the view on a "postback." So, say I don't basically repeat code in my [HTTPPost] from my [HTTPGet]. I get the error:
There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'SheetIndex'.
on
#Html.DropDownListFor(model => model.SheetIndex, Model.SheetsDropdown, "Select...", new { #class = "form-control" })
So unless I repeat code, I get that error when no selection is made. What am I doing wrong?
ViewModel:
public class SelectSheetViewModel
{
public int? Id { get; set; }
public string Name { get; set; }
[Required]
public string SheetIndex { get; set; }
public string SheetName { get; set; }
public int? ChainId { get; set; }
public int? SheetId { get; set; }
public int? FileId { get; set; }
public IEnumerable<SelectListItem> SheetsDropdown { get; set; }
public HeaderViewModel Header { get; set; }
}
Controller:
[HttpGet]
public ActionResult SelectSheet(int? chainId, int? sheetId, int? fileId)
{
if (sheetId == null || fileId == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var fileDetails = db.FileDetails.Find(fileId);
SelectSheetViewModel selectSheet = new SelectSheetViewModel()
{
Id = fileDetails.FileId,
Name = fileDetails.Name,
ChainId = chainId,
SheetId = sheetId,
FileId = fileId
};
string fileName = fileDetails.UniqueName + fileDetails.Extension;
string relativeFileLocation = "~/uploads/" + fileName;
string absoluteFileLocation = HttpContext.Server.MapPath(relativeFileLocation);
if (System.IO.File.Exists(absoluteFileLocation))
{
DSDBuilder builder = new DSDBuilder();
selectSheet.SheetsDropdown = builder.GetSheets(absoluteFileLocation); // Where I get my selectlist
}
else
{
ModelState.AddModelError("SheetDropdown", "Excel workbook does not exist.");
}
selectSheet.Header = BuildHeaderViewModel(chainId, sheetId);
return View(selectSheet);
}
[HttpPost]
public ActionResult SelectSheet(SelectSheetViewModel selectSheet)
{
if (ModelState.IsValid)
{
FileDetail fileDetails = db.FileDetails.Find(selectSheet.FileId);
string[] sheetIndexAndName = selectSheet.SheetIndex.Split(':');
fileDetails.SheetIndex = Convert.ToInt32(sheetIndexAndName[0]);
fileDetails.SheetName = sheetIndexAndName[1];
db.SaveChanges();
return RedirectToAction("Build", "Sheets", new
{
ChainId = selectSheet.ChainId,
SheetId = selectSheet.SheetId,
FileId = selectSheet.FileId
});
}
// Probably not a good method vvv
var fileDetailsPostBack = db.FileDetails.Find(selectSheet.FileId);
string fileName = fileDetailsPostBack.UniqueName + fileDetailsPostBack.Extension;
string relativeFileLocation = "~/uploads/" + fileName;
string absoluteFileLocation = HttpContext.Server.MapPath(relativeFileLocation);
if (System.IO.File.Exists(absoluteFileLocation))
{
DSDBuilder builder = new DSDBuilder();
selectSheet.SheetsDropdown = builder.GetSheets(absoluteFileLocation);
}
else
{
ModelState.AddModelError("SheetDropdown", "Excel workbook does not exist.");
}
// Probably not a good method ^^^
return View(selectSheet);
}
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ChainId)
#Html.HiddenFor(model => model.SheetId)
#Html.HiddenFor(model => model.FileId)
#Html.HiddenFor(model => model.Header.ChainName)
#Html.HiddenFor(model => model.Header.SheetName)
#Html.HiddenFor(model => model.Header.SheetDescription)
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(model => model.SheetIndex, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SheetIndex, Model.SheetsDropdown, "Select...", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.SheetIndex, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Next" class="btn btn-default" />
</div>
</div>
</div>
}
I also would not like to repeat that code because it goes to a function which uses Excel.Interop and is kind of resource heavy. Let me know if anyone has a better solution. I'm always trying to improve my code and do things the "correct" way.
Using a ViewModel for validation:
public class CCvm
{
[Required(ErrorMessage = "Please enter your Name")]
public string cardHolderName { get; set; }
}
My controller calls a task on post:
public async Task<ActionResult> Pay(FormCollection form, CCvm model)
{
if (!ModelState.IsValid)
{
return View(model);
}
}
And the View:
#model GCwholesale.Models.CCvm
#{
Layout = "~/Views/Shared/_HomeSubPageLayout.cshtml";
ViewBag.Title = "Secure Checkout";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="Payment">
<label>Name on Card: </label>
#Html.EditorFor(model => model.cardHolderName, new { htmlAttributes = new { #placeholder = "Cardholder Name Please", #Value = ViewBag.Name } })<br />
#Html.ValidationMessageFor(model => model.cardHolderName)
<button class="submitCheckout">SUBMIT NOW</button>
</div>
}
But when validation fails the data in the form goes away.
Thanks for taking a look.
You do not need to set #Value = ViewBag.Name inside EditorFor.
#Html.EditorFor(model => model.cardHolderName,
new { htmlAttributes = new { #placeholder = "Cardholder Name Please" } })
Besides, you do not need FormCollection as a parameter because you already have CCvm Model.
public async Task<ActionResult> Pay(CCvm model){
{
//...
}
#Value = ViewBag.Name
You're not setting the ViewBag.Name, so it wouldn't have a value and would result in a blank input. Remove that and let the HtmlHelper set it based off the value in the posted model.
My code is as followed and the error message are not displayed:
Index.cshtml
#model WebApp.Models.OrderItems
#using (Html.BeginForm("SaveToDB", "Home", FormMethod.Post, new { #class = "form-group", role = "form" }))
{
#Html.Partial("Information")
}
Partial : Information.cshtml
#model WebApp.Models.OrderItems
<div class="col-lg-4">
<div class="form-group">
<label for="input1" class="col-lg-4 control-label">#Html.LabelFor(model => model.CLInfo.ClientName)</label>
#Html.EditorFor(model => model.CLInfo.ClientName, new { style = "width:250px" })
#Html.ValidationMessageFor(model => model.CLInfo.ClientName)
</div>
</div>
Model :
public class OrderItems
{
public InfoCLInfo{ get; set; }
}
Model : the class for Infos
public class Info
{
[Display(Name = "Client Name")]
[Required]
public string ClientName{ get; set; }
}
The controller
[HttpPost]
[MultipleButton(Name = "action", Argument = "SaveToDB")]
public ActionResult SaveToDB(OrderItems Client)
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (ModelState.IsValid)
{
if (_db == null)
_db = new OrderDB();
OrderItems ClientOrig = Session["Clientobj"] as OrderItems;
ClientOrig.CLInfo = Client.CLInfo;
Session["Clientobj"] = null;
}
return RedirectToAction("Index", "Home");
}
[Authorize]
public ActionResult Index (OrderItems Client)
{
int ClientID = Convert.ToInt32(Session["Client"]);
if ClientID == 0)
{
ClientID = 2;
Session["Client"] = ClientID;
}
if (Session["Clientobj"] == null)
{
Client = new OrderItems();
Client.CLOrderID = 123;
Session["Clientobj"] = Client;
}
else
{
Client = Session["Clientobj"] as OrderItems
}
return View(Client);
}
on post the ModelState.IsValid return false which true, but I don't have any message to tell the user where is the error to be fixed.
I tried to add : #Html.ValidationSummary(true) after the BeginForm , but it didn
Any idea please
Thanks
You cannot use RedirectToAction if you want to retain your model state. All errors and what not are kept in the ModelState object, and when you redirect to action it's performing a new get action, which starts fresh with a clean slate.
You need to return the view like you do in the original action.
my LogIn is partial view. i pass a model that contain some fields of tbl_profile to partial view and fill it and then i pass filled model to a actionresult in [HttpPost] part and ...
but now i'm trouble in [HttpGet] part . i get this error on this line of cod " *#Html.Action("LogOn","Account")"*.
my code :
[HttpGet]
public ActionResult LogOn(string returnUrl)
{
using (var db = new MyContext())
{
var AllFeatureToLog = db.tbl_profile.Select(u => new UsersClass.LogOn { username = u.username, password_User = u.password_User }).ToList();
return PartialView(AllFeatureToLog);
}
}
class:
public class UsersClass
{
public class LogOn
{
public string username { get; set; }
public string password_User { get; set; }
}
}
LogOn.cshtml:
#model MyProject.Models.UsersClass.LogOn
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<form class="signin-form">
#Html.TextBoxFor(m => m.username, new { #id = "username", #class = "input-block- level", #placeholder = "* enter username" })
#Html.TextBoxFor(m => m.password_User, new { #id = "password", #class = "input-block-level", #placeholder = "* enter pass" })
#Html.ValidationMessage("LoginError")
<label class="checkbox">
<input type="checkbox">remember me</label>
<button class="btn btn-medium btn-general input-block-level" type="submit"> enter</button>
</form>
}
error:
Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'
Use this instead ::
#{ Html.RenderAction("LogOn","Account"); }
This will fix your issue.
You sending List:
var AllFeatureToLog = db.tbl_profile.Select(u => new UsersClass.LogOn { username = u.username, password_User = u.password_User }).ToList();
return PartialView(AllFeatureToLog);
But your View expectiong only one model:
#model MyProject.Models.UsersClass.LogOn
Change: your ActionResult on sending one: var AllFeatureToLog = db.tbl_profile.Select(u => new UsersClass.LogOn { username = u.username, password_User = u.password_User }).Fist();
or View for getting List: #model IENumerable<MyProject.Models.UsersClass.LogOn>
I have feedback form on my site, it looks like
I created model for my form
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace CorePartners_Site2.Models
{
public class FeedbackForm
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Company { get; set; }
public string AdditionalInformation { get; set; }
[FileExtensions(Extensions = "doc,txt,pdf")]
public HttpPostedFileBase ProjectInformation { get; set; }
}
}
and created view
#using (Html.BeginForm("Feedback", "Home", FormMethod.Post, new { id = "feedback-form" }))
{
#Html.TextBoxFor(model => model.Name, null, new { #class = "text-field" })
#Html.TextBoxFor(model => model.Email, null, new { #class = "text-field" })
#Html.TextBoxFor(model => model.Phone, null, new { #class = "text-field" })
#Html.TextBoxFor(model => model.Company, null, new { #class = "text-field" })
#Html.TextAreaFor(model => model.AdditionalInformation, new { cols="1", rows="1" })
#Html.TextBoxFor(model => model.ProjectInformation, null, new { type="file", #class="input-file" })
<em><b>Send</b></em>
}
I'd like to know will my form work with a for submit instead <input type="submit" /> ?
And I dont know how to make attachment to letter,
I tried to make
[HttpGet]
public ActionResult Feedback()
{
return View();
}
[HttpPost]
public ActionResult Feedback(FeedbackForm Model)
{
System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
msg.BodyEncoding = Encoding.UTF8;
msg.From = new MailAddress(Model.Email, #Resources.Global.Feedback_Email_Title);
msg.To.Add("tayna-anita#mail.ru");
string message = #Resources.Global.Feedback_Name + ": " + Model.Name + "\n"
+ #Resources.Global.Feedback_Email + ": " + Model.Email + "\n"
+ #Resources.Global.Feedback_Phone + ": " + Model.Phone + "\n"
+ #Resources.Global.Feedback_Company + ": " + Model.Company + "\n\n"
+ Model.AdditionalInformation;
msg.Body = message;
msg.IsBodyHtml = false;
//Attachment
if (Model.ProjectInformation != null)
{
HttpPostedFileBase attFile = Model.ProjectInformation;
int attachFileLength = attFile.ContentLength;
if (attachFileLength > 0)
{
string strFileName = Path.GetFileName(Model.ProjectInformation.FileName);
Model.ProjectInformation.SaveAs(Server.MapPath(strFileName));
MailAttachment attach = new MailAttachment(Server.MapPath(strFileName));
msg.Attachments.Add(attach);
string attach1 = strFileName;
}
}
SmtpClient client = new SmtpClient("smtp.mail.ru", 25);
client.UseDefaultCredentials = false;
client.EnableSsl = false;
try
{
client.Send(msg);
}
catch (Exception ex)
{
}
FeedbackForm tempForm = new FeedbackForm();
return View(tempForm);
}
but it shows a mistake in msg.Attachments.Add(attach); and it seems it will not work.
Well to answer your first question yes you can use an anchor tag in place of a submit input.
You will want to disable the tags default behaviour with javascript/jquery like this and then have it submit the form:
$(function () {
$('a.something').on("click", function (e) {
e.preventDefault();
$('feedback-form').submit();
});
});
The error you are receiving is because you are using the wrong object type for the msg.attachments.add() method. You need to use an Attachment object not a MailAttachment object.
Something like this:
Stream attachmentStream = File.OpenRead (file);
streams.Add (attachmentStream);
mail.Attachments.Add (new Attachment (attachmentStream, Path.GetFileName (file));