master - .Net5 version
master_net31 - 3.x version
This is a Blazor library to work with IndexedDB DOM API. It allows query multiple IndexedDb databases simultaneously
The actual API expose the following methods:
- Open and upgrade an instance of IndexedDB
- Close an instance of IndexedDB
- Delete an instance of IndexedDB
- Add an item to a given store
- Update an item in a given store
- Delete an item from a store by key
- Delete all items from a store
- Retrieve all items from a given store
- Retrieve an items by index
- Retrieve a range of items by key
- Retrieve a range of items by index
Compatibility *Server-side Blazor and client-side Blazor
- Install the Nuget package DnetIndexedDb
- Add the following script reference to your Index.html after the blazor.webassembly.js reference:
<script src="_content/DnetIndexedDb/rxjs.min.js"></script>
<script src="_content/DnetIndexedDb/dnet-indexeddb.js"></script>
- create a new instance of
IndexedDbDatabaseModel
- Create a derive class from
IndexedDbInterop
public class GridColumnDataIndexedDb : IndexedDbInterop
{
public GridColumnDataIndexedDb(IJSRuntime jsRuntime, IndexedDbOptions<GridColumnDataIndexedDb> options)
:base(jsRuntime, options)
{
}
}
- Register your derive class in
ConfiguredServices
onStartup.cs
. When register use options to add the IndexedDbDatabaseModel instance.
services.AddIndexedDbDatabase<GridColumnDataIndexedDb>(options =>
{
options.UseDatabase(GetGridColumnDatabaseModel());
});
- Inject the created instance of your derived class into the component or page.
To create the database model use the following classes. You can find more info about the IndexedDB database here: https://www.w3.org/TR/IndexedDB-2/#database-construct
IndexedDbDatabase
IndexedDbDatabaseModel
IndexedDbIndex
IndexedDbStore
IndexedDbStoreParameter
See the example below
public class IndexedDbDatabaseModel
{
public string Name { get; set; }
public int Version { get; set; }
public List<IndexedDbStore> Stores { get; set; } = new List<IndexedDbStore>();
public int DbModelId { get; set; }
}
var indexedDbDatabaseModel = new IndexedDbDatabaseModel
{
Name = "GridColumnData",
Version = 1,
Stores = new List<IndexedDbStore>
{
new IndexedDbStore
{
Name = "tableField",
Key = new IndexedDbStoreParameter
{
KeyPath = "tableFieldId",
AutoIncrement = true
},
Indexes = new List<IndexedDbIndex>
{
new IndexedDbIndex
{
Name = "tableFieldId",
Definition = new IndexedDbIndexParameter
{
Unique = true
}
},
new IndexedDbIndex
{
Name = "attachedProperty",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "fieldVisualName",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
}, new IndexedDbIndex
{
Name = "hide",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "isLink",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "memberOf",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "tableName",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "textAlignClass",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "type",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
},
new IndexedDbIndex
{
Name = "width",
Definition = new IndexedDbIndexParameter
{
Unique = false
}
}
}
}
},
DbModelId = 0
};
Create database model by @Kylar182
public class TableFieldDatabase : IndexedDbDatabaseModel
{
public TableFieldDatabase()
{
Name = "GridColumnData";
Version = 1;
Stores = _stores;
}
/// <summary>
/// List of Object Stores
/// </summary>
private List<IndexedDbStore> _stores => new List<IndexedDbStore>
{
_tableFieldStore,
};
private IndexedDbStore _tableFieldStore => new TStore<TableFieldDto>();
}
public class TStore<T> : IndexedDbStore where T : class
{
private IndexedDbStoreParameter _key;
private readonly List<IndexedDbIndex> _indexes = new List<IndexedDbIndex>();
public TStore()
{
BuildStore();
Name = typeof(T).Name.ToPlural();
Key = _key;
Indexes = _indexes;
}
private void BuildStore()
{
foreach (PropertyInfo info in typeof(T).GetProperties())
{
var classId = info.Name.Substring(info.Name.Length - 2);
var classAttrs = info.GetCustomAttributes(true);
var keyAttr = classAttrs.Select(p => p as KeyAttribute).FirstOrDefault();
if (classId == "Id" || keyAttr != null)
{
_key = new IndexedDbStoreParameter
{
KeyPath = info.Name.ToCamelCase(),
AutoIncrement = true
};
}
_indexes.Add(new IndexedDbIndex
{
Name = info.Name.ToCamelCase(),
Definition = new IndexedDbIndexParameter { Unique = false }
});
}
}
}
You can create a service for any indexedDB's database that you want to use in your application. Use the base class IndexedDbInterop
to create your derived class. See code below.
public class GridColumnDataIndexedDb : IndexedDbInterop
{
public GridColumnDataIndexedDb(IJSRuntime jsRuntime, IndexedDbOptions<GridColumnDataIndexedDb> options)
:base(jsRuntime, options)
{
}
}
This follows a similar pattern to what you do when you create a new DbContext in EF core.
You can use the AddIndexedDbDatabase
extension method to register your service in ConfiguredServices
on Startup.cs
. Use the options
builder to add the service Database. See code below.
services.AddIndexedDbDatabase<GridColumnDataIndexedDb>(options =>
{
options.UseDatabase(GetGridColumnDatabaseModel());
});
GetGridColumnDatabaseModel()
return an instance of IndexedDbDatabaseModel
You can also use multiple database, declaring as many service as you want.
services.AddIndexedDbDatabase<SecuritySuiteDataIndexedDb>(options =>
{
options.UseDatabase(GetSecurityDatabaseModel());
});
To use IndexedDB service in a component or page first inject the IndexedDB servicer instance.
@inject GridColumnDataIndexedDb GridColumnDataIndexedDb
IndexedDB store are the equivalent of table in SQL Database. For the API demostrations will use the following class as our store model.
public class TableFieldDto
{
public int TableFieldId { get; set; }
public string TableName { get; set; }
public string FieldVisualName { get; set; }
public string AttachedProperty { get; set; }
public bool IsLink { get; set; }
public int MemberOf { get; set; }
public int Width { get; set; }
public string TextAlignClass { get; set; }
public bool Hide { get; set; }
public string Type { get; set; }
}
ValueTask<int> OpenIndexedDb()
var result = await GridColumnDataIndexedDb.OpenIndexedDb();
ValueTask<TEntity> AddItems<TEntity>(string objectStoreName, List<TEntity> items)
var result = await GridColumnDataIndexedDb.AddItems<TableFieldDto>("tableField", items);
ValueTask<TEntity> GetByKey<TKey, TEntity>(string objectStoreName, TKey key)
var result = await GridColumnDataIndexedDb.GetByKey<int, TableFieldDto>("tableField", 11);
ValueTask<string> DeleteByKey<TKey>(string objectStoreName, TKey key)
var result = await GridColumnDataIndexedDb.DeleteByKey<int>("tableField", 11);
ValueTask<List<TEntity>> GetAll<TEntity>(string objectStoreName)
var result = await GridColumnDataIndexedDb.GetAll<TableFieldDto>("tableField");
ValueTask<List<TEntity>> GetRange<TKey, TEntity>(string objectStoreName, TKey lowerBound, TKey upperBound)
var result = await GridColumnDataIndexedDb.GetRange<int, TableFieldDto>("tableField", 15, 20);
ValueTask<List<TEntity>> GetByIndex<TKey, TEntity>(string objectStoreName, TKey lowerBound, TKey upperBound, string dbIndex, bool isRange)
var result = await GridColumnDataIndexedDb.GetByIndex<string, TableFieldDto>("tableField", "Name", null, "fieldVisualName", false);
ValueTask<string> UpdateItems<TEntity>(string objectStoreName, List<TEntity> items)
foreach (var item in items)
{
item.FieldVisualName = item.FieldVisualName + "Updated";
}
var result = await GridColumnDataIndexedDb.UpdateItems<TableFieldDto>("tableField", items);
ValueTask<string> DeleteAll(string objectStoreName)
var result = await GridColumnDataIndexedDb.DeleteAll("tableField");
ValueTask<string> DeleteIndexedDb()
var result = await GridColumnDataIndexedDb.DeleteIndexedDb();