I have limited experience with .NET async Tasks, but I've used BackgroundWorker and IAsyncResult in the past. The code below is in an MVC4 project. When there are no errors, everything works fine. The problem is when something fails. There seems to be something unexpected happening with the async call which I'm at a loss to explain.
Currently, the SMTP server settings are set to a non-existant server so the code bombs out at the async call to await smtp.SendMailAsync(message);
. Rather than the call to the mail server generating an error, the error seems to come from somewhere in the user creation process "The Name is already taken." This is definitely not the case, as any randomly entered username causes the message (eg: "[email protected]").
What I'd expect:
What actually happens:
I get the expected result locally, but on the server I get the bizarre behaviour.
The create user method seeming to cause the error:
public virtual Task CreateAsync(User user)
{
if (user == null)
throw new ArgumentNullException("user");
return Task.Factory.StartNew(() =>
{
using (SqlConnection cn = new SqlConnection(DbHelper.ConnectionString))
{
cn.Insert<User>(user);
}
});
}
The action in registration controller:
[POST("register")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel vm)
{
if (ModelState.IsValid)
{
var user = AutoMapper.Mapper.Map<User>(vm);
user.PasswordDate = DateTime.Now;
var result = await _userManager.CreateAsync(user); // Error message seems to come from here
if (result.Succeeded)
{
// Add roles
//...
foreach (var area in vm.AllowedAreas.Where(a => a.Value))
await _userManager.AddClaimAsync(user.Id, new Claim("Area", area.Key));
// Generate an email and send it out
var thanksForRegisteringVm = new ThanksForRegisteringViewModel();
thanksForRegisteringVm.FullName = vm.FullName;
thanksForRegisteringVm.EmailAddress = vm.EmailAddress;
var emailBody = RenderViewAsString.Render("~/Views/Emails/ThanksForRegistering.cshtml", thanksForRegisteringVm);
var message = new MailMessage()
{
Subject = "Thanks for Registering",
Body = emailBody,
IsBodyHtml = true
};
message.To.Add(vm.EmailAddress);
var smtp = new SmtpClient();
await smtp.SendMailAsync(message); // this will definitely be the true source of the error - a non existant mail server in web.config
return RedirectToAction("ThanksForRegistering");
}
else
{
foreach (var error in result.Errors)
ModelState.AddModelError("", error);
}
}
// If we got this far, something failed, redisplay form
setUpRegisterViewModel(vm);
return View(vm);
}
Update: We've narrowed this down to a difference somewhere in the IIS config between local, dev and live. Local and dev work, live doesn't. Things we've eliminated:
The Action Method is getting called twice, regardless of controller, for both GET and POST requests, but only when an exception is thrown. It's as though the first exception causes the action method to execute again.
After duplicating the site on a new project and installing all dependencies from Nuget we eventually pinned this down to the proxy server - running Cisco IronPort.
Possibly due to misconfiguration or something the infrastructure team set up intentionally, the proxy server is submitting two identical requests to the server even though only one is sent from the client.
Disabling the proxy server or visiting from an external (phone) connection results in one request.