Send mail in ASP MVC have Server Error - asp.net

I'm have problem when practice send email in ASP MVC in tutorials:
How To Send Email In ASP.NET MVC.
I think problem in class:
public async Task<<ActionResult>ActionResult> Index(EmailFormModel model)
{
todosomething
return RedirectToAction("Sent");
}
When run website it show the below error:
Solve:
Thanks to #Simon C.
So, based on your comments, you have a POST contact method, but no way to navigate to the page yet ( just navigating to home/contact in your browser will send a GET request and since you have a [HttpPost] attribute, the route won't match). I think you need to add a GET method to your home controller to get you there:
[HttpGet]
public ActionResult Contact()
{
return View(new EmailFormModel());
}
This means when you first navigate to /home/contact, you will hit the above method. When you post your form back to your site, you will hit the Contact Method marked with [HttpPost].
Edit: As an aside, you will also need to add a method called Sent on your controller for when the email is sent successfully. The line return RedirectToAction("Sent"); will be looking for a method called Sent.

So, based on your comments, you have a POST contact method, but no way to navigate to the page yet ( just navigating to home/contact in your browser will send a GET request and since you have a [HttpPost] attribute, the route won't match). I think you need to add a GET method to your home controller to get you there:
[HttpGet]
public ActionResult Contact()
{
return View(new EmailFormModel());
}
This means when you first navigate to /home/contact, you will hit the above method. When you post your form back to your site, you will hit the Contact Method marked with [HttpPost].
Edit: As an aside, you will also need to add a method called Sent on your controller for when the email is sent successfully. The line return RedirectToAction("Sent"); will be looking for a method called Sent.

In EmailFormModel.cs model:
using System.ComponentModel.DataAnnotations;
using System.Web;
namespace MVCEmail.Models
{
public class EmailFormModel
{
[Required, Display(Name="Your name")]
public string FromName { get; set; }
[Required, Display(Name = "Your email"), EmailAddress]
public string FromEmail { get; set; }
[Required]
public string Message { get; set; }
public HttpPostedFileBase Upload { get; set; }
}
}
Change class Contact in HomeController.cs to:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Contact(EmailFormModel model)
{
if (ModelState.IsValid)
{
var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
var message = new MailMessage();
message.To.Add(new MailAddress("name#gmail.com")); //replace with valid value
message.Subject = "Your email subject";
message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message);
message.IsBodyHtml = true;
if (model.Upload != null && model.Upload.ContentLength > 0)
{
message.Attachments.Add(new Attachment(model.Upload.InputStream, Path.GetFileName(model.Upload.FileName)));
}
using (var smtp = new SmtpClient())
{
await smtp.SendMailAsync(message);
return RedirectToAction("Sent");
}
}
return View(model);
}
And alter the Contact view (Views\Home\Contact.cshtml):
#model MVCEmail.Models.EmailFormModel
#{
ViewBag.Title = "Contact";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("Contact", "Home", null, FormMethod.Post, new {enctype = "multipart/form-data"}))
{
#Html.AntiForgeryToken()
<h4>Send your comments.</h4>
<hr />
<div class="form-group">
#Html.LabelFor(m => m.FromName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.FromName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.FromName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.FromEmail, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.FromEmail, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.FromEmail)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Message, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextAreaFor(m => m.Message, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Message)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Upload, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
<input type="file" name="upload" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Send" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And Webconfig.cs is:
<system.net>
<mailSettings>
<smtp from="you#outlook.com">
<network host="smtp-mail.outlook.com"
port="587"
userName="you#outlook.com"
password="password"
enableSsl="true" />
</smtp>
</mailSettings>
</system.net>
Thank #Dijkgraaf

Related

all my textboxes return null what should I do?

I have a problem here with regards to elements on my pages returning null even though I have typed something in the textbox. What causes this? I want to make a simple CRUD app with a dashboard for final year.
Here is my view:
#model WebApplication1.Models.Category
#{
ViewBag.Title = "Create Category";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class
="control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Name, new { htmlAttributes =
new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new {
#class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here is my controller action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Name")] Category category)
{
if (ModelState.IsValid)
{
db.Categories.Add(category);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(category);
}
I think you need to post to the correct ActionName. You use #using (Html.BeginForm()), which will post to the Index of a Controller. But you have Create. So point the form to that.
#using (Html.BeginForm("Create", "Home", FormMethod.Post))
Make sure that you have proper viewmodel properties setup first:
public class Category
{
public int ID { get; set; }
public string Name { get; set; }
}
Then point to action name and controller name which handles POST action in BeginForm helper:
#* assumed the controller name is 'CategoryController' *#
#using (Html.BeginForm("Create", "Category", FormMethod.Post))
{
// form contents
}
And finally change parameter name to avoid naming conflict in default model binder, also remove BindAttribute because the POST action has strongly-typed viewmodel class as parameter:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Category model)
{
if (ModelState.IsValid)
{
db.Categories.Add(model);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
Related issue:
POST action passing null ViewModel

How to use MVC ValidationMessageFor into bootstrap-modal dialog

Hi everybody i've a little trouble to ask... I'm trying to get error message into a login bootstrap modal dilog using ValidationMessageFor, but actually isn't working and i don't know why.
This is my login dilog with Html.BeginForm
<div class="col-xs-2 login-btn">
<a class="btn pfologin" data-toggle="modal" data-target=".bootstrapmodal">
<span> LOGIN</span>
</a>
<!-- Modal dialog -->
<div class="modal fade bootstrapmodal">
<div class="modal-dialog">
#using (Html.BeginForm("Login", "Account"))
{
<div class="modal-content modal-pfo">
<div class="modal-body">
<p>
User:<br />
#Html.TextBoxFor(s => s.Name, new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.Password, "", new { #class = "text-danger" })
</p>
<p>
Password:<br />
#Html.TextBoxFor(s => s.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.Password, "", new { #class = "text-danger" })
</p>
<p style="display: flex;">
#Html.CheckBoxFor(s => s.Privacy, new { #class = "checkbox" }) Remember me
</p>
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-pfo">Cancel</button>
<input type="submit" value="Login" class="btn btn-pfo" />
</div>
</div>
}
</div>
</div>...
this is the model
public class LoginModel
{
[Required(ErrorMessage = "Username requested")]
public string Name { get; set; }
[Required(ErrorMessage = "Password requested")]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool Privacy { get; set; }
}
and this is the controller
[HttpPost]
public async Task<ActionResult> Login(LoginModel loginModel)
{
if (String.IsNullOrEmpty(loginModel.Name))
{
return ModelState.AddModelError("Name", loginModel.Name);
}
if (String.IsNullOrEmpty(loginModel.Password))
{
ModelState.AddModelError("Password", loginModel.Password);
}
if (ModelState.IsValid)
{
}
return RedirectToAction("Index", "Home");
}
yes I redirect from Login/Post to Index but i don't think this is the problem... thank you!
When you return RedirectToAction, you lose all your form data (and, therefore, all validation information). Instead of redirecting to Index, return the View with the model that was passed in.
Second, because both properties are marked as Required, you do not need to explicitly check if they are null or empty. The model is already validated before it hits your [HttpPost] method, based on the attributes you set on the model. If you return the View with this model, your validation messages will appear. This is the most basic implementation, but you can probably get away with:
[HttpPost]
public async Task<ActionResult> Login(LoginModel loginModel)
{
if (ModelState.IsValid)
{
// Do work
return RedirectToAction("Index", "Home");
}
// Else, if not valid, re-render the view with the updated information and display it to the user
return View(loginModel);
}
More info on validation here

Clear fields on postback/errors - MVC with DataType attribute validation

On my ResetPassword action I am trying to clear the email and password fields on post-backs such as when an error occurs. I have tried to use ModelState.Clear(), however the issue is that certain errors never post back to the action
such as:
"The Password must be at least 6 characters long."
"The password and confirmation password do not match."
I believe the reason for this is due to #Scripts.Render("~/bundles/jqueryval") and/or the model DataType attributes
The ResetPassword view is as follows:
#model TestGame.ViewModels.ResetPasswordViewModel
#{
ViewBag.Title = "Reset password";
}
<h2>#ViewBag.Title</h2>
#using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form", autocomplete="off" }))
{
#Html.AntiForgeryToken()
<h4>Reset your password</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Code)
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control", #autofocus = "autofocus" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Reset" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
and the ResetPasswordViewModel is as follows:
public class ResetPasswordViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public string Code { get; set; }
}
I don't know why you want to clear the fields. Doing that will be annoying to the users who will be forced to type everything again. But if you still want to do it anyway then keep reading.
The errors that you mentioned not to be posting back are validation errors, which are handled on the client-side. So to clear the fields in this case, you will need some JavaScript code. You will need to do one of the following:
Write your own JavaScript of the client-side validation and use the custom validation to attach it to your fields.
Modify the JavaScript of the client-side validation. This is not recommended, but it works.
Hack the JavaScript of the client-side validation by adding additional JavaScript function that will run right after the validation. Run your page in the browser and view the generated source code then search for the JavaScript validation near the bottom.

ASP.NET code snippit to query database for unique field value

I'm trying to create custom remote data annotation to check for unique values.
So far I have:
[Remote("checkForUniqueSpeciesName", "Create", ErrorMessage = "A Species by that name already exists.")]
public string SpeciesName { get; set; }
and
public ActionResult checkForUniqueSpeciesName(string species_name)
{
bool is_unique = ........
return Json(is_unique, JsonRequestBehavior.AllowGet);
}
To be honest, I don't really understand how this works, I'm just trying to follow examples found on the web. I guess checkForUniqueSpeciesName is called when the form is submitted, and the method returns true or false. Is there something I need to put in the view to make the validation message come up, such as?
#Html.ValidationMessageFor(model => model.SpeciesName, "", new { #class = "text-danger" })
Do I need that?
Model Species.cs:
public class Species
{
[Key]
public int SpeciesId { get; set; }
[Display(Name = "Species")]
[Required(ErrorMessage = "You must enter a species name.")]
[Remote("CheckForUniqueSpeciesName", "Create", ErrorMessage = "A Species by that name already exists.")]
public string SpeciesName { get; set; }
}
Controller SpeciesController.cs:
namespace Gators3.Controllers
{
public class SpeciesController : Controller
{
private GatorsContext db = new GatorsContext();
// GET: Species
public ActionResult Index()
{
return View(db.Species.ToList());
}
// GET: Species/Create
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "SpeciesId,SpeciesName")] Species species)
{
if (ModelState.IsValid)
{
db.Species.Add(species);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(species);
}
public ActionResult CheckForUniqueSpeciesName(string speciesName)
{
using (GatorsContext ctx = new GatorsContext())
{
bool isUnique = !ctx.Species.Any(s => s.SpeciesName == speciesName);
return Json(isUnique, JsonRequestBehavior.AllowGet);
}
}
.
.
.
.
View Views->Species->Create.cshtml:
#model Gators3.Models.Species
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Species</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SpeciesName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SpeciesName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SpeciesName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I guess checkForUniqueSpeciesName is called when the form is
submitted, and the method returns true or false.
No, that is not the case. The [RemoteAttribute] adds some JavaScript to your page automatically that will call a method on your Controller to do some server side validation and display the result on the page without the user needing to submit the whole HTML form. i.e. The validation is invoked when you tab out of the text box, not when you click submit.
With your code, I assume your controller is named CreateController?
I'm guessing you're just missing your data access code to actually check uniqueness?
So something like this would be required:
public ActionResult CheckForUniqueSpeciesName(string speciesName)
{
using (YourEntityFrameworkDbContext ctx = new YourEntityFrameworkDbContext())
{
bool isUnique = !ctx.Species.Any(s => s.SpeciesName == speciesName);
return Json(isUnique , JsonRequestBehavior.AllowGet);
}
}
Then in your view, you just need something like this:
#Html.ValidationMessageFor(x => x.SpeciesName)
Which will display the validation message you specified in your [Remote] attribute.
By the way, just as a side note - the coding conventions/casing you've applied to some of your code won't be popular with most C# programmers (unless your team are abiding by an unusual standard) so note the formatting I've applied.
Update - I think your code needs to have the following:
[Remote("CheckForUniqueSpeciesName", "Species", ErrorMessage="A Species by that name already exists.")]

asp.net mvc model didn't receive on form submit

I have written an asp.net mvc site that works fine on local.
But after publishing it, i have some problems with models sent from forms.
i think it determines my model state always not valid.
i don't receive any data!
[HttpGet]
public ActionResult LogIn()
{
return View();
}
[HttpPost]
public ActionResult LogIn(Models.LoginViewModel data)
{
if (!ModelState.IsValid)
{
return LogIn();
}
TAPortalEntities db = new TAPortalEntities();
UserAccount probableUser = db.UserAccounts.FirstOrDefault(p => p.UserName == data.UserName && p.Pass == data.Pass);
if (probableUser == null)
{
ModelState.AddModelError(string.Empty, "نام کابری یا رمز عبور اشتباه وارد شده است!");
return LogIn();
}
Session["LogedIn"] = true;
Session["UserName"] = probableUser.UserName;
Session["Course"] = probableUser.Course.Name;
Session["TeacherName"] = probableUser.Course.TeacherName;
Session["RealName"] = probableUser.RealName;
return RedirectToAction("Index", "Home");
}
and the view is like this:
#model TAPortal.Models.LoginViewModel
#{
ViewBag.Title = "ورود به سایت";
}
<h2>ورود</h2>
#using (Html.BeginForm())
{
#*#Html.AntiForgeryToken()*#
<div class="form-horizontal">
<h4>اطلاعات ورود را وارد کنید</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.UserName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Pass, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Pass)
#Html.ValidationMessageFor(model => model.Pass)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="ورود" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("برگشت به خانه", "Index","Home")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
and the model class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace TAPortal.Models
{
public class LoginViewModel
{
[Required(ErrorMessage="نام کاربری باید وارد شود!")]
[Display(Name="نام کاربری")]
public string UserName { get; set; }
[Required(ErrorMessage = "رمز عبور باید وارد شود!")]
[Display(Name = "رمز عبور")]
public string Pass { get; set; }
}
}
see these results:
input:
output local :
output on online host :
Try to add this filter
[ValidateAntiForgeryToken]
to your POST Action
Edit:
in your get method instantiate your model and set to false the ValidationSummary
[HttpGet]
public ActionResult LogIn()
{
var model = new LoginViewModel();
return View(model);
}
Now I have the answer. I share it for the others who face this problem.
From first, every thing was correct but the wrong thing was the version of the .NET framework of my host. This type of coding requires .NET framework 4.5 but my host's .NET framework version was 4.0 and it was all the story.
Now I have transferred my code to a host of 4.5.

Resources