Asp.net 核心电子邮件发件人在注册页面中不工作
Asp.net Core Email Sender is not working in Registration page
我正在尝试使用 asp.net 身份设置 asp.net 核心剃须刀页面应用程序。
我已设置好所有内容,正在尝试生成注册电子邮件,但代码为:
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 服务器数据库中没有任何问题。
这是我要进行的设置:
appsetting.js
Program.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();
}
}
我想通了:
有一个 IEmailSender
接口:
using Microsoft.AspNetCore.Identity.UI.Services;
我的 IEmailSender
没有指向我制作的本地文件。
以下是更改和修复。
现在正在为注册正确发送电子邮件。
这是我的代码更改:
我正在尝试使用 asp.net 身份设置 asp.net 核心剃须刀页面应用程序。
我已设置好所有内容,正在尝试生成注册电子邮件,但代码为:
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 服务器数据库中没有任何问题。
这是我要进行的设置:
appsetting.js
Program.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();
}
}
我想通了:
有一个 IEmailSender
接口:
using Microsoft.AspNetCore.Identity.UI.Services;
我的 IEmailSender
没有指向我制作的本地文件。
以下是更改和修复。
现在正在为注册正确发送电子邮件。
这是我的代码更改: