I've read that usually for this type of error you have only to register the new class on your Startup.cs like this:
services.AddTransient<IEmailSender,MyEmailSender>();
The problem is that i had it implemented even before the error occurred. Here is the raw error and the code:
System.InvalidOperationException: Unable to resolve service for type 'xxxx.Areas.Identity.Services.MyEmailSender' while attempting to activate 'xxxx.Areas.Identity.Pages.Account.RegisterModel'. at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) at lambda_method(Closure , IServiceProvider , Object[] ) at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageModelActivatorProvider.<>c__DisplayClass1_0.b__0(PageContext context) at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageModelFactoryProvider.<>c__DisplayClass3_0.b__0(PageContext pageContext) at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.CreateInstance() at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Now the code:
Startup.cs myemail registration
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>(config => {
config.SignIn.RequireConfirmedEmail = true;
config.Stores.MaxLengthForKeys = 128; })
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders();
services.AddTransient<IEmailSender, MyEmailSender>(i =>
new MyEmailSender(
Configuration["EmailSender:Host"],
Configuration.GetValue<int>("EmailSender:Port"),
Configuration.GetValue<bool>("EmailSender:EnableSSL"),
Configuration["EmailSender:UserName"],
Configuration["EmailSender:Password"]
)
);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddControllersAsServices();
}
Register.cshtml.cs
namespace xxxx.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class RegisterModel : PageModel
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly ILogger<RegisterModel> _logger;
private readonly MyEmailSender _emailSender;
public RegisterModel(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILogger<RegisterModel> logger,
MyEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
_emailSender = emailSender;
}
[BindProperty]
public InputModel Input { get; set; }
public string ReturnUrl { 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; }
[Required]
[MinLength(4)]
[Column(TypeName = "Varchar(30)")]
public string User { get; set; }
[Required]
[MinLength(4)]
[Column(TypeName = "Varchar(30)")]
public string Name { get; set; }
[Required]
[MinLength(4)]
[Column(TypeName = "Varchar(30)")]
public string Surname { get; set; }
public Gender Gender { get; set; }
public DateTime RegistrationDate { get; set; } = DateTime.Now;
[DefaultValue(0)]
public int Coins { get; set; }
[Required]
public bool IsAdmin { get; set; }
}
public void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = Input.User, Email = Input.Email, Name = Input.Name,
SurName = Input.Surname, Gender = Input.Gender };
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);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
StringBuilder VerCode = new StringBuilder();
Char[] generator = user.Id.ToCharArray();
for (int i = 0; i < 16; i = +4)
{
VerCode.Append(generator[i]);
}
var verificationCode = VerCode.ToString();
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
"Your verification code for your registration to Gen/Music is "
+ verificationCode + " please use this to verify your account!"
+ $"Please write the given code to confirm your account <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>Click here first!</a>.");
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();
}
}
}