Asp.net Core 电子邮件发件人在注册页面中不起作用

Posted

技术标签:

【中文标题】Asp.net Core 电子邮件发件人在注册页面中不起作用【英文标题】:Asp.net Core Email Sender is not working in Registration page 【发布时间】:2022-01-04 20:27:00 【问题描述】:

我正在尝试使用 asp.net 身份设置一个 asp.net core razor 页面应用程序。

我已经完成了所有设置,我正在尝试生成用于注册的电子邮件,但代码如下:

                    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",  $"Please confirm your account by <a href='htmlEncoder.Default.Encode(value: callbackUrl)'>clicking here</a>.").ConfigureAwait(false);

没有被击中。就像它甚至不会调试到它一样,因此我的注册电子邮件没有被发送或生成。这些值保存在我的 SQL Server 数据库中,没有任何问题。

这是我要进行的设置:

appsetting.js

程序.cs

    public class Program
    
        /// <summary>
        /// Defines the entry point of the application.
        /// </summary>
        /// <param name="args">The arguments.</param>
        public static void Main(string[] args)
        
            CreateHostBuilder(args).Build().Run();
            var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
            try
            
                logger.Debug("init main");
                CreateHostBuilder(args).Build().Run();
            
            catch (Exception exception)
            
                // NLog: catch setup errors
                logger.Error(exception, "Stopped program because of exception");
                throw;
            
            finally
            
                // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
                NLog.LogManager.Shutdown();
            
        

        /// <summary>
        /// Creates the host builder.
        /// </summary>
        /// <param name="args">The arguments.</param>
        /// <returns></returns>
        public static IHostBuilder CreateHostBuilder(string[] args) =>
               Host.CreateDefaultBuilder(args)
                  .ConfigureWebHostDefaults(webBuilder =>
                  
                      webBuilder.UseStartup<Startup>();
                  )
                  .ConfigureLogging(logging =>
                  
                      logging.ClearProviders();
                      logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                  )
                  .UseNLog();  // NLog: Setup NLog for Dependency injection
    

Starup.cs

    /// <summary>
    /// Startup
    /// </summary>
    public class Startup
    
        /// <summary>
        /// Initializes a new instance of the <see cref="Startup"/> class.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        public Startup(IConfiguration configuration)
        
            Configuration = configuration;
        

        /// <summary>
        /// Gets the configuration.
        /// </summary>
        /// <value>
        /// The configuration.
        /// </value>
        public IConfiguration Configuration  get; 

        /// <summary>
        /// Configures the services.
        /// // This method gets called by the runtime. Use this method to add services to the container.
        /// </summary>
        /// <param name="services">The services.</param>
        public void ConfigureServices(IServiceCollection services)
        
            // Add framework services.
            services
                .AddControllersWithViews()
                .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);

            // Added for identity set up - core27
            services.AddRazorPages();
            services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");

            services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
            services.Configure<SessionTimeoutSettings>(Configuration.GetSection("SessionTimeoutSettings"));
            services.AddSingleton<IEmailSender, EmailSender>();

            // not sure what this is for?
            //services.AddDevExpressControls();

            // Auto Mapper Configurations
            var mappingConfig = new MapperConfiguration(cfg =>
            
                cfg.AddMaps(Assembly.GetExecutingAssembly());
                cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
                cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention();
            );

            var sessionTimeout = Convert.ToDouble(Configuration.GetSection("SessionTimeoutSettings").GetSection("SessionTimeout").Value);
            services.AddSession(options => 
                options.IdleTimeout = TimeSpan.FromMinutes(sessionTimeout);
            );
        

        /// <summary>
        /// Configures the specified application.
        /// </summary>
        /// <param name="app">The application.</param>
        /// <param name="env">The env.</param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            
            else
            
                app.UseExceptionHandler("/Error");
            

            app.UseStaticFiles();

            app.UseRouting();

            // Added for identity set up - core27
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints => 
                endpoints.MapControllers();
                endpoints.MapDefaultControllerRoute();
                endpoints.MapRazorPages();
            );

            app.UseStaticFiles();

            app.UseStaticFiles(new StaticFileOptions
            
                FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "node_modules")),
                RequestPath = "/node_modules",
            );
        
    

EmailSender.cs

#pragma warning disable SA1649 // File name should match first type name
    public interface IEmailSender
#pragma warning restore SA1649 // File name should match first type name
    
        /// <summary>
        /// Sends the email asynchronous.
        /// </summary>
        /// <param name="email">The email.</param>
        /// <param name="subject">The subject.</param>
        /// <param name="message">The message.</param>
        /// <returns>Task</returns>
        Task SendEmailAsync(string email, string subject, string message);
    

    /// <summary>
    /// EmailSender
    /// </summary>
    /// <seealso cref="MORE.Website.Service.IEmailSender" />
    public class EmailSender : IEmailSender
    
        /// <summary>
        /// The email settings
        /// </summary>
        private readonly EmailSettings emailSettings;

        /// <summary>
        /// The env
        /// </summary>
        private readonly IWebHostEnvironment env;

        /// <summary>
        /// Initializes a new instance of the <see cref="EmailSender"/> class.
        /// </summary>
        /// <param name="emailSettings">The email settings.</param>
        /// <param name="env">The env.</param>
        public EmailSender(
            IOptions<EmailSettings> emailSettings,
            IWebHostEnvironment env)
        
            this.emailSettings = emailSettings.Value;
            this.env = env;
        

        /// <summary>
        /// Sends the email asynchronous.
        /// </summary>
        /// <param name="email">The email.</param>
        /// <param name="subject">The subject.</param>
        /// <param name="message">The message.</param>
        /// <exception cref="InvalidOperationException">InvalidOperationException</exception>
        /// <returns>Task</returns>
        public async Task SendEmailAsync(string email, string subject, string message)
        
            try
            
                var mimeMessage = new MimeMessage();

                mimeMessage.From.Add(new MailboxAddress(emailSettings.SenderName, emailSettings.SenderFromAddress));

                mimeMessage.To.Add(new MailboxAddress(email));

                mimeMessage.Subject = subject;

                mimeMessage.Body = new TextPart("html")
                
                    Text = message,
                ;

                using (var client = new SmtpClient())
                
                    // For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                    if (env.IsDevelopment())
                    
                        // The third parameter is useSSL (true if the client should make an SSL-wrapped
                        // connection to the server; otherwise, false).
                        // set to false for testing.
                        await client.ConnectAsync(emailSettings.MailServer, emailSettings.MailPort, false);
                    
                    else
                    
                        await client.ConnectAsync(emailSettings.MailServer);
                    

                    // Note: only needed if the SMTP server requires authentication
                    await client.AuthenticateAsync(emailSettings.Sender, emailSettings.Password);

                    await client.SendAsync(mimeMessage);

                    await client.DisconnectAsync(true);
                
            
            catch (Exception ex)
            
                // TODO: handle exception
                throw new InvalidOperationException(ex.Message);
            
        
    

Registration.cshtml

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    using System.Text.Encodings.Web;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.AspNetCore.Identity.UI.Services;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.RazorPages;
    using Microsoft.AspNetCore.WebUtilities;
    using Microsoft.Extensions.Logging;
    using Svc27M.Areas.Identity.Data;
    using Svc27M.Services;
 [AllowAnonymous]
    public class RegisterModel : PageModel
    
        private readonly SignInManager<Svc27MUser> _signInManager;
        private readonly UserManager<Svc27MUser> _userManager;
        private readonly ILogger<RegisterModel> _logger;
        private readonly IEmailSender _emailSender;

        public RegisterModel(
            UserManager<Svc27MUser> userManager,
            SignInManager<Svc27MUser> signInManager,
            ILogger<RegisterModel> logger,
            IEmailSender emailSender)
        
            _userManager = userManager;
            _signInManager = signInManager;
            _logger = logger;
            _emailSender = emailSender;
        

        [BindProperty]
        public InputModel Input  get; set; 

        public string ReturnUrl  get; set; 

        public IList<AuthenticationScheme> ExternalLogins  get; set; 

        public class InputModel
        
            [Required]
            [EmailAddress]
            [Display(Name = "Email")]
            public string Email  get; set; 

            [Required]
            [StringLength(100, ErrorMessage = "The 0 must be at least 2 and at max 1 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 async Task OnGetAsync(string returnUrl = null)
        
            ReturnUrl = returnUrl;
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        
            returnUrl = returnUrl ?? Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            
                var user = new Svc27MUser  UserName = Input.Email, Email = Input.Email ;
                var result = await _userManager.CreateAsync(user, Input.Password);
                if (result.Succeeded)
                
                    _logger.LogInformation("User created a new account with password.");

                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new  area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl ,
                        protocol: Request.Scheme);

                    await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",  $"Please confirm your account by <a href='HtmlEncoder.Default.Encode(value: callbackUrl)'>clicking here</a>.").ConfigureAwait(false);

                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    
                        return RedirectToPage("RegisterConfirmation", new  email = Input.Email, returnUrl = returnUrl );
                    
                    else
                    
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    
                
                foreach (var error in result.Errors)
                
                    ModelState.AddModelError(string.Empty, error.Description);
                
            

            // If we got this far, something failed, redisplay form
            return Page();
        
    

【问题讨论】:

【参考方案1】:

我想通了:

内部有一个IEmailSender 接口:

   using Microsoft.AspNetCore.Identity.UI.Services;

我的IEmailSender 并没有指向我创建的本地地址。

以下是更改和修复。

现在正在正确发送电子邮件以进行注册。

这是我的代码更改:

【讨论】:

以上是关于Asp.net Core 电子邮件发件人在注册页面中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ASP.NET Core Identity 将登录/注册系统添加到现有数据库?

ASP.NET MVC 用户管理器 SendEmailAsync:如何更改发件人电子邮件

ASP.NET Core 2.1 Razor 页面返回带有模型的页面

在 2 个控制器 ASP.NET Core 3.1 MVC 之间传递 ID

自定义页面过滤器中的 ASP .NET Core 注入服务

[ASP.NET Core 3.1 MVC Razor页面仅在模型成员有效时显示图标