MVC,ASP.NET身份,EmailService和异步调用w / Angularjs

时间:2015-09-17 16:16:01

标签: c# asp.net angularjs asp.net-mvc async-await

在审核并尝试围绕错误消息的许多建议之后:

  

“异步模块或处理程序在异步时完成   手术还在等待。“

我发现自己处于这样的情况,即使对MVC accountController的调用实际上执行了所需的代码(电子邮件被发送到正确的地方并且具有正确的内容)并且控制器方法中的Try / Catch也不会“捕获” '错误,正在启动呼叫的AngularJS工厂将收到服务器错误“page”。

工厂:(AngularJS)

InitiateResetRequest: function (email) {
                    var deferredObject = $q.defer();

                    $http.post(
                        '/Account/InitiateResetPassword', { email: email }
                    )
                    .success(function (data) {
                            deferredObject.resolve(data);
                    })
                    .error(function (data) {
                        //This is a stop-gap solution that needs to be fixed..!
                        if (data.indexOf("An asynchronous module or handler completed while an asynchronous operation was still pending.") > 0) {
                            deferredObject.resolve(true);
                        } else {
                            deferredObject.resolve(false);
                        }
                    });
                    return deferredObject.promise;
                }

MVC控制器(C#):

        [HttpPost]
        [AllowAnonymous]
        public async Task<int> InitiateResetPassword(string email)
        {
            try
            {
                _identityRepository = new IdentityRepository(UserManager);
                string callbackUrl = Request.Url.AbsoluteUri.Replace(Request.Url.AbsolutePath, "/account/reset?id=");
                await _identityRepository.InitiatePasswordReset(email, callbackUrl);
                return 0;
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return 1;
            }
        }

Identity Repository / InitiatePasswordReset:

 public async Task InitiatePasswordReset(string email, string callbackUrl)
        {
            try
            {
                var u = await _applicationUserManager.FindByEmailAsync(email);

                string passwordResetToken = await GetResetToken(u);
                callbackUrl = callbackUrl + HttpUtility.UrlEncode(passwordResetToken);
                await _applicationUserManager.SendEmailAsync(u.Id, RESET_SUBJECT, string.Format(RESET_BODY, u.FirstName, u.LastName, callbackUrl));
            }
            catch(Exception ex)
            {      //another vain attempt to catch the exception...
                Console.WriteLine(ex.ToString());
                throw ex;
            }
        }

将EmailService注入ASP.NET标识“ApplicationUserManager”

   public class EmailService : IIdentityMessageService
    {
        XYZMailer xyzMailer;
        public EmailService()
        {
            xyzMailer = XYZMailer.getCMRMailer();
        }
        public async Task SendAsync(IdentityMessage message)
        {
            //original code as posted:
            //await Task.FromResult(xyzMailer.SendMailAsync(message));
            //solution from @sirrocco-
            await xyzMailer.SendMailAsync(message);
        }
    }

最后...... XYZMailer类

class XYZMailer
    {
        #region"Constants"
        private const string SMTP_SERVER = "XYZEXCHANGE.XYZ.local";
        private const string NO_REPLY = "noReply@XYZCorp.com";
        private const string USER_NAME = "noreply";
        private const string PASSWORD = "theMagicP@55word"; //NO, that is not really the password :) 
        private const int SMTP_PORT = 587;
        private const SmtpDeliveryMethod SMTP_DELIVERY_METHOD = SmtpDeliveryMethod.Network;
        #endregion//Constants

        internal XYZMailer()
        {
            //default c'tor
        }

        private static XYZMailer _XYZMailer = null;
        public static XYZMailer getXYZMailer()
        {
            if (_XYZMailer == null)
            {
                _XYZMailer = new XYZMailer();
            }
            return _XYZMailer;
        }

        public async Task<int> SendMailAsync(IdentityMessage message)
        {
#if DEBUG
                message.Body += "<br/><br/>DEBUG Send To: " + message.Destination;
                message.Destination = "me@XYZCorp.com";
#endif
            // Create the message:
            var mail =
                new MailMessage(NO_REPLY, message.Destination)
                {
                    Subject = message.Subject,
                    Body = message.Body,
                    IsBodyHtml = true
                };

            // Configure the client:
            using (SmtpClient client = new SmtpClient(SMTP_SERVER, SMTP_PORT)
            {
                DeliveryMethod = SMTP_DELIVERY_METHOD,
                UseDefaultCredentials = false,
                Credentials = new System.Net.NetworkCredential(USER_NAME, PASSWORD),
                EnableSsl = true
            })
            {
                // Send:
                await client.SendMailAsync(mail);

            }
            return 0;
        }

    }

(注意:最初控制器方法只是“public async Task InitiateResetPassword,我添加了返回类型,试图在服务器上捕获错误。在运行时,返回0;确实命中(断点)捕获没有被击中并在客户端“)

目前我只是过滤了预期的错误消息并告诉javascript将其视为成功。这种解决方案具有“实际工作”的好处......但它并不“理想”。

如何防止服务器上的错误? 或者, 如何在服务器上捕获错误?

1 个答案:

答案 0 :(得分:1)

您需要从await Task.FromResult中删除EmailService,因为这样可以使代码同步执行而不是异步。

至于为什么异常仍然在try / catch之外被提出并冒出来 - 我怀疑Task.FromResult也是罪魁祸首 - 如果你现在在SendAsync中引发异常(只是为了测试它你应该抓住控制器。