enkodellc / blazorboilerplate

Blazor Boilerplate / Starter Template with MudBlazor
MIT License
1.87k stars 369 forks source link

Use local storage in favor of storing user profile in database? #96

Open oneparameter opened 4 years ago

oneparameter commented 4 years ago

Local storage is great for storing the UserProfile's properties LastPageVisited, isNavOpen and isNavMinified. It's easily accessible through jsinterop and you'd also would save valuable resources on the server because it removes the call to the server and the database.

enkodellc commented 4 years ago

@oneparameter Yes I have researched it a bit but it was several months ago.

Do you have a component to recommend?

It looks like they have updated the ProtectedSessionStore in 3.1.. https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-3.1

In any case I am open to discussions / changes for best practices for the UserProfile. I first put it in because there was not much out there and at the time I think the scoped UserProfile was Loaded Once from the DB if it was null and the user was logged in. Then when it needed to update it would call the DB.

The only caveat I have with other components is they tend to not keep up with the latest changes and then I have to rely on doing other people's PR's and fixes. I was really waiting for MS to come up with a Profile / Session for Blazor to replace my "hack"

oneparameter commented 4 years ago

Do you have a component to recommend?

By component to recommend, do you mean a component that is developed by someone else and incorporate that into your app?

It looks like they have updated the ProtectedSessionStore in 3.1.. https://docs.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-3.1

I'd argue that keeping UI related information in localstorage or sessionstorage without using dataprotection is perfectly fine and harmless. If a user wants to change those values, let him go ahead.

The only caveat I have with other components is they tend to not keep up with the latest changes and then I have to rely on doing other people's PR's and fixes. I was really waiting for MS to come up with a Profile / Session for Blazor to replace my "hack"

So my question about other components is still important because I don't exactly understand what it is you mean by them.

Also, I think Microsoft won't be providing such specific components.

To provide an example as to how easy access it is to access local storage:

@inject IJSRuntime js

code {

    async Task AddToLocalStorage(string value) 
    {
        await js.InvokeAsync<object>("localStorage.setItem", "some-key", value);
    }

}
enkodellc commented 4 years ago

@oneparameter Yes I have seen this pattern before. Are you suggesting that update the UserProfile class to use this pattern to get / set the UserProfile data and subsequently to the server asynchronously when appropriate? I like it. I can create a branch if you want to refactor and submit a PR?

The "other" components I spoke of are 3rd party components like this: https://github.com/Blazored/LocalStorage

I come from using Asp.net Webforms for a long time and used their Profile Property Provider for most of this type of information. It was a bit costly because it would access the DB but of course that is server side so that design pattern is not good for Blazor WebAssembly.

oneparameter commented 4 years ago

@enkodellc I'd happy to redesign the profile part, but do you still even prefer to keep the user profile data in the database at all? - I'm talking about the data mentioned in my first post of course.

I mean after all, besides being able to keep menu state when switching devices or browsers, does your portal boilerplate really benefit from this? It just feels a bit gimmicky. But maybe if the whole point of the portal is to add as many showcases or examples, then yes.

Personally, I see every addition like that as another obstacle that might prevent someone from using the boilerplate in their projects since the user profile gets really 'woven' into the whole thing especially when you store it in the database like that.

enkodellc commented 4 years ago

@oneparameter thanks for you feedback. For me the User Profile Settings stored in a persistent data store is very beneficial, the current fields are a bit gimmicky because that is a starting point. In the application I am refactoring into Blazor, which is why I created Blazor Boilerplate, I store well over a dozen user specific flags or settings that enhance user experience.

I do want to showcase examples and of course I want to be aware of feature creep. I do plan on putting as much in there as I personally use in my projects.

Here are some examples I use for my User Profile:

If you have an alternative solution to using this type of data or have additional questions let's discuss on Gitter: https://gitter.im/blazorboilerplate/community

I have no ego in this app so I am very open to design and architecture opinions. Thanks!

VR-Architect commented 4 years ago

As you start to tackle this, please keep in mind the need for offline storage with auto-sync to server when reconnected to the internet feature. The user profile could be the first object for this. If I get to it first, I will add it back to the repository if desired.

MaxLaurieHutchinson commented 4 years ago

ever thought of using options.UseInMemoryDatabase("Database")); and a data persistence layer, that way it can be easier to getting setup for testing and having mock data.

This could be used with a DBContextFactory and and Data Initializer?

enkodellc commented 4 years ago

Honestly @maximus258 I have been too busy with maintaining BB, updating MatBlazor, and my real job to do more features. That is where I was hoping more contributors would step in and do some advanced features / functionality since I have provided a ton of the UI / foundation for BB. If you wish to contribute to BB it would be greatly appreciated.

prvit commented 3 years ago

Not sure if it needs to be implemented as someone can just take a package, for example Blazored.LocalStorage configure DI and inject when needed. In the box, it still will call

await js.InvokeAsync<object>("localStorage.setItem", "some-key", value);

but you have a great c# wrapper that's already covered by tests etc. That's how it would look like :


await localStorage.SetItemAsync("name", "John Smith");
var name = await localStorage.GetItemAsync<string>("name");