Trouble when using ApplicationUser: IdentityUser, UserManager in clean architecture asp.net core
Asked Answered
L

1

6

I am working a asp.net core 6.0 WebAPI in a clean Architecture.https://github.com/jasontaylordev/CleanArchitecture

There are 4 projects in this architecture. WebApi, Infrastructure, Application and Domain.

  • Domain is the Core.
  • Application Layer is dependent on Domain Layer.
  • Infrastructure Layer is dependent on Application Layer.
  • WebApi Layer is dependent on Application Layer and Infrastructure Layer.

And The Queries and command (CQRS) should be written inside Application Layer

I want to use Asp.Net Core Identity.

ApplicationUser.cs ( in Infrastructure/Identity )

namespace Infrastructure.Identity;

public class ApplicationUser : IdentityUser
{
  // removed
}

IIdentityService.cs (in Application/Common/Interfaces)

namespace Application.Common.Interfaces;

public interface IIdentityService
{
    Task<string> GetUserNameAsync(string userId);

    Task<bool> IsInRoleAsync(string userId, string role);

    Task<bool> AuthorizeAsync(string userId, string policyName);

    Task<(Result Result, string UserId)> CreateUserAsync(string userName, string password);

    Task<Result> DeleteUserAsync(string userId);

   // and so on
}

IdentityService.cs ( in Infrastructure/Identity )

namespace Infrastructure.Identity;

public class IdentityService : IIdentityService
{
    private readonly UserManager<ApplicationUser> _userManager;

    public IdentityService(
        UserManager<ApplicationUser> userManager )
    {
        _userManager = userManager;
    }

  //implementations of Interface by using userManager
}

above all work fine.

My Issue is, I have to UserManager<ApplicationUser> userManager to write a query (in APllication Layer )

I got error, Unnecessary using directive. [Application] The type or namespace name 'Infrastructure' does not exist in the namespace are you missing an assembly reference?) [Application]

Query.cs ( in Application/SiteCodes/Queries/GetAll )

using Infrastructure.Identity;   // error

namespace Application.SiteCodes.Queries.GetAll
{
    public class GetAllQueryHandler : IRequest<List<SiteCode>>
    {

    }
    public class GetAllQueryHandlerHandler : IRequestHandler<GetAllQueryHandler,List<SiteCode>>
    {
        private readonly UserManager<ApplicationUser> _userManager;  // error
        private readonly IHttpContextAccessor _httpContextAccessor;

       // constructor removed 

       public async Task<List<SiteCode>> Handle(GetAllQueryHandler request, 
           CancellationToken cancellationToken)
        {
            var user = await 
           _userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);   // By using usermanger. I have to call more function like this from useManager

           // removed rest
        }
    }
}

How can I do this without any error?. How can I call userManager and ApplicationUser ( : IdentyUser) inside Application Layer

Please help me.

Note : I don't want to write function by myself like useManager package. I want to use userManager.

Eg: Like this

private readonly UserManager<ApplicationUser> _userManager;

_userManager.GetUserAsync(_httpContextAccessor.HttpContext.User);

Anyone have idea to solve this issue?

Ladyfinger answered 5/1, 2022 at 17:56 Comment(0)
R
5

In your application layer, you're only supposed to use the common interfaces. For example here, you shouldn't use the UserManager class directly, but use the public interface IIdentityService.

The application layer is described as:

This layer defines interfaces that are implemented by outside layers. For example, if the application need to access a notification service, a new interface would be added to application and an implementation would be created within infrastructure.

That means you can extend the IIdentityService interface as needed, with the corresponding implementation in the infrastructure layer.

You also shouldn't be using the IHttpContextAccessor in your application layer, because it's part of the WebUI layer.

Some ideas to fix your issues:

  • IHttpContextAccessor should only be accessed in the WebUI layer: in your API controller, get the current user from it, then retrieve the ApplicationUser and its ID from the UserManager
  • pass the user's ID to your application layer
  • use the IIdentityService with that user ID
Ramshackle answered 6/1, 2022 at 14:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.