I'm currently developing a Web API used by our mobile application. If an API-call is made that needs to send an email, the email is added to a queue in Azure Storage. For handling the queue (reading the queue mails and actually sending them) I thought the best solution would be creating a Hosted Service that will do this in the background.
For implementing this I followed the instructions from the following documentation: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.1
I created a class that implements the abstract BackgroundService-class from .NET Core 2.1 for this. It looks like this:
namespace Api.BackgroundServices
{
/// <summary>
/// Mail queue service.
/// This handles the queued mails one by one.
/// </summary>
/// <seealso cref="Microsoft.Extensions.Hosting.BackgroundService" />
public class MailQueueService : BackgroundService
{
private readonly IServiceScopeFactory serviceScopeFactory;
/// <summary>
/// Initializes a new instance of the <see cref="MailQueueService"/> class.
/// </summary>
/// <param name="serviceScopeFactory">The service scope factory.</param>
public MailQueueService(IServiceScopeFactory serviceScopeFactory)
{
this.serviceScopeFactory = serviceScopeFactory;
}
/// <summary>
/// This method is called when the <see cref="T:Microsoft.Extensions.Hosting.IHostedService" /> starts. The implementation should return a task that represents
/// the lifetime of the long running operation(s) being performed.
/// </summary>
/// <param name="stoppingToken">Triggered when <see cref="M:Microsoft.Extensions.Hosting.IHostedService.StopAsync(System.Threading.CancellationToken)" /> is called.</param>
/// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that represents the long running operations.</returns>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await HandleMailQueueAsync();
//await Task.Delay(3000, stoppingToken);
}
}
private async Task HandleMailQueueAsync()
{
using (IServiceScope serviceScope = serviceScopeFactory.CreateScope())
{
TelemetryClient telemetryClient = serviceScope.ServiceProvider.GetService<TelemetryClient>();
try
{
IMailHandler mailHandler = serviceScope.ServiceProvider.GetService<IMailHandler>();
await mailHandler.HandleMailQueueAsync();
}
catch (Exception exception)
{
telemetryClient.TrackException(exception);
}
}
}
}
}
After registering it by calling
services.AddHostedService<MailQueueService>();
in the Startup.cs, it will successfully handle the mail queue, but all other calls to the WebAPI take almost ten times as long. Only if I comment out the Task.Delay() part in my implementation of the BackgroundService, the performance goes back to an acceptable level.
However this seems more like a workaround than a real solution for my problem. Am I doing something else wrong that makes the performance tank like this?
I want my application to respect browser accept header and return 406, if it does not match the response format.
I have this options set in Mvc configuration:
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
/// <param name="services">The collection of the services.</param>
/// <returns>The provider of the service.</returns>
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// add mvc services
services.AddMvc(options =>
{
options.RespectBrowserAcceptHeader = true;
options.ReturnHttpNotAcceptable = true;
options.CacheProfiles.Add(
"CodebookCacheProfile",
new CacheProfile()
{
Duration = (int)TimeSpan.FromDays(1).TotalSeconds
});
})
.AddControllersAsServices()
.AddJsonOptions(options =>
{
options.SerializerSettings.Converters.Add(new StringEmptyToNullConverter());
options.SerializerSettings.Converters.Add(new StringEnumConverter(true));
});
// add response compression services
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>();
});
// add application services
services.AddSwaggerDoc()
.AddConfiguration(configuration)
.AddModel()
.AddDataAccess(configuration)
.AddAuthentication(configuration)
.AddDomainServices()
.AddSchedulerContainer(() => serviceProvider);
// initialize container
serviceProvider = services.CreateServiceProvider();
return serviceProvider;
}
When I try to send request like this: (with Accept header set on whatever, for example "text/xml")
I always get 200 OK - with "application/json"
My CountriesController looks like this:
/// <summary>
/// REST API controller for actions with countries.
/// </summary>
[AllowAnonymous]
[Area(Area.Common)]
[Route("[area]/Codebooks/[controller]")]
[ResponseCache(CacheProfileName = "CodebookCacheProfile")]
public class CountriesController : ApiController
{
private readonly ICountryService countryService;
/// <summary>
/// Initializes a new instance of the <see cref="CountriesController" /> class.
/// </summary>
/// <param name="countryService">The country service.</param>
public CountriesController(ICountryService countryService)
{
this.countryService = countryService ?? throw new ArgumentNullException(nameof(countryService));
}
/// <summary>
/// Gets countries by search settings.
/// </summary>
/// <response code="200">The countries was returned correctly.</response>
/// <response code="401">The unauthorized access.</response>
/// <response code="406">The not acceptable format.</response>
/// <response code="500">The unexpected error.</response>
/// <param name="countrySearchSettings">The search settings of the country.</param>
/// <returns>Data page of countries.</returns>
[HttpGet]
[ProducesResponseType(typeof(IDataPage<Country>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void), StatusCodes.Status406NotAcceptable)]
[ProducesResponseType(typeof(ApiErrorSummary), StatusCodes.Status500InternalServerError)]
[SwaggerOperation("SearchCountries")]
public IDataPage<Country> Get([FromQuery(Name = "")] CountrySearchSettings countrySearchSettings)
{
return countryService.Search(countrySearchSettings);
}
/// <summary>
/// Gets a country.
/// </summary>
/// <response code="200">The country was returned correctly.</response>
/// <response code="400">The country code is not valid.</response>
/// <response code="401">The unauthorized access.</response>
/// <response code="406">The not acceptable format.</response>
/// <response code="500">The unexpected error.</response>
/// <param name="countryCode">The code of the country.</param>
/// <returns>Action result.</returns>
[HttpGet("{countryCode}")]
[ProducesResponseType(typeof(Country), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiValidationErrorSummary), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void), StatusCodes.Status406NotAcceptable)]
[ProducesResponseType(typeof(ApiErrorSummary), StatusCodes.Status500InternalServerError)]
[SwaggerOperation("GetCountry")]
public IActionResult Get(string countryCode)
{
var country = countryService.GetByCode(countryCode);
return Ok(country);
}
}
Do you have any idea why the request Accept header is always ignored and the response is always 200 OK with correct Json data?
What am I missing? I thought that the setting of RespectBrowserAcceptHeader and ReturnHttpNotAcceptable would do the thing... but apparently not.
Why it always falls back to the default Json formatter?
For ReturnHttpNotAcceptable to work, the type returned by an action must be either an ObjectResult (e.g. Ok(retval)) or a type that does not implement IActionResult (in which case the MVC framework will wrap it in an ObjectResult for you).
This is because the MVC framework only checks against the value of ReturnHttpNotAcceptable in ObjectResultExecutor, and not in any of the other IActionResultExecutor implementations (like ViewResultExecutor). (See source code for ObjectResultExecutor and ViewResultExecutor)
Put simply, make sure that the type you are returning doesn't implement (or inherit from anything that implements) IActionResult.
Add the following line in your ConfigureServices method of Startup.cs
services.AddMvcCore().AddJsonFormatters().AddApiExplorer();
i have an action on a controller which calls
var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
i'm trying to mock this result in a unit test like so
httpContextMock.AuthenticateAsync(Arg.Any<string>()).Returns(AuthenticateResult.Success(...
however that throws an InvalidOperationException
"No service for type 'Microsoft.AspNetCore.Authentication.IAuthenticationService' has been registered"
what is the correct way to mock this method?
That extension method
/// <summary>
/// Extension method for authenticate.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> context.</param>
/// <param name="scheme">The name of the authentication scheme.</param>
/// <returns>The <see cref="AuthenticateResult"/>.</returns>
public static Task<AuthenticateResult> AuthenticateAsync(this HttpContext context, string scheme) =>
context.RequestServices.GetRequiredService<IAuthenticationService>().AuthenticateAsync(context, scheme);
goes through the IServiceProvider RequestServices property.
/// <summary>
/// Gets or sets the <see cref="IServiceProvider"/> that provides access to the request's service container.
/// </summary>
public abstract IServiceProvider RequestServices { get; set; }
Mock the service provider to return a mocked IAuthenticationService and you should be able to fake your way through the test.
authServiceMock.AuthenticateAsync(Arg.Any<HttpContext>(), Arg.Any<string>())
.Returns(Task.FromResult(AuthenticateResult.Success()));
providerMock.GetService(typeof(IAuthenticationService))
.Returns(authServiceMock);
httpContextMock.RequestServices.Returns(providerMock);
//...
I have the following class:
/// <summary>
/// Represents an implementation of the <see cref="IAspNetCoreLoggingConfigurationBuilder"/> to configure the ASP.NET Core Logging.
/// </summary>
public class AspNetCoreLoggingConfigurationBuilder : IAspNetCoreLoggingConfigurationBuilder
{
#region Properties
/// <summary>
/// Gets the <see cref="ILogSource"/> that's used to write log entries.
/// </summary>
public ILogSource LogSource{ get; private set; }
#endregion
#region IAspNetCoreLoggingConfigurationBuilder Members
/// <summary>
/// Sets the log source that should be used to save log entries.
/// </summary>
/// <param name="logSource">The source </param>
public void SetLogSource(ILogSource logSource)
{
LogSource = logSource;
}
#endregion
}
I also have a method in which I create an instance of this class:
/// <summary>
/// Adds logging to the <see cref="IApplicationBuilder"/> request execution pipeline.
/// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to configure the application's request pipeline.</param>
/// <param name="configuration">Builder used to configure the ASP.NET Core Logging.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseAspNetCoreLogging(this IApplicationBuilder app, Action<IAspNetCoreLoggingConfigurationBuilder> configuration)
{
var aspNetLoggerConfiguration = new AspNetCoreLoggingConfigurationBuilder();
configuration(aspNetLoggerConfiguration);
// Add the registered ILogSource into the registered services.
_services.AddInstance(typeof (ILogSource), aspNetLoggerConfiguration.LogSource);
// The entire configuration for the middleware has been done, so return the middleware.
return app.UseMiddleware<AspNetCoreLoggingMiddleware>();
}
Notice the first line here, I'm creating an instance of the class.
However, when I inspect this variable in a watch, when my cursor is on line configuration(aspNetLoggerConfiguration); I do get that the variable does not exists in the current context.
Creating an instance of the variable does work when doing it directly in the watch window.
Anyone has a clue?
P.S. It's a DNX project which I'm testing in xUnit. The code is running in 'Debug' mode.
Thats no runtime and no compiling-error.
It's a problem of Visual Studio not beeing able to show the object in a debug-window as it is a runtime-object (something like that).
Another occurence of this problem is in a wcf-service client. Create a new serviceclient Client and try to show client.InnerChannel in the watch window. It won't work. You can however create a temp-object (bool, string, etc..) and write the desired value into it to see your value.
#if DEBUG
var tmpLog = aspNetLoggerConfiguration.LogSource;
#endif
You should see the LogSource in the tmpLog when your mouse is over it.
Our team decided to use Domain Driven Design architecture for our project. Now the discussion is going on for, "can we use ASP.NET Identity in DDD?".
Is there any disadvantages on using ASP.NET identity in DDD design.
I'm in a confusion to make a decision on it.
I have searched for it, but I didn't get any idea.
Any help would be appreciable.
The questions reveals several misconceptions:
It appears that you perceive the domain model as some monolithic model where you put every piece of application in. Instead, concentrate on strategic patterns to distinguish Bounded Contexts. Consider the domain as a composition of several loosely interconnected components. Then identify what your core domain is and apply DDD tactical patterns there. Not every ccomponent needs DDD. Some of them even should not use DDD. Especially - generic domains, like Authentication.
DDD is technology agnostic (to some point) so yes, you can use ASP.NET Identity or whatever library you like.
Authentication typically belongs to the Application layer, not Domain layer.
However - if in your domain there is a concept of a user/client/person, it might be required to use the identity provided by the identity component. But you have to understand that the meaning of User in your bounded context is different than meaning of User in Identity component. These are not the same concept. Although they both refer to the same physical person sitting somewhere and clicking on your app's GUI, they are 2 different models (or projections) of him that serve different purposes. So you shouldn't just reuse the ASP.NET User class in your bounded context.
Instead - separate contexts should communicate via an anticorruption layer. Basically you have to make some service (interface only) in your bounded context that produces context-specific User objects. The implementation of that interface made in infrastructure layer will be a wrapper of ASP.NET Identity that gets ASP.NET Identity user and produce corresponding bounded context's user.
I am new to DDD. But I achieved integration with Identity and DDD. Although I doubt it truly sticks to the priciples of DDD.
I started with the Entity:
public partial class User : IdentityUser {
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager) {
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
/// <summary>
/// The Date the User Registered for general information purposes
/// </summary>
public DateTime DateRegistered { get; set; }
}
Then the Interface:
public interface IUserRepository:IBaseRepository<User> {
/// <summary>
/// Register User to Identity Database
/// </summary>
/// <param name="userManager">User Manager to Handle Registration</param>
/// <param name="user">User to add to database</param>
/// <param name="password">User's password</param>
/// <returns>Identity Result</returns>
Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password);
/// <summary>
/// Login User
/// </summary>
/// <param name="signinManager">Signin Manager to handle login</param>
/// <param name="email">Email of user</param>
/// <param name="password">Password of user</param>
/// <param name="rememberMe">Boolean if the user wants to be remembered</param>
/// <returns>SignIn Status</returns>
Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe);
/// <summary>
/// Verify that code sent to User is valid
/// </summary>
/// <param name="signinManager">Signin Manager to handle verification</param>
/// <param name="provider">Provider of the code</param>
/// <param name="code">The code</param>
/// <param name="rememberMe">Boolean if user wants to be remembered</param>
/// <param name="rememberBrowser">Boolean if browser should be remembered</param>
/// <returns>SignIn Status</returns>
Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser);
/// <summary>
/// Confirm email of User
/// </summary>
/// <param name="userManager">User Manager to handle confirmation</param>
/// <param name="userId">String user Id of the User</param>
/// <param name="code">User code sent in Email</param>
/// <returns>Identity Result</returns>
Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code);
void ForgotPassword();
void ForgotPasswordConfirmation();
void ResetPassword();
void ResetPasswordConfirmation();
void ExternalLogin();
void SendCode();
void ExternalLoginCallback();
void ExternalLoginConfirmation();
/// <summary>
/// Log off user from the Application
/// </summary>
/// <param name="AuthenticationManager">Application Manager to handle Sign out</param>
void Logoff(IAuthenticationManager AuthenticationManager);
/// <summary>
/// Get user based on their Email
/// </summary>
/// <param name="Email">Email of user</param>
/// <returns>User</returns>
User GetUser(string Email);
/// <summary>
/// Get User by their GUID
/// </summary>
/// <param name="ID">GUID</param>
/// <returns>User</returns>
User GetUserById(string ID);
}
Then the Repository:
public class UserRepository : BaseRepository<User>, IUserRepository {
/// <summary>
/// Confirm email of User
/// </summary>
/// <param name="userManager">User Manager to handle confirmation</param>
/// <param name="userId">String user Id of the User</param>
/// <param name="code">User code sent in Email</param>
/// <returns>Identity Result</returns>
public async Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code) =>
await userManager.ConfirmEmailAsync(userId, code);
public void ExternalLogin() {
throw new NotImplementedException();
}
public void ExternalLoginCallback() {
throw new NotImplementedException();
}
public void ExternalLoginConfirmation() {
throw new NotImplementedException();
}
public void ForgotPassword() {
throw new NotImplementedException();
}
public void ForgotPasswordConfirmation() {
throw new NotImplementedException();
}
/// <summary>
/// Get user based on their Email
/// </summary>
/// <param name="Email">Email of user</param>
/// <returns>User</returns>
public User GetUser(string Email) =>
_context.Users.Where(p => p.Email == Email).FirstOrDefault();
/// <summary>
/// Get User by their GUID
/// </summary>
/// <param name="ID">GUID</param>
/// <returns>User</returns>
public User GetUserById(string ID) =>
_context.Users.Find(ID);
/// <summary>
/// Login User
/// </summary>
/// <param name="signinManager">Signin Manager to handle login</param>
/// <param name="email">Email of user</param>
/// <param name="password">Password of user</param>
/// <param name="rememberMe">Boolean if the user wants to be remembered</param>
/// <returns>SignIn Status</returns>
public async Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe) =>
await signinManager.PasswordSignInAsync(email, password, rememberMe, shouldLockout: false);
/// <summary>
/// Log off user from the Application
/// </summary>
/// <param name="AuthenticationManager">Application Manager to handle Sign out</param>
public void Logoff(IAuthenticationManager AuthenticationManager) {
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
}
/// <summary>
/// Register User to Identity Database
/// </summary>
/// <param name="userManager">User Manager to Handle Registration</param>
/// <param name="user">User to add to database</param>
/// <param name="password">User's password</param>
/// <returns>Identity Result</returns>
public async Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password) =>
await userManager.CreateAsync(user, password);
public void ResetPassword() {
throw new NotImplementedException();
}
public void ResetPasswordConfirmation() {
throw new NotImplementedException();
}
public void SendCode() {
throw new NotImplementedException();
}
/// <summary>
/// Verify that code sent to User is valid
/// </summary>
/// <param name="signinManager">Signin Manager to handle verification</param>
/// <param name="provider">Provider of the code</param>
/// <param name="code">The code</param>
/// <param name="rememberMe">Boolean if user wants to be remembered</param>
/// <param name="rememberBrowser">Boolean if browser should be remembered</param>
/// <returns>SignIn Status</returns>
public async Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser) =>
await signinManager.TwoFactorSignInAsync(provider, code, isPersistent: rememberMe, rememberBrowser: rememberBrowser);
}
IService:
public interface IUserService {
/// <summary>
/// Register User to Identity Database
/// </summary>
/// <param name="userManager">User Manager to Handle Registration</param>
/// <param name="user">User to add to database</param>
/// <param name="password">User's password</param>
/// <returns></returns>
Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password);
/// <summary>
/// Login User
/// </summary>
/// <param name="signinManager">Signin Manager to handle login</param>
/// <param name="email">Email of user</param>
/// <param name="password">Password of user</param>
/// <param name="rememberMe">Boolean if the user wants to be remembered</param>
/// <returns></returns>
Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe);
/// <summary>
/// Verify that code sent to User is valid
/// </summary>
/// <param name="signinManager">Signin Manager to handle verification</param>
/// <param name="provider">Provider of the code</param>
/// <param name="code">The code</param>
/// <param name="rememberMe">Boolean if user wants to be remembered</param>
/// <param name="rememberBrowser">Boolean if browser should be remembered</param>
/// <returns></returns>
Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser);
/// <summary>
/// Confirm email of User
/// </summary>
/// <param name="userManager">User Manager to handle confirmation</param>
/// <param name="userId">String user Id of the User</param>
/// <param name="code">User code sent in Email</param>
/// <returns></returns>
Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code);
void ForgotPassword();
void ForgotPasswordConfirmation();
void ResetPassword();
void ResetPasswordConfirmation();
void ExternalLogin();
void SendCode();
void ExternalLoginCallback();
void ExternalLoginConfirmation();
/// <summary>
/// Log off user from the Application
/// </summary>
/// <param name="AuthenticationManager">Application Manager to handle Sign out</param>
void Logoff(IAuthenticationManager AuthenticationManager);
/// <summary>
/// Get user based on their Email
/// </summary>
/// <param name="Email">Email of user</param>
/// <returns>User</returns>
User GetUser(string Email);
/// <summary>
/// Get User by their GUID
/// </summary>
/// <param name="ID">GUID</param>
/// <returns>User</returns>
User GetUserById(string ID);
}
Service:
public class UserService : ServiceBase, IUserService {
#region Private Field
private IUserRepository _userRepository;
#endregion
#region Constructor
/// <summary>
/// Constructor to initialise User Repository
/// </summary>
/// <param name="userRepository"></param>
public UserService(IUserRepository userRepository) {
_userRepository = userRepository;
}
#endregion
#region Methods
/// <summary>
/// Confirm email of User
/// </summary>
/// <param name="userManager">User Manager to handle confirmation</param>
/// <param name="userId">String user Id of the User</param>
/// <param name="code">User code sent in Email</param>
/// <returns>Identity Result</returns>
public Task<IdentityResult> ConfirmEmail(UserManager<User, string> userManager, string userId, string code) =>
_userRepository.ConfirmEmail(userManager, userId, code);
public void ExternalLogin() {
throw new NotImplementedException();
}
public void ExternalLoginCallback() {
throw new NotImplementedException();
}
public void ExternalLoginConfirmation() {
throw new NotImplementedException();
}
public void ForgotPassword() {
throw new NotImplementedException();
}
public void ForgotPasswordConfirmation() {
throw new NotImplementedException();
}
/// <summary>
/// Get user based on their Email
/// </summary>
/// <param name="Email">Email of user</param>
/// <returns>User</returns>
public User GetUser(string Email) {
throw new NotImplementedException();
}
/// <summary>
/// Get User by their GUID
/// </summary>
/// <param name="ID">GUID</param>
/// <returns>User</returns>
public User GetUserById(string ID) {
throw new NotImplementedException();
}
/// <summary>
/// Login User
/// </summary>
/// <param name="signinManager">Signin Manager to handle login</param>
/// <param name="email">Email of user</param>
/// <param name="password">Password of user</param>
/// <param name="rememberMe">Boolean if the user wants to be remembered</param>
/// <returns>SignIn Status</returns>
public Task<SignInStatus> Login(SignInManager<User, string> signinManager, string email, string password, bool rememberMe) =>
_userRepository.Login(signinManager, email, password, rememberMe);
/// <summary>
/// Log off user from the Application
/// </summary>
/// <param name="AuthenticationManager">Application Manager to handle Sign out</param>
public void Logoff(IAuthenticationManager AuthenticationManager) {
_userRepository.Logoff(AuthenticationManager);
}
/// <summary>
/// Register User to Identity Database
/// </summary>
/// <param name="userManager">User Manager to Handle Registration</param>
/// <param name="user">User to add to database</param>
/// <param name="password">User's password</param>
public Task<IdentityResult> Register(UserManager<User, string> userManager, User user, string password) =>
_userRepository.Register(userManager, user, password);
public void ResetPassword() {
throw new NotImplementedException();
}
public void ResetPasswordConfirmation() {
throw new NotImplementedException();
}
public void SendCode() {
throw new NotImplementedException();
}
/// <summary>
/// Verify that code sent to User is valid
/// </summary>
/// <param name="signinManager">Signin Manager to handle verification</param>
/// <param name="provider">Provider of the code</param>
/// <param name="code">The code</param>
/// <param name="rememberMe">Boolean if user wants to be remembered</param>
/// <param name="rememberBrowser">Boolean if browser should be remembered</param>
/// <returns>SignIn Status</returns>
public Task<SignInStatus> VerifyCode(SignInManager<User, string> signinManager, string provider, string code, bool rememberMe, bool rememberBrowser) =>
_userRepository.VerifyCode(signinManager, provider, code, rememberMe, rememberBrowser);
#endregion
}
You can use anything you like. But be aware of pollution particular solution is going to make. If your domain model gets messed up with hundreds of lines of asp.net technical kind of plumbing code that makes your domain logic hard to perceive and you are missing point of DDD.
In ideal situation - your domain model should depend only on programming language.
Also - you might find something useful from my long time ago implementation of user session related code.