C
C#•6mo ago
Gipper

ASP.NET Problem with emailSender in Register Page

Hi, so I did something and now when I go to my Register page (that I got when I create the project with the "Individual Accounts" authentication option), I get this exception: InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UI.Services.IEmailSender' while attempting to activate 'Proj_Name.Areas.Identity.Pages.Account.RegisterModel'. I've tried to try to comment ou any reference to emailSender in the entire solution, doing .AddDefaultUI() in my services config, here is that config code btw:
builder.Services.AddIdentity<IdentityUser, IdentityRole>
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddRoles<IdentityRole>()
.AddDefaultTokenProviders()
.AddDefaultUI();
builder.Services.AddIdentity<IdentityUser, IdentityRole>
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddRoles<IdentityRole>()
.AddDefaultTokenProviders()
.AddDefaultUI();
I should say that I don't have an actual emailSender implement nor desire or resources to implement it. I don't actually need to have email confirmation of accounts, I was happy with what it did before which was just show the text page pretending there was an email confirmation feature when there wasn't.
7 Replies
Anu6is
Anu6is•6mo ago
looks like the RegisterModel is expecting IEmailSender to be injected but you don't have an IEmailSender in your service collection
Jimmacle
Jimmacle•6mo ago
you need to register some implementation of it it can be a dummy implementation that doesn't do anything if you don't actually want to send emails or find the relevant configuration to disable email confirmation on registration probably the better option considering a non-confirmed account probably isn't usable
Gipper
Gipper•6mo ago
The only thing I've found to disable email confirmation, is doing:
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = false;
});
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = false;
});
Which I've done and gotten the same exception. WHat would you say would be the bare minimum to write a dummy implementation of emailSender?
Anu6is
Anu6is•6mo ago
if you created the project with authentication individual accounts (or whatever the option is) the identity defaults include a IdentityNoOpEmailSender
Jimmacle
Jimmacle•6mo ago
what @Anu6is said, or just implement the interface methods and do nothing in them
Anu6is
Anu6is•6mo ago
namespace Microsoft.AspNetCore.Identity.UI.Services;

/// <summary>
/// The default <see cref="IEmailSender"/> that does nothing in <see cref="SendEmailAsync(string, string, string)"/>.
/// It is used to detect that the <see cref="IEmailSender" /> has been customized. If not, Identity UI provides a development
/// experience where the email confirmation link is rendered by the UI immediately rather than sent via an email.
/// </summary>
public sealed class NoOpEmailSender : IEmailSender
{
/// <summary>
/// This method does nothing other return <see cref="Task.CompletedTask"/>. It should be replaced by a custom implementation
/// in production.
/// </summary>
public Task SendEmailAsync(string email, string subject, string htmlMessage) => Task.CompletedTask;
}
namespace Microsoft.AspNetCore.Identity.UI.Services;

/// <summary>
/// The default <see cref="IEmailSender"/> that does nothing in <see cref="SendEmailAsync(string, string, string)"/>.
/// It is used to detect that the <see cref="IEmailSender" /> has been customized. If not, Identity UI provides a development
/// experience where the email confirmation link is rendered by the UI immediately rather than sent via an email.
/// </summary>
public sealed class NoOpEmailSender : IEmailSender
{
/// <summary>
/// This method does nothing other return <see cref="Task.CompletedTask"/>. It should be replaced by a custom implementation
/// in production.
/// </summary>
public Task SendEmailAsync(string email, string subject, string htmlMessage) => Task.CompletedTask;
}
this is provided default
internal sealed class IdentityNoOpEmailSender : IEmailSender<ApplicationUser>
{
private readonly IEmailSender emailSender = new NoOpEmailSender();

public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) =>
emailSender.SendEmailAsync(email, "Confirm your email", $"Please confirm your account by <a href='{confirmationLink}'>clicking here</a>.");

public Task SendPasswordResetLinkAsync(ApplicationUser user, string email, string resetLink) =>
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password by <a href='{resetLink}'>clicking here</a>.");

public Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode) =>
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password using the following code: {resetCode}");
}
internal sealed class IdentityNoOpEmailSender : IEmailSender<ApplicationUser>
{
private readonly IEmailSender emailSender = new NoOpEmailSender();

public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) =>
emailSender.SendEmailAsync(email, "Confirm your email", $"Please confirm your account by <a href='{confirmationLink}'>clicking here</a>.");

public Task SendPasswordResetLinkAsync(ApplicationUser user, string email, string resetLink) =>
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password by <a href='{resetLink}'>clicking here</a>.");

public Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode) =>
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password using the following code: {resetCode}");
}
Gipper
Gipper•6mo ago
@🅱immacle @Anu6is ok, thank ya'll I started moving stuff around and somehow I ended up changing compiler versions and it got real ugly real fast, just reverted to previous commit, will try again to implement what I was doing more carefully and with you guy's advice I'll call you guys here if I run into more trouble with that