From 1e563e8b5f7522a3d2031445ad6c17a12e622755 Mon Sep 17 00:00:00 2001 From: Chanan Braunstein Date: Thu, 6 Dec 2018 09:19:42 -0700 Subject: [PATCH] V0.7.0 --- BlazorDB.sln | 6 -- README.md | 25 +++++++ src/BlazorDB/BlazorDB.csproj | 8 +-- src/BlazorDB/IStorageContext.cs | 8 ++- src/BlazorDB/ServiceCollectionExtensions.cs | 21 ++++-- src/BlazorDB/Storage/IStorageManager.cs | 8 +-- src/BlazorDB/Storage/Logger.cs | 15 +++-- src/BlazorDB/Storage/StorageManager.cs | 8 +-- src/BlazorDB/Storage/StorageManagerLoad.cs | 51 ++++++-------- src/BlazorDB/Storage/StorageManagerSave.cs | 35 +++++----- src/BlazorDB/Storage/StorageManagerUtil.cs | 12 ++-- src/BlazorDB/Storage/StringExtensions.cs | 10 +++ src/BlazorDB/Storage/blazorDBInterop.cs | 27 +++++--- src/BlazorDB/StorageContext.cs | 17 +++-- src/BlazorDB/StorageSet.cs | 4 +- src/BlazorDB/content/blazorDBInterop.js | 67 +++++++++---------- .../FluxorIntegration.csproj | 8 +-- .../Pete/IServiceCollectionExtensions.cs | 15 +++++ .../PeteConsumer/MovieDbState.cs | 0 src/FluxorIntegration/Program.cs | 28 ++------ src/FluxorIntegration/Startup.cs | 30 +++++++++ src/FluxorIntegration/wwwroot/index.html | 5 +- src/Sample/Pages/Associations.cshtml | 4 ++ src/Sample/Pages/Index.cshtml | 12 ++-- src/Sample/Pages/TodoItemForm.cshtml | 19 ++++-- src/Sample/Pages/Todos.cshtml | 24 ++++--- src/Sample/Program.cs | 20 ++---- src/Sample/Sample.csproj | 29 ++------ src/Sample/Startup.cs | 25 +++++++ src/Sample/global.json | 2 +- src/Sample/wwwroot/index.html | 7 +- 31 files changed, 318 insertions(+), 232 deletions(-) create mode 100644 src/BlazorDB/Storage/StringExtensions.cs create mode 100644 src/FluxorIntegration/Pete/IServiceCollectionExtensions.cs create mode 100644 src/FluxorIntegration/PeteConsumer/MovieDbState.cs create mode 100644 src/FluxorIntegration/Startup.cs create mode 100644 src/Sample/Startup.cs diff --git a/BlazorDB.sln b/BlazorDB.sln index 0cc1e22..c1899b9 100644 --- a/BlazorDB.sln +++ b/BlazorDB.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorDB", "src\BlazorDB\Bl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "src\Sample\Sample.csproj", "{DAABB1BD-F735-4AB8-8ECF-70E00048175B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluxorIntegration", "src\FluxorIntegration\FluxorIntegration.csproj", "{9C42034D-6331-4623-B178-7417F9AB1345}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -23,10 +21,6 @@ Global {DAABB1BD-F735-4AB8-8ECF-70E00048175B}.Debug|Any CPU.Build.0 = Debug|Any CPU {DAABB1BD-F735-4AB8-8ECF-70E00048175B}.Release|Any CPU.ActiveCfg = Release|Any CPU {DAABB1BD-F735-4AB8-8ECF-70E00048175B}.Release|Any CPU.Build.0 = Release|Any CPU - {9C42034D-6331-4623-B178-7417F9AB1345}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C42034D-6331-4623-B178-7417F9AB1345}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C42034D-6331-4623-B178-7417F9AB1345}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C42034D-6331-4623-B178-7417F9AB1345}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 861ba7b..e233c12 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,22 @@ In memory, persisted to localstorage, database for .net Blazor browser framework ## Warning This library like Blazor itself is experimental and API is likely to change. +## Breaking change as of V0.7.0 + +At this time, you will need to initialize the `Context` prior to using it. I hope that I cna get this done automatically again in a future version: + +``` +protected async override Task OnInitAsync() +{ + await Context.Initialize(); +} +``` + +## Note about the sample project + +The Todo page does not work fully. The TodoForm that allows you to edit an item or add a new item is not working correctly. The OnInitAsync in the +child component is not firing. However, since BlazorDB itself it working, I decided to publish the version and figure out the Sample app afterwards. + ## Docs ### Install @@ -67,6 +83,15 @@ Inject your context into your component: @inject Context Context ``` +Currently, as of v0.7.0, before using the `Context` object you must initialize it. Hopefully, this requirement will go away in a future version: + +``` +protected async override Task OnInitAsync() +{ + await Context.Initialize(); +} +``` + Create a model and add it to your Context: ``` diff --git a/src/BlazorDB/BlazorDB.csproj b/src/BlazorDB/BlazorDB.csproj index 5be6cc9..01a1673 100644 --- a/src/BlazorDB/BlazorDB.csproj +++ b/src/BlazorDB/BlazorDB.csproj @@ -7,7 +7,7 @@ false 7.3 BlazorDB - 0.2.0 + 0.7.0 Chanan Braunstein Blazor localStorage Database In memory, persisted to localstorage, database for .net Blazor browser framework @@ -23,9 +23,9 @@ - - - + + + diff --git a/src/BlazorDB/IStorageContext.cs b/src/BlazorDB/IStorageContext.cs index 94952ea..9f47464 100644 --- a/src/BlazorDB/IStorageContext.cs +++ b/src/BlazorDB/IStorageContext.cs @@ -1,8 +1,10 @@ -namespace BlazorDB +using System.Threading.Tasks; + +namespace BlazorDB { public interface IStorageContext { - int SaveChanges(); - void LogToConsole(); + Task SaveChanges(); + Task LogToConsole(); } } diff --git a/src/BlazorDB/ServiceCollectionExtensions.cs b/src/BlazorDB/ServiceCollectionExtensions.cs index 75cec8a..829b68b 100644 --- a/src/BlazorDB/ServiceCollectionExtensions.cs +++ b/src/BlazorDB/ServiceCollectionExtensions.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; +using Microsoft.JSInterop; namespace BlazorDB { @@ -26,14 +28,19 @@ public static IServiceCollection AddBlazorDB(this IServiceCollection serviceColl private static void Scan(IServiceCollection serviceCollection, Assembly assembly) { var types = ScanForContexts(serviceCollection, assembly); - RegisterBlazorDb(serviceCollection, types); - } - - private static void RegisterBlazorDb(IServiceCollection serviceCollection, IEnumerable types) - { serviceCollection.AddSingleton(StorageManager); - foreach (var contextType in types) - StorageManager.LoadContextFromStorageOrCreateNew(serviceCollection, contextType); + + foreach (var type in types) + { + serviceCollection.AddSingleton(type, s => + { + var jsRuntime = s.GetRequiredService(); + var instance = Activator.CreateInstance(type); + var smProp = type.GetProperty("StorageManager", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + smProp.SetValue(instance, StorageManager); + return instance; + }); + } } private static IEnumerable ScanForContexts(IServiceCollection serviceCollection, Assembly assembly) diff --git a/src/BlazorDB/Storage/IStorageManager.cs b/src/BlazorDB/Storage/IStorageManager.cs index 61e4395..7bf3860 100644 --- a/src/BlazorDB/Storage/IStorageManager.cs +++ b/src/BlazorDB/Storage/IStorageManager.cs @@ -1,11 +1,11 @@ -using Microsoft.Extensions.DependencyInjection; -using System; +using System; +using System.Threading.Tasks; namespace BlazorDB.Storage { public interface IStorageManager { - int SaveContextToLocalStorage(StorageContext context); - void LoadContextFromStorageOrCreateNew(IServiceCollection serviceCollection, Type contextType); + Task SaveContextToLocalStorage(StorageContext context); + Task LoadContextFromLocalStorage(StorageContext context); } } diff --git a/src/BlazorDB/Storage/Logger.cs b/src/BlazorDB/Storage/Logger.cs index f00320d..adf2d82 100644 --- a/src/BlazorDB/Storage/Logger.cs +++ b/src/BlazorDB/Storage/Logger.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace BlazorDB.Storage { @@ -10,23 +11,23 @@ internal static class Logger private const string Normal = "color: black; font-style: normal;"; internal static bool LogDebug { get; set; } = true; - internal static void LogStorageSetToConsole(Type type, object list) + internal async static Task LogStorageSetToConsole(Type type, object list) { if (!LogDebug) return; - BlazorLogger.Logger.Log($"StorageSet<{type.GetGenericArguments()[0].Name}>: %o", list); + await BlazorLogger.Logger.Log($"StorageSet<{type.GetGenericArguments()[0].Name}>: %o", list); } - internal static void StartContextType(Type contextType, bool loading = true) + internal async static Task StartContextType(Type contextType, bool loading = true) { if (!LogDebug) return; - var message = loading ? " loading" : " log"; - BlazorLogger.Logger.GroupCollapsed($"Context{message}: %c{contextType.Namespace}.{contextType.Name}", Blue); + var message = loading ? "loading" : "log"; + await BlazorLogger.Logger.GroupCollapsed($"Context {message}: %c{contextType.Namespace}.{contextType.Name}", Blue); } - internal static void ContextSaved(Type contextType) + internal async static Task ContextSaved(Type contextType) { if (!LogDebug) return; - BlazorLogger.Logger.GroupCollapsed($"Context %csaved: %c{contextType.Namespace}.{contextType.Name}", Green, + await BlazorLogger.Logger.GroupCollapsed($"Context %csaved: %c{contextType.Namespace}.{contextType.Name}", Green, Blue); } diff --git a/src/BlazorDB/Storage/StorageManager.cs b/src/BlazorDB/Storage/StorageManager.cs index 58678c8..f4e62ef 100644 --- a/src/BlazorDB/Storage/StorageManager.cs +++ b/src/BlazorDB/Storage/StorageManager.cs @@ -1,5 +1,5 @@ using System; -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; namespace BlazorDB.Storage { @@ -8,14 +8,14 @@ internal class StorageManager : IStorageManager private readonly StorageManagerLoad _storageManagerLoad = new StorageManagerLoad(); private readonly StorageManagerSave _storageManagerSave = new StorageManagerSave(); - public int SaveContextToLocalStorage(StorageContext context) + public Task SaveContextToLocalStorage(StorageContext context) { return _storageManagerSave.SaveContextToLocalStorage(context); } - public void LoadContextFromStorageOrCreateNew(IServiceCollection serviceCollection, Type contextType) + public Task LoadContextFromLocalStorage(StorageContext context) { - _storageManagerLoad.LoadContextFromStorageOrCreateNew(serviceCollection, contextType); + return _storageManagerLoad.LoadContextFromLocalStorage(context); } } } \ No newline at end of file diff --git a/src/BlazorDB/Storage/StorageManagerLoad.cs b/src/BlazorDB/Storage/StorageManagerLoad.cs index 4a19ae9..0ebf2b1 100644 --- a/src/BlazorDB/Storage/StorageManagerLoad.cs +++ b/src/BlazorDB/Storage/StorageManagerLoad.cs @@ -3,32 +3,31 @@ using System.Linq; using System.Reflection; using System.Text; -using Microsoft.AspNetCore.Blazor; -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.JSInterop; namespace BlazorDB.Storage { internal class StorageManagerLoad { - public void LoadContextFromStorageOrCreateNew(IServiceCollection serviceCollection, Type contextType) + public async Task LoadContextFromLocalStorage(StorageContext context) { - Logger.StartContextType(contextType); + var contextType = context.GetType(); + await Logger.StartContextType(contextType); var storageSets = StorageManagerUtil.GetStorageSets(contextType); - var stringModels = LoadStringModels(contextType, storageSets); + var stringModels = await LoadStringModels(contextType, storageSets); //PrintStringModels(stringModels); stringModels = ScanNonAssociationModels(storageSets, stringModels); stringModels = ScanAssociationModels(storageSets, stringModels); stringModels = DeserializeModels(stringModels, storageSets); //PrintStringModels(stringModels); - var context = CreateContext(contextType, stringModels); - RegisterContext(serviceCollection, contextType, context); + await EnrichContext(context, contextType, stringModels); Logger.EndGroup(); } - private static object CreateContext(Type contextType, + private static async Task EnrichContext(StorageContext context, Type contextType, IReadOnlyDictionary> stringModels) { - var context = Activator.CreateInstance(contextType); foreach (var prop in contextType.GetProperties()) if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(StorageSet<>)) @@ -36,7 +35,7 @@ private static object CreateContext(Type contextType, var modelType = prop.PropertyType.GetGenericArguments()[0]; var storageSetType = StorageManagerUtil.GenericStorageSetType.MakeGenericType(modelType); var storageTableName = Util.GetStorageTableName(contextType, modelType); - var metadata = StorageManagerUtil.LoadMetadata(storageTableName); + var metadata = await StorageManagerUtil.LoadMetadata(storageTableName); if (stringModels.ContainsKey(modelType)) { var map = stringModels[modelType]; @@ -46,14 +45,11 @@ private static object CreateContext(Type contextType, { Logger.LoadModelInContext(modelType, 0); } - var storageSet = metadata != null ? LoadStorageSet(storageSetType, contextType, modelType, stringModels[modelType]) : CreateNewStorageSet(storageSetType, contextType); prop.SetValue(context, storageSet); } - - return context; } private static Dictionary> DeserializeModels( @@ -251,7 +247,7 @@ private static string FixAssociationsInStringModels(SerializedModel stringModel, private static string ReplaceListWithAssociationList(string serializedModel, string propName, string strList) { - var propStart = serializedModel.IndexOf($"\"{propName}\":[", StringComparison.Ordinal); + var propStart = serializedModel.IndexOf($"\"{propName.ToCamelCase()}\":[", StringComparison.Ordinal); var start = serializedModel.IndexOf('[', propStart) + 1; var end = serializedModel.IndexOf(']', start); var result = StorageManagerUtil.ReplaceString(serializedModel, start, end, strList); @@ -262,13 +258,13 @@ private static bool TryGetIdListFromSerializedModel(string serializedModel, stri out List idList) { var list = new List(); - if (serializedModel.IndexOf($"\"{propName}\":null", StringComparison.Ordinal) != -1) + if (serializedModel.IndexOf($"\"{propName.ToCamelCase()}\":null", StringComparison.Ordinal) != -1) { idList = list; return false; } - var propStart = serializedModel.IndexOf($"\"{propName}\":[", StringComparison.Ordinal); + var propStart = serializedModel.IndexOf($"\"{propName.ToCamelCase()}\":[", StringComparison.Ordinal); var start = serializedModel.IndexOf('[', propStart) + 1; var end = serializedModel.IndexOf(']', start); var stringlist = serializedModel.Substring(start, end - start); @@ -297,7 +293,7 @@ private static bool IsScanDone(Dictionary return done; } - private static Dictionary> LoadStringModels(Type contextType, + private static async Task>> LoadStringModels(Type contextType, IEnumerable storageSets) { var stringModels = new Dictionary>(); @@ -306,12 +302,12 @@ private static Dictionary> LoadStringMode var modelType = prop.PropertyType.GetGenericArguments()[0]; var map = new Dictionary(); var storageTableName = Util.GetStorageTableName(contextType, modelType); - var metadata = StorageManagerUtil.LoadMetadata(storageTableName); + var metadata = await StorageManagerUtil.LoadMetadata(storageTableName); if (metadata == null) continue; foreach (var guid in metadata.Guids) { var name = $"{storageTableName}-{guid}"; - var serializedModel = BlazorDBInterop.GetItem(name, false); + var serializedModel = await BlazorDBInterop.GetItem(name, false); var id = FindIdInSerializedModel(serializedModel); map.Add(id, new SerializedModel {StringModel = serializedModel}); } @@ -325,13 +321,13 @@ private static Dictionary> LoadStringMode //TODO: Verify that the found id is at the top level in case of nested objects private static bool TryGetIdFromSerializedModel(string serializedModel, string propName, out int id) { - if (serializedModel.IndexOf($"\"{propName}\":null", StringComparison.Ordinal) != -1) + if (serializedModel.IndexOf($"\"{propName.ToCamelCase()}\":null", StringComparison.Ordinal) != -1) { id = -1; return false; } - var propStart = serializedModel.IndexOf($"\"{propName}\":", StringComparison.Ordinal); + var propStart = serializedModel.IndexOf($"\"{propName.ToCamelCase()}\":", StringComparison.Ordinal); var start = serializedModel.IndexOf(':', propStart); id = GetIdFromString(serializedModel, start); return true; @@ -340,7 +336,7 @@ private static bool TryGetIdFromSerializedModel(string serializedModel, string p //TODO: Verify that the found id is at the top level in case of nested objects private static int FindIdInSerializedModel(string serializedModel) { - var start = serializedModel.IndexOf($"\"{StorageManagerUtil.Id}\":", StringComparison.Ordinal); + var start = serializedModel.IndexOf($"\"{StorageManagerUtil.Id.ToCamelCase()}\":", StringComparison.Ordinal); return GetIdFromString(serializedModel, start); } @@ -368,7 +364,7 @@ private static int GetIdFromString(string stringToSearch, int startFrom = 0) private static string ReplaceIdWithAssociation(string result, string name, int id, string stringModel) { - var stringToFind = $"\"{name}\":{id}"; + var stringToFind = $"\"{name.ToCamelCase()}\":{id}"; var nameIndex = result.IndexOf(stringToFind, StringComparison.Ordinal); var index = result.IndexOf(id.ToString(), nameIndex, StringComparison.Ordinal); result = StorageManagerUtil.ReplaceString(result, index, index + id.ToString().Length, stringModel); @@ -398,20 +394,13 @@ private static object DeserializeModel(Type modelType, string value) var model = genericMethod.Invoke(new JsonWrapper(), new object[] {value}); return model; } - - private static void RegisterContext(IServiceCollection serviceCollection, Type type, object context) - { - serviceCollection.AddSingleton( - type, - context); - } } internal class JsonWrapper { public T Deserialize(string value) { - return JsonUtil.Deserialize(value); + return Json.Deserialize(value); } } } \ No newline at end of file diff --git a/src/BlazorDB/Storage/StorageManagerSave.cs b/src/BlazorDB/Storage/StorageManagerSave.cs index 25247d8..7ce51c7 100644 --- a/src/BlazorDB/Storage/StorageManagerSave.cs +++ b/src/BlazorDB/Storage/StorageManagerSave.cs @@ -3,29 +3,30 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using BlazorDB.DataAnnotations; -using Microsoft.AspNetCore.Blazor; +using Microsoft.JSInterop; namespace BlazorDB.Storage { internal class StorageManagerSave { - public int SaveContextToLocalStorage(StorageContext context) + public async Task SaveContextToLocalStorage(StorageContext context) { var total = 0; var contextType = context.GetType(); - Logger.ContextSaved(contextType); + await Logger.ContextSaved(contextType); var storageSets = StorageManagerUtil.GetStorageSets(contextType); var error = ValidateModels(context, storageSets); if (error == null) { - var metadataMap = LoadMetadataList(context, storageSets, contextType); - total = SaveStorageSets(context, total, contextType, storageSets, metadataMap); + var metadataMap = await LoadMetadataList(context, storageSets, contextType); + total = await SaveStorageSets(context, total, contextType, storageSets, metadataMap); Logger.EndGroup(); } else { - BlazorLogger.Logger.Error("SaveChanges() terminated due to validation error"); + await BlazorLogger.Logger.Error("SaveChanges() terminated due to validation error"); Logger.EndGroup(); throw new BlazorDBUpdateException(error); } @@ -83,7 +84,7 @@ private string ValidateModels(StorageContext context, IEnumerable return error; } - private static IReadOnlyDictionary LoadMetadataList(StorageContext context, + private static async Task> LoadMetadataList(StorageContext context, IEnumerable storageSets, Type contextType) { var map = new Dictionary(); @@ -91,7 +92,7 @@ private static IReadOnlyDictionary LoadMetadataList(StorageCon { var modelType = prop.PropertyType.GetGenericArguments()[0]; var storageTableName = Util.GetStorageTableName(contextType, modelType); - var metadata = StorageManagerUtil.LoadMetadata(storageTableName) ?? new Metadata + var metadata = await StorageManagerUtil.LoadMetadata(storageTableName) ?? new Metadata { Guids = new List(), ContextName = Util.GetFullyQualifiedTypeName(context.GetType()), @@ -103,7 +104,7 @@ private static IReadOnlyDictionary LoadMetadataList(StorageCon return map; } - private static int SaveStorageSets(StorageContext context, int total, Type contextType, + private static async Task SaveStorageSets(StorageContext context, int total, Type contextType, List storageSets, IReadOnlyDictionary metadataMap) { foreach (var prop in storageSets) @@ -115,7 +116,7 @@ private static int SaveStorageSets(StorageContext context, int total, Type conte EnsureAllModelsHaveIds(storageSetValue, modelType, metadataMap); EnsureAllAssociationsHaveIds(context, storageSetValue, modelType, storageSets, metadataMap); - var guids = SaveModels(storageSetValue, modelType, storageTableName, storageSets); + var guids = await SaveModels(storageSetValue, modelType, storageTableName, storageSets); total += guids.Count; var oldMetadata = metadataMap[Util.GetFullyQualifiedTypeName(modelType)]; SaveMetadata(storageTableName, guids, contextType, modelType, oldMetadata); @@ -220,7 +221,7 @@ private static void EnsureAllModelsHaveIds(object storageSetValue, Type modelTyp } } - private static void SaveMetadata(string storageTableName, List guids, Type context, Type modelType, + private static async void SaveMetadata(string storageTableName, List guids, Type context, Type modelType, Metadata oldMetadata) { var metadata = new Metadata @@ -231,10 +232,10 @@ private static void SaveMetadata(string storageTableName, List guids, Type MaxId = oldMetadata.MaxId }; var name = $"{storageTableName}-{StorageManagerUtil.Metadata}"; - BlazorDBInterop.SetItem(name, JsonUtil.Serialize(metadata), false); + await BlazorDBInterop.SetItem(name, Json.Serialize(metadata), false); } - private static List SaveModels(object storageSetValue, Type modelType, string storageTableName, + private static async Task> SaveModels(object storageSetValue, Type modelType, string storageTableName, List storageSets) { var guids = new List(); @@ -247,8 +248,8 @@ private static List SaveModels(object storageSetValue, Type modelType, str guids.Add(guid); var model = enumerator.Current; var name = $"{storageTableName}-{guid}"; - var serializedModel = ScanModelForAssociations(model, storageSets, JsonUtil.Serialize(model)); - BlazorDBInterop.SetItem(name, serializedModel, false); + var serializedModel = ScanModelForAssociations(model, storageSets, Json.Serialize(model)); + await BlazorDBInterop.SetItem(name, serializedModel, false); } return guids; @@ -286,7 +287,7 @@ private static string FixManyAssociation(object model, PropertyInfo prop, string { var idProp = GetIdProperty(item); var id = Convert.ToString(idProp.GetValue(item)); - var serializedItem = JsonUtil.Serialize(item); + var serializedItem = Json.Serialize(item); result = ReplaceModelWithId(result, serializedItem, id); } @@ -298,7 +299,7 @@ private static string FixOneAssociation(object model, PropertyInfo prop, string var associatedModel = prop.GetValue(model); var idProp = GetIdProperty(associatedModel); var id = Convert.ToString(idProp.GetValue(associatedModel)); - var serializedItem = JsonUtil.Serialize(associatedModel); + var serializedItem = Json.Serialize(associatedModel); result = ReplaceModelWithId(result, serializedItem, id); return result; } diff --git a/src/BlazorDB/Storage/StorageManagerUtil.cs b/src/BlazorDB/Storage/StorageManagerUtil.cs index 079a5e4..0a83e03 100644 --- a/src/BlazorDB/Storage/StorageManagerUtil.cs +++ b/src/BlazorDB/Storage/StorageManagerUtil.cs @@ -1,8 +1,9 @@ -using Microsoft.AspNetCore.Blazor; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Threading.Tasks; +using Microsoft.JSInterop; namespace BlazorDB.Storage { @@ -18,6 +19,7 @@ internal static class StorageManagerUtil internal const string List = "List"; internal static readonly Type GenericStorageSetType = typeof(StorageSet<>); internal static readonly Type GenericListType = typeof(List<>); + internal const string JsonId = "id"; internal static List GetStorageSets(Type contextType) { @@ -27,11 +29,11 @@ where prop.PropertyType.IsGenericType && select prop).ToList(); } - internal static Metadata LoadMetadata(string storageTableName) + internal static async Task LoadMetadata(string storageTableName) { var name = $"{storageTableName}-{Metadata}"; - var value = BlazorDBInterop.GetItem(name, false); - return value != null ? JsonUtil.Deserialize(value) : null; + var value = await BlazorDBInterop.GetItem(name, false); + return value != null ? Json.Deserialize(value) : null; } internal static string ReplaceString(string source, int start, int end, string stringToInsert) diff --git a/src/BlazorDB/Storage/StringExtensions.cs b/src/BlazorDB/Storage/StringExtensions.cs new file mode 100644 index 0000000..a985200 --- /dev/null +++ b/src/BlazorDB/Storage/StringExtensions.cs @@ -0,0 +1,10 @@ +namespace BlazorDB.Storage +{ + public static class StringExtensions + { + public static string ToCamelCase(this string str) + { + return char.ToLowerInvariant(str[0]) + str.Substring(1); + } + } +} diff --git a/src/BlazorDB/Storage/blazorDBInterop.cs b/src/BlazorDB/Storage/blazorDBInterop.cs index d6ac338..20e16c3 100644 --- a/src/BlazorDB/Storage/blazorDBInterop.cs +++ b/src/BlazorDB/Storage/blazorDBInterop.cs @@ -1,28 +1,35 @@ using System; -using Microsoft.AspNetCore.Blazor.Browser.Interop; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.JSInterop; -namespace BlazorDB +namespace BlazorDB.Storage { internal class BlazorDBInterop { - public static bool SetItem(string key, string value, bool session) + public static Task SetItem(string key, string value, bool session) { - return RegisteredFunction.Invoke("BlazorDB.blazorDBInterop.SetItem", key, value, session); + return JSRuntime.Current.InvokeAsync("blazorDBInterop.setItem", key, value, session); } - public static string GetItem(string key, bool session) + public static Task GetItem(string key, bool session) { - return RegisteredFunction.Invoke("BlazorDB.blazorDBInterop.GetItem", key, session); + return JSRuntime.Current.InvokeAsync("blazorDBInterop.getItem", key, session); } - public static bool RemoveItem(string key, bool session) + public static Task RemoveItem(string key, bool session) { - return RegisteredFunction.Invoke("BlazorDB.blazorDBInterop.RemoveItem", key, session); + return JSRuntime.Current.InvokeAsync("blazorDBInterop.removeItem", key, session); } - public static bool Clear(bool session) + public static Task Clear(bool session) { - return RegisteredFunction.Invoke("BlazorDB.blazorDBInterop.Clear", session); + return JSRuntime.Current.InvokeAsync("blazorDBInterop.clear", session); + } + public static Task Log(params object[] list) + { + var _list = new List(list); //This line is needed see: https://github.com/aspnet/Blazor/issues/740 + return JSRuntime.Current.InvokeAsync("blazorDBInterop.logs"); } } } diff --git a/src/BlazorDB/StorageContext.cs b/src/BlazorDB/StorageContext.cs index a599bc0..52b31f4 100644 --- a/src/BlazorDB/StorageContext.cs +++ b/src/BlazorDB/StorageContext.cs @@ -1,14 +1,14 @@ -using BlazorDB.Storage; +using System.Threading.Tasks; +using BlazorDB.Storage; namespace BlazorDB { public class StorageContext : IStorageContext { - private IStorageManager StorageManager { get; set; } = new StorageManager(); // Dep injection not working right now - - public void LogToConsole() + protected IStorageManager StorageManager { get; set; } + public async Task LogToConsole() { - Logger.StartContextType(GetType(), false); + await Logger.StartContextType(GetType(), false); var storageSets = StorageManagerUtil.GetStorageSets(GetType()); foreach (var prop in storageSets) { @@ -19,9 +19,14 @@ public void LogToConsole() Logger.EndGroup(); } - public int SaveChanges() + public Task SaveChanges() { return StorageManager.SaveContextToLocalStorage(this); } + + public Task Initialize() + { + return StorageManager.LoadContextFromLocalStorage(this); + } } } \ No newline at end of file diff --git a/src/BlazorDB/StorageSet.cs b/src/BlazorDB/StorageSet.cs index 2dfc757..542eb0c 100644 --- a/src/BlazorDB/StorageSet.cs +++ b/src/BlazorDB/StorageSet.cs @@ -10,9 +10,9 @@ public class StorageSet : IList where TModel : class private string StorageContextTypeName { get; set; } private IList List { get; set; } = new List(); - public void LogToConsole() + public async void LogToConsole() { - Logger.LogStorageSetToConsole(GetType(), List); + await Logger.LogStorageSetToConsole(GetType(), List); } public TModel this[int index] diff --git a/src/BlazorDB/content/blazorDBInterop.js b/src/BlazorDB/content/blazorDBInterop.js index 43e4f90..5f8c277 100644 --- a/src/BlazorDB/content/blazorDBInterop.js +++ b/src/BlazorDB/content/blazorDBInterop.js @@ -1,36 +1,33 @@ -Blazor.registerFunction('BlazorDB.blazorDBInterop.SetItem', function (key, value, session) { - if (session) { - sessionStorage.setItem(key, value); - } else { - localStorage.setItem(key, value); +window.blazorDBInterop = { + setItem: function(key, value, session) { + if (session) { + sessionStorage.setItem(key, value); + } else { + localStorage.setItem(key, value); + } + return true; + }, + getItem: function (key, session) { + if(session) { + return sessionStorage.getItem(key); + } else { + return localStorage.getItem(key); + } + }, + removeItem: function (key, session) { + if(session) { + sessionStorage.removeItem(key); + } else { + localStorage.removeItem(key); + } + return true; + }, + clear: function (session) { + if(session) { + sessionStorage.clear(); + } else { + localStorage.clear(); + } + return true; } - return true; -}); - -Blazor.registerFunction('BlazorDB.blazorDBInterop.GetItem', function (key, session) { - if (session) { - return sessionStorage.getItem(key); - } else { - return localStorage.getItem(key); - } -}); - -Blazor.registerFunction('BlazorDB.blazorDBInterop.RemoveItem', function (key, session) { - if (session) { - sessionStorage.removeItem(key); - } else { - localStorage.removeItem(key); - } - return true; -}); - - -Blazor.registerFunction('BlazorDB.blazorDBInterop.Clear', function (session) { - if (session) { - sessionStorage.clear(); - } else { - localStorage.clear(); - } - return true; -}); - +}; \ No newline at end of file diff --git a/src/FluxorIntegration/FluxorIntegration.csproj b/src/FluxorIntegration/FluxorIntegration.csproj index f1db2fa..41e4898 100644 --- a/src/FluxorIntegration/FluxorIntegration.csproj +++ b/src/FluxorIntegration/FluxorIntegration.csproj @@ -8,10 +8,10 @@ - - - - + + + + diff --git a/src/FluxorIntegration/Pete/IServiceCollectionExtensions.cs b/src/FluxorIntegration/Pete/IServiceCollectionExtensions.cs new file mode 100644 index 0000000..f8a3e81 --- /dev/null +++ b/src/FluxorIntegration/Pete/IServiceCollectionExtensions.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace FluxorIntegration.Pete +{ + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddBlazorFluxor(this IServiceCollection services) + where TContext: class, new() + { + var context = new TContext(); + services.AddSingleton(context); + return services; + } + } +} \ No newline at end of file diff --git a/src/FluxorIntegration/PeteConsumer/MovieDbState.cs b/src/FluxorIntegration/PeteConsumer/MovieDbState.cs new file mode 100644 index 0000000..e69de29 diff --git a/src/FluxorIntegration/Program.cs b/src/FluxorIntegration/Program.cs index 7296827..59ecff0 100644 --- a/src/FluxorIntegration/Program.cs +++ b/src/FluxorIntegration/Program.cs @@ -1,30 +1,16 @@ -using Microsoft.AspNetCore.Blazor.Browser.Rendering; -using Microsoft.AspNetCore.Blazor.Browser.Services; -using Blazor.Fluxor; -using BlazorDB; +using Microsoft.AspNetCore.Blazor.Hosting; namespace FluxorIntegration { public class Program { - static void Main(string[] args) + public static void Main(string[] args) { - var serviceProvider = new BrowserServiceProvider(services => - { - services.AddBlazorDB(options => - { - options.LogDebug = true; - options.Assembly = typeof(Program).Assembly; - }); - - services.AddFluxor(options => options - .UseDependencyInjection(typeof(Program).Assembly) - .AddMiddleware() - .AddMiddleware() - ); - }); - - new BrowserRenderer(serviceProvider).AddComponent("app"); + CreateHostBuilder(args).Build().Run(); } + + public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) => + BlazorWebAssemblyHost.CreateDefaultBuilder() + .UseBlazorStartup(); } } diff --git a/src/FluxorIntegration/Startup.cs b/src/FluxorIntegration/Startup.cs new file mode 100644 index 0000000..ff91b6f --- /dev/null +++ b/src/FluxorIntegration/Startup.cs @@ -0,0 +1,30 @@ +using Blazor.Fluxor; +using BlazorDB; +using Microsoft.AspNetCore.Blazor.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace FluxorIntegration +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddBlazorDB(options => + { + options.LogDebug = true; + options.Assembly = typeof(Program).Assembly; + }); + + services.AddFluxor(options => options + .UseDependencyInjection(typeof(Program).Assembly) + .AddMiddleware() + .AddMiddleware() + ); + } + + public void Configure(IBlazorApplicationBuilder app) + { + app.AddComponent("app"); + } + } +} diff --git a/src/FluxorIntegration/wwwroot/index.html b/src/FluxorIntegration/wwwroot/index.html index 9228821..2dafd86 100644 --- a/src/FluxorIntegration/wwwroot/index.html +++ b/src/FluxorIntegration/wwwroot/index.html @@ -9,8 +9,7 @@ - Loading... - - +Loading... + diff --git a/src/Sample/Pages/Associations.cshtml b/src/Sample/Pages/Associations.cshtml index 7f96bb0..64e08c6 100644 --- a/src/Sample/Pages/Associations.cshtml +++ b/src/Sample/Pages/Associations.cshtml @@ -45,6 +45,10 @@ @functions { Person _person; + protected async override Task OnInitAsync() + { + await Context.Initialize(); + } void OnAdd(UIMouseEventArgs e) { var person = new Person { FirstName = "John", LastName = "Smith" }; diff --git a/src/Sample/Pages/Index.cshtml b/src/Sample/Pages/Index.cshtml index 1df64a5..2872bd5 100644 --- a/src/Sample/Pages/Index.cshtml +++ b/src/Sample/Pages/Index.cshtml @@ -27,6 +27,10 @@ @functions { private Person Person { get; set; } + protected async override Task OnInitAsync() + { + await Context.Initialize(); + } void OnclickAddPerson() { //In this case, address gets serailized as part of the object because Address is not in the Context @@ -55,14 +59,14 @@ StateHasChanged(); } - void OnclickSaveChanges() + async void OnclickSaveChanges() { - Context.SaveChanges(); + await Context.SaveChanges(); } void OnRequired() { - var person = new Person {LastName = "Firstname required!"}; + var person = new Person { LastName = "Firstname required!" }; Context.People.Add(person); Context.SaveChanges(); } @@ -73,4 +77,4 @@ Context.People.Add(person); Context.SaveChanges(); } -} +} \ No newline at end of file diff --git a/src/Sample/Pages/TodoItemForm.cshtml b/src/Sample/Pages/TodoItemForm.cshtml index 7cd4696..76c6b36 100644 --- a/src/Sample/Pages/TodoItemForm.cshtml +++ b/src/Sample/Pages/TodoItemForm.cshtml @@ -31,8 +31,10 @@ TodoItem Todo { get; set; } = new TodoItem(); - protected override void OnInit() + protected async override Task OnInitAsync() { + Console.WriteLine("OnInitAsync"); + await Context.Initialize(); if (SelectedId == 0) Todo = new TodoItem(); else { @@ -40,13 +42,20 @@ } } - protected override void OnParametersSet() + protected async override Task OnParametersSetAsync() { + Console.WriteLine("OnParametersSetAsync"); + if (Context.Todos == null) + { + Console.WriteLine("OnParametersSetAsync - init"); + await Context.Initialize(); + } SetTodo(); } void SetTodo() { + if (Context.Todos == null) return; var query = from todo in Context.Todos where todo.Id == SelectedId select todo; @@ -54,13 +63,13 @@ Todo = item != null ? item : new TodoItem(); } - void onclick() + async void onclick() { - if(Todo.Id == 0) + if (Todo.Id == 0) { Context.Todos.Add(Todo); //add new todo to the context } - Context.SaveChanges(); + await Context.SaveChanges(); StateHasChanged(); NewTodoAdded(); } diff --git a/src/Sample/Pages/Todos.cshtml b/src/Sample/Pages/Todos.cshtml index ad32395..c408cc5 100644 --- a/src/Sample/Pages/Todos.cshtml +++ b/src/Sample/Pages/Todos.cshtml @@ -5,7 +5,7 @@
- +
@@ -17,7 +17,7 @@ { var color = todo.IsDone ? Color.Success : Color.Danger; - + @todo.IsDone @todo.Text @@ -26,31 +26,32 @@

Selected Item

- + @functions { string Filter { get; set; } - IList Filtered { get; set; } + List Filtered { get; set; } = new List(); int SelectedId { get; set; } = 1; - protected override void OnInit() + protected async override Task OnInitAsync() { - if(Context.Todos.Count == 0) + await Context.Initialize(); + if (Context.Todos.Count == 0) { //Insert some initial data - Context.Todos.Add(new TodoItem { IsDone = true, Text = "Create initial BlazorDB project" } ); + Context.Todos.Add(new TodoItem { IsDone = true, Text = "Create initial BlazorDB project" }); Context.Todos.Add(new TodoItem { IsDone = true, Text = "Make a todo app" }); Context.Todos.Add(new TodoItem { IsDone = false, Text = "Make BlazorDB really awesome!" }); - Context.SaveChanges(); + await Context.SaveChanges(); } - Filtered = Context.Todos; + Filtered = Context.Todos.ToList(); } void onFilter() { if(Filter == String.Empty) { - Filtered = Context.Todos; + Filtered = Context.Todos.ToList(); } else { @@ -61,8 +62,9 @@ } } - void onclick(int i) + void onClickItem(int i) { + Console.WriteLine("Todos onClickItem: {0}", i); SelectedId = i; StateHasChanged(); } diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 27f210e..f30da0f 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -1,22 +1,16 @@ -using BlazorDB; -using Microsoft.AspNetCore.Blazor.Browser.Rendering; -using Microsoft.AspNetCore.Blazor.Browser.Services; +using Microsoft.AspNetCore.Blazor.Hosting; namespace Sample { public class Program { - static void Main(string[] args) + public static void Main(string[] args) { - var serviceProvider = new BrowserServiceProvider(services => - { - services.AddBlazorDB(options => - { - options.LogDebug = true; - options.Assembly = typeof(Program).Assembly; - }); - }); - new BrowserRenderer(serviceProvider).AddComponent("app"); + CreateHostBuilder(args).Build().Run(); } + + public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) => + BlazorWebAssemblyHost.CreateDefaultBuilder() + .UseBlazorStartup(); } } diff --git a/src/Sample/Sample.csproj b/src/Sample/Sample.csproj index 3d991e2..5f78763 100644 --- a/src/Sample/Sample.csproj +++ b/src/Sample/Sample.csproj @@ -8,35 +8,14 @@ - - - - + + + + - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Sample/Startup.cs b/src/Sample/Startup.cs new file mode 100644 index 0000000..f1a3152 --- /dev/null +++ b/src/Sample/Startup.cs @@ -0,0 +1,25 @@ +using System; +using BlazorDB; +using Microsoft.AspNetCore.Blazor.Builder; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.JSInterop; + +namespace Sample +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddBlazorDB(options => + { + options.LogDebug = true; + options.Assembly = typeof(Program).Assembly; + }); + } + + public void Configure(IBlazorApplicationBuilder app) + { + app.AddComponent("app"); + } + } +} diff --git a/src/Sample/global.json b/src/Sample/global.json index d65e3d5..6cb33ce 100644 --- a/src/Sample/global.json +++ b/src/Sample/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.1.300" + "version": "2.2.100" } } diff --git a/src/Sample/wwwroot/index.html b/src/Sample/wwwroot/index.html index 47fe905..8bddcf8 100644 --- a/src/Sample/wwwroot/index.html +++ b/src/Sample/wwwroot/index.html @@ -9,8 +9,7 @@ - Loading... - - +Loading... + - + \ No newline at end of file