{"id":37044288,"url":"https://github.com/augustocb23/json-stores","last_synced_at":"2026-01-14T05:06:51.446Z","repository":{"id":48380639,"uuid":"347208322","full_name":"augustocb23/json-stores","owner":"augustocb23","description":"Persist your data on JSON files in an easy and flexible way","archived":false,"fork":false,"pushed_at":"2022-08-31T00:31:09.000Z","size":92,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-28T23:16:33.515Z","etag":null,"topics":["json","repository","store"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/augustocb23.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-03-12T21:59:42.000Z","updated_at":"2022-11-29T17:36:06.000Z","dependencies_parsed_at":"2023-01-16T17:00:18.495Z","dependency_job_id":null,"html_url":"https://github.com/augustocb23/json-stores","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/augustocb23/json-stores","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/augustocb23%2Fjson-stores","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/augustocb23%2Fjson-stores/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/augustocb23%2Fjson-stores/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/augustocb23%2Fjson-stores/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/augustocb23","download_url":"https://codeload.github.com/augustocb23/json-stores/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/augustocb23%2Fjson-stores/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28410188,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","repository","store"],"created_at":"2026-01-14T05:06:50.734Z","updated_at":"2026-01-14T05:06:51.441Z","avatar_url":"https://github.com/augustocb23.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# JsonStores\n\n[![GitHub](https://img.shields.io/github/license/augustocb23/json-stores)](LICENSE) [![Nuget](https://img.shields.io/nuget/v/JsonStores)](https://www.nuget.org/packages/JsonStores) [![Nuget](https://img.shields.io/nuget/dt/JsonStores)](https://www.nuget.org/packages/JsonStores) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/augustocb23/json-stores/.NET)](https://github.com/augustocb23/json-stores/actions/workflows/dotnet.yml)\n\nPersist your data on JSON files in an easy and flexible way\n\n- Create stores (containing a single object) or repositories (containing a collection of items)\n- Thread-safe overloads ([see docs](#Concurrent-stores))\n- Developed on top of [System.Text.Json](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-overview) and compatible with `netstandard2.1`\n\n## Getting started\n\nInstall the package from [Nuget](https://www.nuget.org/packages/JsonStores)\n\n```text\n    dotnet add package JsonStores\n```\n\nJust add it to your [DI container](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) using `AddJsonStores()` extension method\n\n```csharp\n    public void ConfigureServices(IServiceCollection services)\n    {\n        // add your dependencies\n\n        services.AddJsonStores();\n    }\n```\n\nInject this with `IJsonStore\u003cT\u003e` or `IJsonRepository\u003cT, TKey\u003e` interfaces\n\n```csharp\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class MyController : ControllerBase\n    {\n        private readonly IJsonRepository\u003cMyClass, MyClassKey\u003e _repository;\n        private readonly IJsonStore\u003cMyConfig\u003e _config;\n\n        public MyController(IJsonRepository\u003cMyClass, MyClassKey\u003e repository, IJsonStore\u003cMyConfig\u003e config)\n        {\n            _repository = repository;\n            _config = config;\n        }\n\n        [HttpGet]\n        public async Task\u003cActionResult\u003e Get()\n        {\n            var items = await _repository.GetAllAsync();\n            return Ok(items);\n        }\n\n        [HttpPost(\"ChangeData\")]\n        public async Task\u003cActionResult\u003e Post(Dto dto)\n        {\n            var item = await _config.ReadOrCreateAsync();\n\n            item.Data1 = dto.Data1;\n            item.Data2 = dto.Data2;\n\n            await _config.SaveAsync(item);\n            return Ok();\n        }\n    }\n```\n\n## Change options\n\nUse the class `JsonStoreOptions` to customize\n\n```csharp\n    public void ConfigureServices(IServiceCollection services)\n    {\n        var options = new JsonStoreOptions\n        {\n            // file location - default is the current directory\n            Location = @\"C:\\my files\",\n            // how generate the file name - default is the name of the generic class\n            NamingStrategy = new StaticNamingStrategy(\"myFile\"),\n            // file extension - default is 'json'\n            FileExtension = \"arq\"\n            // looks file writing time to avoid data loss - default is 'true'\n            ThrowOnSavingChangedFile = false;\n        };\n        \n        services.AddJsonRepository\u003cMyClass, MyClassId\u003e(options);\n        services.AddJsonStore\u003cSettings\u003e(options =\u003e options.NamingStrategy = new StaticNamingStrategy(\"configs\"));\n\n        // you can add generic classes with other options\n        services.AddJsonStores(options =\u003e options.Location = @\"D:\\stores\", ServiceLifetime.Transient);\n    }\n```\n\n## Create your JSON repository\n\nIn order to instantiate the repository, you must specify a property as an unique key. The second generic parameter must\nmatch the type of this property.\n\n- If your class has an Id property, it will be used. You can change this behavior by adding the `IgnoreIdProperty`\n  annotation to your class.\n- To use another property, add the `JsonRepositoryKey` annotation on any property of your class.\n\nIf your are manually instantiating your class, you can pass an expression in the constructor:\n\n```csharp\n    var options = new JsonStoreOptions();\n    var repository = new JsonRepository\u003cMyClass, int\u003e(options, myClass =\u003e myClass.Key);\n```\n\nAn `InvalidJsonRepositoryKeyException` will be thrown if:\n\n- Your class don't have an `Id` or any property with the `JsonRepositoryKey` annotation.\n- There is more than one property with the `JsonRepositoryKey` annotation.\n- The property type don't match the second generic parameter.\n\n## Personalize your store using inheritance\n\nYou can also customize the behavior of your stores just extending `JsonStore` and `JsonRepository` classes.\n\n```csharp\n    public class CustomStore : JsonRepository\u003cMyClass, Guid\u003e\n    {\n        protected override string FileName =\u003e \"my-items\";\n    \n        public CustomStore(options) : base(options, obj =\u003e obj.ObjId)\n        {\n        }\n\n        // ...\n    }\n```\n\nSee the `NoteStore` class on [sample app](#Sample-apps) for details.\n\n## Concurrent stores\n\nThe `Concurrent` namespace contains the thread-safe overloads: `ConcurrentJsonStore` and `ConcurrentJsonRepository`.\n\n### Semaphore factories\n\nIn addition to the default parameters, you'll need to provide a `ISemaphoreFactory`. A binary [Semaphore](https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphore) is obtained based on the type of the store (the `T` parameter) and used to control who can access the store.\n\nThere are three built-in implementations:\n\n- `LocalSemaphoreFactory` returns the same (singleton) semaphore. This lightweight instance may not work properly on a multi-instance app.\n- `NamedSemaphoreFactory` returns a named (system-wide) semaphore with the given string. This will be available for the entire SO.\n- `PerFileSemaphoreFactory` returns a named semaphore based on a given `IJsonStoreOptions`.\n\n\u003e Named semaphores are only available on Windows machines. See [this issue](https://github.com/dotnet/runtime/issues/4370) for details.\n\n#### Custom factory\n\nTo implement your own factory, just return a binary (from 1 to 1) Semaphore object.\n\n```csharp\n    public class CustomFactory : ISemaphoreFactory\n    {\n        public Semaphore GetSemaphore\u003cT\u003e()\n        {\n            if (typeof(T) == typeof(string))\n                return new Semaphore(1, 1, \"my-string-semaphore\");\n            if (typeof(T) == typeof(int))\n                return new Semaphore(1, 1, \"my-int-semaphore\");\n\n            throw new ApplicationException($\"Invalid type: '{typeof(T).Name}'.\");\n        }\n    }\n```\n\n### Additional repository methods\n\n`ConcurrentJsonRepository` class contains methods to edit and save the store as a single operation. If you are implementing a multi-instance app (or using multiple repositories instances), use there methods to avoid a `FileChangedException`.\n\n## Sample apps\n\nYou can see the usage of both `JsonStore` and `JsonRepository` with the apps on [Samples](Samples/README.md) folder.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faugustocb23%2Fjson-stores","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faugustocb23%2Fjson-stores","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faugustocb23%2Fjson-stores/lists"}