Mohsen
Mohsen

Reputation: 11

Currently logged in user info in a class in ASP.NET Core .NET 8 Blazor Server Project

I have a Blazor server project that has auth set up through Entra Id. I can get user info including their roles in the components, but I also need to identify who the current user is in a class.

The main reason I need the user info is that when an error happens in a class (say database becomes unavailable while retrieving some data), I would catch the error, amend all the metadata I can (including who the user was when this happened) and then log it to a file, in order to make troubleshooting easier.

I used to do this easily in ASP.NET forms but I am new to .NET Core and Blazor and there are not much documentation when it comes to .NET 8 and Entra Id.

For now the only work around I have found is that in the components, when I need to create an instance of an object or run a static method, I pass on the current logged in user info to the class which then can be used while logging error. I would prefer to have a class that gets this done for me so that I don't need to run the same code in every component.

Any help would be appreciated.

Here is my code - component:

@code
{
    string loggedinUser = "";

    private void Log()
    {    
        loggedinUser = GetClaimsPrincipalData().Result;
        Building.Test(loggedinUser);
    }

    private async Task<string?> GetClaimsPrincipalData()
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;
        string username = "";

        if (user.Identity is not null && user.Identity.IsAuthenticated)
        {
            username = user.FindFirst(c => c.Type == ClaimTypes.Email)?.Value;
        }
        else
        {
            Logger.Log("MessageType", "Error Number", "SourceFileName", "Unknown User", "Message");
        }

        return username;
    }
}

And this is the class:

using Microsoft.Extensions.Logging;
using System.Data.SqlClient;
using System.Data;

namespace MyApp.Models
{
    public class Building
    {
        public static void Test(string UserName)
        {
            Logger.Log("MessageType", "Error Number", "SourceFileName", UserName, "Message");
        }
    }
}

Update: As per @qiang-fu 's comment, if I have the following class, how can I get the username from other classes?

public class AuthTest 
{
     private readonly AuthenticationStateProvider _authenticationStateProvider;

     public AuthTest(AuthenticationStateProvider authenticationStateProvider)
     {
         this._authenticationStateProvider = authenticationStateProvider;
     }
     public async Task<string> Username()
     {
         var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
         var user = authState.User;
         string username = "Unknown";

         if (user.Identity is not null && user.Identity.IsAuthenticated)
         {
             username = user.FindFirst(c => c.Type == ClaimTypes.Email)?.Value;
         }
         return username;
     }
     public AuthTest()
     {
     }
}

Thanks

Upvotes: 1

Views: 1406

Answers (1)

Qiang Fu
Qiang Fu

Reputation: 8631

You cannot use dependency injection for static class/method. So just make a normal class like below with inject "AuthenticationStateProvider".

    public class Building
    {
        private readonly AuthenticationStateProvider _authenticationStateProvider;

        public Building(AuthenticationStateProvider authenticationStateProvider)
        {
            this._authenticationStateProvider = authenticationStateProvider;
        }
        private async Task Log()
        { 
            var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
            var user = authState.User;
            string username = "";

            if (user.Identity is not null && user.Identity.IsAuthenticated)
            {
                username = user.FindFirst(c => c.Type == ClaimTypes.Email)?.Value;
                Logger.Log("MessageType", "Error Number", "SourceFileName", username, "Message");
            }
            else
            {
                Logger.Log("MessageType", "Error Number", "SourceFileName", "Unknown User", "Message");
            }
        }
    }

Then register it in the program.cs

builder.Services.AddScoped<Building>();

Then you can use it in component by inject them

@inject AuthenticationStateProvider AuthenticationStateProvider
@inject Building Building


@code{
    private void Log()
    {
        Building.Log(AuthenticationStateProvider);
    }
}

Upvotes: 1

Related Questions