Home > Back-end >  Passing data inside the application via services
Passing data inside the application via services

Time:06-06

I have a web app that has rows of data which has a column called active. If a row is inactive the row is still presented to the user.

The client wants to have a localStorage toggle option to hide inactive rows from the view. Since all of my logic happens in the controller using the localStorage to filter html rows just doesn't seem proper. (Hiding elements with javascript vs simply filtering the data at the controller level).

If I cannot add a new column in the database for a "hide inactive items" feature--what would be the best solution to add a toggle inactive items in the entire application?

I was thinking of creating a claim:

new Claim(ClaimTypes.UserData, "true", ClaimValueTypes.Boolean), // Hide inactive rows

And later in the application:

internal static bool showInactiveRows(ClaimsPrincipal user)
{
    var showInactive = true; // Default hide inactive rows
    var identity = (ClaimsIdentity)user.Identity;
    if (identity != null)
    {
        // Get claim containing our setting
        var _showInactiveRows = identity.FindFirst(ClaimTypes.UserData);

        if (_showInactiveRows != null)
            // Set the session value to the model
            showInactive = bool.Parse(_showInactiveRows.Value);

    }
    return showInactive;
}

internal static async void setHideInactiveRows(ClaimsPrincipal user, bool hideInactiveRows)
{
    var identity = (ClaimsIdentity)user.Identity;
    if (identity != null)
    {
        // Get claim containing our setting
        var _showInactiveRows = identity.FindFirst(ClaimTypes.UserData);

        identity.RemoveClaim(_showInactiveRows);
        identity.AddClaim(new Claim(ClaimTypes.UserData, hideInactiveRows.ToString(), ClaimValueTypes.Boolean));

        /*if (SignInManager.IsSignedIn(User)) // Need to call this to refresh claims without logging out
        {
            var user = await UserManager.GetUserAsync(User);
            await SignInManager.RefreshSignInAsync(user);
        }*/

    }
}

Then when I'm grabbing data:

var hideInactiveRows = UserClaims.showInactiveRows(User);

if(hideInactiveRows)
{
    FarmList = await _context.Farms
        .Where(i => i.Active == hideInactiveRows) // Active = true show only active rows
        .OrderBy(g => g.Name)
        .ToListAsync();
} else {
     FarmList = await _context.Farms
        .OrderBy(g => g.Name)
        .ToListAsync();
}

However this too doesn't seem right to me.

Is there a better way to update and pass data inside the application on a per user basis?

CodePudding user response:

To anyone who needs a solution in the future I tried the query param checking in the OnGet() method but this was taking too long as I have to modify 50 pages.

The solution I came up with is to simply just create a Singleton Service:

public interface IUserMemStorage
{
    // Using concurrent dictionary as it's thread safe
    ConcurrentDictionary<int, string> UserHideInactiveRowStore { get; set; }
        
    // Create other tmp storages here
}

// Note: Only register this interface as a singleton
// I created a new interface to explicitly mention singleton
public interface IUserMemStorageSingleton : IUserMemStorage { }

public class UserMemStorage : IUserMemStorageSingleton
{
    public UserMemStorage()
    {
        UserHideInactiveRowStore = new();
    }

    public ConcurrentDictionary<int, string> UserHideInactiveRowStore { get; set; }
}

then later register the service in the Startup.cs.

Now on the pages I need this on I can simply use the dependency injection container and check if I should show/hide the results based on the userId. No need to modify any backlinks or different navigation pages as the bool is stored in the thread safe dictionary. :)

  • Related