Giter Club home page Giter Club logo

monkey-cache's Introduction

πŸ’Cache

2.0-beta -> This is a WIP and targets only .NET 6 using source generators instead of Newtonsoft.Json. This is cutting edge, please don't update yet unless you want to try out some crazy awesome stuff ;)

Easily cache any data structure for a specific amount of time in any .NET application.

Monkey Cache is comprised of one core package (MonkeyCache) and three providers which reference the core package as a dependency. At least one provider must be installed for Monkey Cache to work and each offer the same API (IBarrel). Depending on your existing application you may already have SQLite or LiteDB installed so these would be your natural choice. A lightweight file based Monkey Cache is also provided if you aren't already using one of these options.

Listen to our podcast Merge Conflict: Episode 76 for an overview of Monkey Cache and it's creation.

A full breakdown of performance can be found in the performance.xlsx. When dealing with a small amount of records such as inserting under 50 records, the performance difference between each provider is negligible and it is only when dealing with a large amount of records at a single time that you should have to worry about the provider type.

Azure DevOps

You can follow the full project here: https://dev.azure.com/jamesmontemagno/MonkeyCache

Build Status:

NuGets

Name Description NuGet
πŸ’ MonkeyCache Contains base interfaces and helpers NuGet
πŸ™Š MonkeyCache.SQLite A SQLite backing for Monkey Cache NuGet
πŸ™‰ MonkeyCache.LiteDB A LiteDB backing for Monkey Cache NuGet
πŸ™ˆ MonkeyCache.FileStore A local file based backing for Monkey Cache NuGet
Development Feed MyGet

Platform Support v2.X

Version 2.0 and above target .NET 6 and above

Platform Version
.NET 6+
.NET MAUI All
.NET for iOS All
.NET for Android All
.NET for MacCatalyst All
Windows 10 UWP (.NET 6+) 10.0.19041+

Platform Support - v1.X

Monkey Cache is a .NET Standard 2.0 library, but has some platform specific tweaks for storing data in the correct Cache directory.

Platform Version
Xamarin.iOS iOS 7+
Xamarin.Mac All
Xamarin.Android API 14+
Windows 10 UWP 10.0.16299+
.NET Core 2.0+
ASP.NET Core 2.0+
.NET Framework 4.6.1+

Setup

First, select an implementation of Monkey Cache that you would like (LiteDB, SQLite, or FileStore). Install the specific NuGet for that implementation, which will also install the base MonkeyCache library. Installing MonkeyCache without an implementation will only give you the high level interfaces.

It is required that you set an ApplicationId for your application so a folder is created specifically for your app on disk. This can be done with a static string on Barrel before calling ANY method:

Barrel.ApplicationId = "your_unique_name_here";

LiteDB Encryption

LiteDB offers built in encryption support, which can be enabled with a static string on Barrel before calling ANY method. You must choose this up front before saving any data.

Barrel.EncryptionKey = "SomeKey";

LiteDB Upgrade (4 -> 5) | NuGet 1.3 -> 1.5

If you are upgrading from 1.3 to 1.5 of the NuGet package it also went through an upgrade of LiteDB.

You may need to do an upgrade of the database before using it. In your project you can set the folowing after setting your EncryptionKey or Applicationid:

Barrel.Upgrade = true;

What is Monkey Cache?

The goal of Monkey Cache is to enable developers to easily cache any data for a limited amount of time. It is not Monkey Cache's mission to handle network requests to get or post data, only to cache data easily.

All data for Monkey Cache is stored and retrieved in a Barrel.

For instance you are making a web request and you get some json back from the server. You would want the ability to cache this data in case you go offline, but also you need it to expire after 24 hours.

That may look something like this:

async Task<IEnumerable<Monkey>> GetMonkeysAsync()
{
    var url = "http://montemagno.com/monkeys.json";

    //Dev handle online/offline scenario
    if (!CrossConnectivity.Current.IsConnected)
    {
        return Barrel.Current.Get<IEnumerable<Monkey>>(key: url);
    }
    
    //Dev handles checking if cache is expired
    if (!Barrel.Current.IsExpired(key: url))
    {
        return Barrel.Current.Get<IEnumerable<Monkey>>(key: url);
    }

    var client = new HttpClient();
    var monkeys = await client.GetFromJsonAsync<IEnumerable<Monkey>>(url);

    //Saves the cache and pass it a timespan for expiration
    Barrel.Current.Add(key: url, data: monkeys, expireIn: TimeSpan.FromDays(1));
}

Ideally, you can make these calls extremely generic and just pass in a string:

public async Task<T> GetAsync<T>(string url, int days = 7, bool forceRefresh = false)
{
    if (!CrossConnectivity.Current.IsConnected)
        return Barrel.Current.Get<T>(url);

    if (!forceRefresh && !Barrel.Current.IsExpired(url))
       return Barrel.Current.Get<T>(url);

    try
    {
        T result = await httpClient.GetFromJsonAsync<T>(url);
        Barrel.Current.Add(url, result, TimeSpan.FromDays(days));
        return result;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Unable to get information from server {ex}");
        //probably re-throw here :)
    }

    return default;
}

MonkeyCache will never delete data unless you want to, which is pretty nice incase you are offline for a long period of time. However, there are additional helpers to clean up data:

    //removes all data
    Barrel.Current.EmptyAll();
	
	//removes all expired data
    Barrel.Current.EmptyExpired();

    //param list of keys to flush
    Barrel.Current.Empty(key: url);

The above shows how you can integrate Monkey Cache into your existing source code without any modifications to your network code. However, MonkeyCache can help you there too! MonkeyCache also offers helpers when dealing with network calls via HttpCache.

HttpCache balances on top of the Barrel and offers helper methods to pass in a simple url that will handle adding and updating data into the Barrel based on the ETag if possible.

Task<IEnumerable<Monkey>> GetMonkeysAsync()
{
    var url = "http://montemagno.com/monkeys.json";

    //Dev handle online/offline scenario
   
	var result = await HttpCache.Current.GetCachedAsync(barrel, url, TimeSpan.FromSeconds(60), TimeSpan.FromDays(1));
    return JsonConvert.DeserializeObject<IEnumerable<Monkey>>(result);
}

Cache will always be stored in the default platform specific location:

Platform Location
Xamarin.iOS NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User)[0];
Xamarin.Mac NSSearchPath.GetDirectories(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomain.User)[0];
Xamarin.Android Application.Context.CacheDir.AbsolutePath
Windows 10 UWP Windows.Storage.ApplicationData.Current.LocalFolder.Path
.NET Core Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
ASP.NET Core Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
.NET Framework Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)

Persisting Data Longer

Since the default is to use the Cache directories the platform can clean this up at any time. If you want to change the base path of where the data is stored you can call the following static method:

BarrelUtils.SetBaseCachePath("Path");

You MUST call this before initializing or accessing anything in the Barrel, and it can only ever be called once else it will throw an InvalidOperationException.

Json Serialization

MonkeyCache v2.0 and higher uses System.Text.Json to serialize objects to/from the backing store. By default, the default System.Text.Json serialization behavior is used. There are two options for controlling this serialization:

  1. Pass an optional JsonSerializationOptions instance to Barrel.Current.Add and Barrel.Current.Get.
  2. Pass a JsonTypeInfo<T> instance to Barrel.Current.Add and Barrel.Current.Get. You can get a JsonTypeInfo<T> instance by using the System.Text.Json source generator. See How to use source generation in System.Text.Json for more information.

No matter which option you choose, it is recommended to use the same option between Barrel.Current.Add and Barrel.Current.Get. If the options are inconsistent, the information going into the backing store may not be read properly when retrieving it back from the Barrel.

FAQ

Have questions? Open up an issue. Here are a few:

How does Monkey Cache differ from the Settings Plugin?

Great question. I would also first say to read through this: https://github.com/jamesmontemagno/SettingsPlugin#settings-plugin-or-xamarinforms-appproperties as it will compare it to app.properties.

So with the Settings Plugin it is storing properties to the users local preferences/settings api of each platform. This is great for simple data (bool, int, and small strings). Each platform has different limitations when it comes to these different types of data and strings especially should never house a large amount of data. In fact if you try to store a super huge string on Android you could easily get an exception.

Monkey Cache enables you to easily store any type of data or just a simple string that you can easily serialize and deserialize back and forth. The key here is that you can set an expiration data associated with that data. So you can say this data should be used for the next few days. A key here is the ETag that is extra data that can be used to help with http caching and is used in the http caching library.

Isn't this just Akavache?

Akavache offers up a great and super fast asynchronous, persistent key-value store that is based on SQLite and Reactive Extensions. I love me some Akavache and works great for applications, but wasn't exactly what I was looking for in a data caching library. Akavache offers up a lot of different features and really cool Reactive type of programming, but Monkey Cache focuses in on trying to create a drop dead simple API with a focus on data expiration. My goal was also to minimize dependencies on the NuGet package, which is why Monkey Cache offers a SQLite, LiteDB, or a simple FileStore implementation for use.

How about the link settings?

You may need to --linkskip=SQLite-net or other libraries.

Where Can I Learn More?

Listen to our podcast Merge Conflict: Episode 76 for an overview of Monkey Cache and it's creation.

License

Under MIT (see license file)

Want To Support This Project?

All I have ever asked is to be active by submitting bugs, features, and sending those pull requests down! Want to go further? Make sure to subscribe to my weekly development podcast Merge Conflict, where I talk all about awesome Xamarin goodies and you can optionally support the show by becoming a supporter on Patreon.

monkey-cache's People

Contributors

bartlannoeye avatar ctyar avatar depechie avatar dependabot[bot] avatar eerhardt avatar jamesmontemagno avatar lucecarter avatar matthewclendening avatar mikefoden avatar redth avatar scarlettcode avatar trbenning avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

monkey-cache's Issues

Request: Barrel.Current.GetAllKeys()

First, is it possible to get all the keys that are stored in the cache?

When having large lists which needs paging, I cache the pages with a key and append the page number on the end. For example $"{MyListCache}{PageNumber}";

However when I want to refresh the pages, I want to remove all the keys which include the text MyListCache.

Therefor I would like to get all the keys, determine if they start with my MyListCache key then remove them.

Performance chart

Cool library!

I was trying to interpret the performance chart, but I can't figure out the labels. I presume the columns are milliseconds?

And the ETag values are all zero because that's not supported?

And I'm not sure exactly why there are two different charts. I see 1-4000 for each backing store, but then what is the significance of the chart on the right?

Sorry to be dense.

currentBarrel.Empty() doesn't delete files with MonkeyCache.FileStore

I have detected that the size of app cache doesn't change after emptying the keys - so, the files have not been deleted. I think that it can be connected with file attributes, and can be fixed with
File.SetAttributes(destinationFilename, FileAttributes.Normal);
before File.Delete(destinationFilename);
as it is mentioned here
https://stackoverflow.com/questions/45076903/c-sharp-file-delete-doesnt-not-work

Thanks for the MonkeyCache!

Thread safety?

Is this stuff thread safe? I don’t see any mentioning about it.

PS It looks really nice.

Make UniqueID for NETCore go away

By setting the UniqueID for the folder in .NET Core, does the developer have to know that key later? Can you obfuscate the implementation detail and just create the unique ID folder for me on that platform? Like just a GUID?

Invalid encryption key

A few times I've had the error invalid encryption key.

Is it possible to remove the the current cache instance/ db and recreate it when this error is thrown?

Question: Can expiration days be null?

As I review the code I can use it to store data even not from http. For example I am using akavache as to store user results. If user plays a game, I create object with akavache and using "Save" I save it and "Get" to display results. Therefore those in app data never gets expired. Is it possible to that? Akavache exposes this parameter as nullable.

Creating new HttpClient for each call

I know a while back it was suggested that we not create a new HttpClient for each call as it was thread safe and expensive.

Has that advice changed? Or maybe it was just for Asp.Net. Or .Net before .Net Core

Is it performant enough for a XF app?

TIA

How is it different than SettingsPlugin?

Reading the docs, I know both the plugins save data at different locations but I'm trying to understand why and how these two plugins will be used inside same app. Sorry for asking a question here.

file is not a database

hello, I have a problem with MonkeyCache.SqlLite 1.2.0 and I use an android api 26

I try to use this code

Barrel.ApplicationId = "Cache";
Barrel.Current.EmptyExpired ();
string cache = Barrel.Current.Get ("Visits-" + id_bn);

and an Exception is thrown: "file is not a database"

Could you help me?

Failed to add Reference

I am getting this error when installing to my android project :

Failed to add reference. The package 'MonkeyCache' tried to add a framework reference to 'System.Runtime' which was not found in the GAC. This is possibly a bug in the package. Please contact the package owners for assistance. Error HRESULT E_FAIL has been returned from a call to a COM component.

Target Framework : .Net Standard 2.0 ( converted from PCL)
Xamarin.Forms version : 2.5.0.280555
Android Target Framework Version : 8.0

Add Auto Expiration

Description

While I certainly understand that some developers may prefer to handle removing expired values, I would suggest adding a setting that will tell MonkeyCache to automatically purge expired values.

Barrel.AutoExpire = true;

// Now returns a null if the object is expired.
var monkey = Barrel.Current.Get<Monkey>("foo");

Clearing Cache While App is Running Causing System.IO.DirectoryNotFoundException

Steps to reproduce:

  1. Run up my app
  2. In my Android phone I manually clear the application cache via Settings -> App -> Storage -> Clear Cache
  3. Return to my app
  4. Go somewhere that uses something cached.
  5. The Barrel.Current.Get returns a null, so I go get the data again
  6. Barrel.Current.Add then causes the directory not found exception.

The only way I have found around this is to try/catch all of the Add calls and then call Barrel.Create if that Exception occurs.

Request: Barrel.Current.EmptyAllExcept(string[] keys)

I really love this cache and would like to issue a feature request.
I use the cache all over my app with a lot of keys but when I do some major release upgrade I would like to empty the cache for all except few keys,
Since my keys are partially dynamic it is really difficult to delete all keys except few ones which need to stay.

So it would be helpful to have some kind of exclude functionality.

Barrel.Current.EmptyAllExcept(string[] keys);

If this is not possible please kindly provide functionality to get all the keys in the cache.
With this I could empty the keys one-by-one and exclude some keys-manually.

Thx a lot.

Barrel.ApplicationId needed for Android?

I guess Barrel.ApplicationId shouldn't be needed for android, or at least it would need to be unique only within the application itself since the cache directory is application bound.

Read-only issue while executing MonkeyCache.SQLite.Barrel.Empty

Hi James,

I am facing the below issue while executing
MonkeyCache.SQLite.Barrel.Empty().

Error log:
04-02 22:32:07.346 16465 16465 E AndroidRuntime: android.runtime.JavaProxyThrowable: SQLite.SQLiteException: ReadOnly
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at SQLite.SQLiteCommand.ExecuteNonQuery () [0x000c0] in :0
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at SQLite.SQLiteConnection.Execute (System.String query, System.Object[] args) [0x0003a] in :0
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at SQLite.SQLiteConnection.Delete (System.Object primaryKey, SQLite.TableMapping map) [0x00048] in :0
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at SQLite.SQLiteConnection.Delete[T] (System.Object primaryKey) [0x00013] in :0
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at MonkeyCache.SQLite.Barrel+<>c__DisplayClass22_0.b__0 () [0x0000f] in <407b98dd74624081a17e95bdc70a6233>:0
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at SQLite.SQLiteConnection.RunInTransaction (System.Action action) [0x0001d] in :0
04-02 22:32:07.346 16465 16465 E AndroidRuntime: at MonkeyCache.SQLite.Barrel.Empty (System.String[] key) [0x00025] in <407b98dd74624081a17e95bdc70a6233>:0

Any suggestions ?

Data migration

Is there any recommended way to handle a previous record of same key but with different type due to update of the code base?
This is like updating your database column into a different type.

var val1 = Barrel.Current.Get<TPrevious>(key); // throws
var val2 = Barrel.Current.Get<TUpdated>(key); // OK

I'm thinking of something like:

Barrel.Current.Configure(config =>
{
    config.ForVersion(2).MigrateType<OldType, NewType>(oldValue =>
    {
         return new NewType
        {
            Id = oldValue.Id,
            // more mapping...
        };
    });
});

Database Is Locked

I use Monkey Cache to get data for two fragments that are displayed on a tab layout with a viewpager. Both fragments are loaded at the same time even though only one is visible at any given time. However, I get a "Database Is Locked" error in Crashlytics.

I quick workaround that came to mind was to just load one fragment at a time. However, both fragments have to be loaded for the sake of showing a sliding animation.

Perhaps using a singleton with locking for accessing Monkey Cache could also alleviate the problem.

Thank you for your help.

GetAll and EmptyAll for same type?

For some cases it could be useful to cache same object type (serialized into string) with different keys but under same group. Could be possible to extend Banana with some kind of "groupkey" and have function like IEnumerableGetAll(string Groupkey); and EmptyAll for a group. Just an idea. it can be useful.

Would a sqllite-net encryption provider be useful.

I am aware that there are two database backed providers for MonkeyCache, SQLite and LiteDB. As I understand it the only provider that offers encryption is the LiteDB provider. It would appear that there are however security concerns with the encryption implementation in LiteDB (open issue at mbdavid/LiteDB#581).

A SQLite provider exists, which doesn't provide an encryption option. I believe that SQLite-net does provide encryption (via the sqlite-net-sqlcipher package) and I that got me wondering a couple of things.

  1. Would a SQLite-net provide for Monkey Cache that supports encryption be something useful? I imagine it wouldn't be too different from the SQLite provider? Or is there some other reason that a SQLite-net provider is not viable?

  2. Is it possible for a user of Monkey Cache to provide their own persistence provider, rather than using one of the existing providers?

Using TimeSpan.MaxValue in expiration makes Barrel throw Exception

Code needed to reproduce:

Barrel.Current.Add("key", "val", TimeSpan.MaxValue);

Expected outcome:

Message: System.ArgumentOutOfRangeException : The added or subtracted value results in an un-representable DateTime.
Parameter name: value

StackTrace:

Result StackTrace:
at System.DateTime.AddTicks(Int64 value)
at MonkeyCache.FileStore.Barrel.Add(String key, String data, TimeSpan expireIn, String eTag)
at MonkeyCache.FileStore.Barrel.Add[T](String key, T data, TimeSpan expireIn, String eTag)

Provide a way to specify where the cache is stored

This is a feature request.

The platform specific cache directory is used to store the cache now. I guess the underlying cache provider implementation decides ultimately where the cache is created. However it would be better to provide the developers with an option to specify the cache storage location so that for example in iOS and Android, the app dir can be used.

Cache item expiry date

I want to know when a particular cache item will expire or how many days remaining before expiry. Is there a way?

Cache file is not deleted in Android when clearing cache is done from android's App Info page

Saving data in the cache works as expected but I have a couple of strange behaviors on android:

  • When I erase the cache by using android's App Info page (in settings) I would have expected (as the docs are saying) that this would remove all my cache entries. This doesn't seem to be the case.
  • When I try to find the files (I use FileStore) using a file explorer (on the device or on Windows through USB) I can't find any folder 'MonkeyFileFS' in the Cache folder nor in the Files folder. So, where are they?

On UWP the files are present in the LocalState folder. Didn't test yet on iOS.

I must also remark that the tests I have done were all with deployments coming from Visual Studio, not with a real 'apk' from the play store. Could that be the reason?

Marking cached data as "modified"

Hi, I have a question.

I was wondering if it's possible the mark cached data as modified.
Which means that is has to be sent to the server after being modified locally, and not be overwritten with new data from the server.
Does this functionality already exist, I didn't see it in the documentation?

I ask because I'm looking at rewriting my own hamstrung caching implementation, but if this were to have that functionality I'd strongly consider using this instead.

Using from inside unit tests?

I have a project that relies heavily on Monkey Cache, and I'm in the process of adding unit tests to it. The thing is that it's easier and more convenient to inject the FileStore backend than making a mock by myself that may end not behaving exactly the same.

Everything works when running the tests but some of them seem to run concurrently and I get a few IOExceptions:

Message: System.IO.IOException : The process cannot access the file 'C:\Users\xxx\AppData\Local\com.mycompany.myapp\MonkeyCacheFS\idx.dat' because it is being used by another process.

Is this a known issue? Should I just lock access to the Barrel when I'm using it?

Get Sharing violation exception

Hi James,
I used MonkeyChache.FileStore 1.2.0-beta in my .NetStandard 2.0 Xamarin.forms project.

I got this exception when I try to call

 Barrel.Current.Exists(key);
System.IO.IOException: Sharing violation on path /data/user/0/com.xx.app/MonkeyCacheFS/idx.dat

Do you have any idea why it throw this exceptions?
I can catch the exception and it works fine. Do you think it's necessary to mention this in the document?

Thanks,
Jesse

Issue set and retrieve expiration

Hi James and Crew!

I currently tried out monkey cache simply for... well caching data and it worked great out of the box. Now i tried to implement expiration logic, but for some reason it is not working like expected.

    string res;
    TimeSpan ts;
    switch (timeSpanType)
    {
        case TimeSpanTypeEnums.FromMinutes:
        ts = TimeSpan.FromMinutes(validFor);
        Barrel.Current.Add(key:url.ToString(), data:result, expireIn: ts);
        after = Barrel.Current.GetExpiration(url.ToString());
        break;
        [...]
    }

In the added code it appears that after running into the correct case, 'ts' gets set correctly, by for example 5 minutes (validFor), then the data gets cached with the Add-method, but when I try to get the remaining expiration after adding the monkeys into the barrel, 'after' always returns "{01.01.0001 00:00:00}" BUT: IsExpired works as expected. What am I doing wrong? I bet I miss something very basic, I am not sure if this is the right place for this question. Thank you!

Best regards

Grexy

iOS with full-linking enabled crashes app

Running with LinkSDKOnly works great, but once I enable full linking I get this error.
I tried to --linkskip MonkeyCache and MonkeyCache.Sqlite without success.

The stack trace:

{System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> SQLite.SQLiteException: duplicate column name: Id
  at SQLite.SQLite3.Prepare2 (SQLitePCL.sqlite3 db, System.String query) [0x0000f] in /Users/vagrant/git/src/SQLite.cs:3544 
  at SQLite.SQLiteCommand.Prepare () [0x00000] in /Users/vagrant/git/src/SQLite.cs:2463 
  at SQLite.SQLiteCommand.ExecuteNonQuery () [0x00030] in /Users/vagrant/git/src/SQLite.cs:2318 
  at SQLite.SQLiteConnection.Execute (System.String query, System.Object[] args) [0x0003a] in /Users/vagrant/git/src/SQLite.cs:673 
  at SQLite.SQLiteConnection.MigrateTable (SQLite.TableMapping map) [0x000be] in /Users/vagrant/git/src/SQLite.cs:605 
  at SQLite.SQLiteConnection.CreateTable (System.Type ty, SQLite.CreateFlags createFlags) [0x0014a] in /Users/vagrant/git/src/SQLite.cs:440 
  at SQLite.SQLiteConnection.CreateTable[T] (SQLite.CreateFlags createFlags) [0x00000] in /Users/vagrant/git/src/SQLite.cs:392 
  at MonkeyCache.SQLite.Barrel..ctor () [0x00044] in <8e67637579214cf39cd2a1a6ddb88bea>:0 
  at MonkeyCache.SQLite.Barrel.get_Current () [0x00009] in <8e67637579214cf39cd2a1a6ddb88bea>:0 

Let me know if there is anything more I can do to help you investigate it.
Keep up the good work

Maximum Cache Size Limit

MonkeyCache is awesome, loving it so far. Was wondering if this would be useful. Have a set maximum cache limit (in bytes). So that if you cache something that goes over the limit it will first remove all expired items, but then if necessary remove the least recent items until the volume of cache hits the maximum cache limit.

I have a requirement to implement this now with an app using monkey cache. Any recommendation on how to do this? Sorry if this isn't the most appropriate place to put this.

Can't find Barrel class.

I'm hoping that this is the correct place to ask.

I've just installed MonkeyCache with NuGet on Visual Studio for Mac. The code examples in the README file show the use of a class called Barrel, such as Barrel.Current.Get and Barrel.Current.Add. Visual Studio does not find this class in my installation. It finds the interface IBarrel and BarrelUtils when MonkeyCache has been imported. I've tried messing around with both of those to try and achieve the same result as the code examples give but to no avail.

Code-completion in Visual Studio shows me 5 suggestions if I just type "MonkeyCache." and they are:

  • BarrelUtils
  • HttpCache
  • HttpCacheExtensions
  • HttpCacheRequestException
  • IBarrel

The first four are classes, the last one is of course an interface.

Kinda stuck at this point. Any help appreciated.

Unable to write to a DB file on a macOS [Unit test]

When creating the Unit test for my MonkeyCache.LiteDB service it throws the following exception on Barrel.Current.Exists(key)

FAIL: [IsCachedDataAvailable] Your platform does not support FileStream.Lock. Please set mode=Exclusive in your connnection string to avoid this error.
at LiteDB.StreamExtensions.CreateLockNotSupportedException(PlatformNotSupportedException innerEx)
at LiteDB.StreamExtensions.<>c__DisplayClass4_0.b__0()
at LiteDB.FileHelper.TryExec(Action action, TimeSpan timeout)
at LiteDB.StreamExtensions.TryLock(FileStream stream, Int64 position, Int64 length, TimeSpan timeout)
at LiteDB.FileDiskService.Lock(LockState state, TimeSpan timeout)
at LiteDB.LiteEngine..ctor(IDiskService disk, String password, Nullable1 timeout, Int32 cacheSize, Logger log, Boolean utcDate) at LiteDB.LiteDatabase.<>c__DisplayClass11_0.<.ctor>b__0() at LiteDB.LazyLoad1.get_Value()
at LiteDB.LiteCollection1.<Find>d__17.MoveNext() at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source)
at MonkeyCache.LiteDB.Barrel.Exists(String key) in D:\a\1\s\src\MonkeyCache.LiteDB\Barrel.cs:line 73

As the error log says "Your platform does not support FileStream.Lock. Please set mode=Exclusive in your connnection string to avoid this error."

Would be possible to add the option to actually add a ConnectionString with mode included?

db = new LiteDatabase(path);
error on LiteDB ref : mbdavid/LiteDB#787

Stable release for MonkeyCache

Hi James,

I am using below monkey cache version in my POC.
"MonkeyCache" version="0.1.0.10-beta"

But i am not able to use it Production app. because it is in Beta state.
So, When can we expect a stable release ??
or
Can you please suggest an alternate for monkey cache??

With Regards,
Siva

System.MissingMethodException: void SQLite.SQLiteConnection..ctor(string,bool)

Hello!
I'm trying monkeycache 0.1.0.10-beta in a sample app where I'm using sqlite-net-pcl 1.5.231 too.

Barrel.ApplicationId = "TestAppNSPrism7";            
var data = Barrel.Current.Get("test");

on the second line I'm getting a:
System.MissingMethodException: void SQLite.SQLiteConnection..ctor(string,bool)

Any hint on what am I doing wrong?
Thanks!

DelegatingHandler

Maybe having a custom DelegatingHandler that would manage http cache could be a better solution since it would be queue-able with other HttpHandlers instead of having implementation hidden behind HttpCache(which could stay and use the custom handler).

\" added to strings

Hi James - Thank you for this wonderful tool.

I upgraded from Beta to version 1.3 (LiteDb). When I request a string, the string now comes back wrapped in \" . The Beta version returned a string without the \"

Is there a way to disable that serialization?

 Barrel.Current.Add(key, "dog", expire);
 var x = Barrel.Current.Get<T>(key);   //where T is a string
 // x now is \"dog\"

Storage of file

Sorry to post as an issue. But how (and can) I use MonkeyCache to store files. I guess I can store a base64 string but don't really want the size overhead with that.

First time hitting cache

Based on your example code in the readme IsExpired returns false as per line 88 below

public bool IsExpired(string key)
{
Banana ent;
lock (dblock)
{
ent = db.Find<Banana>(key);
}
if (ent == null)
return false;
return DateTime.UtcNow > ent.ExpirationDate;
}

This means that you can never get past the expired check for an empty cache. Shouldn't an empty cache return IsExpired = true? Or am I missing something? How do I populate the cache the very first time?

Using this with LinqPad

First, this is a really great library. I know that sounds stupid, but it just works and that's so refreshing.

In case this helps anyone else, I was trying to use this with LINQPad and if you create a class using the C# Program Language your type name becomes something useful to LINQPad but not JSON so much and it gets upset.

I feel sure there's a way to do it, but I ended up creating classes and namespaces outside the LINQPad environment and used SWApi to test. HTH.

So much fun.

iOS cache gets cleared

I use MonkeyCache to store my user info, including a jwt token.
When I start the app, I check for the existence of that cache. If it exists, the user is logged on and can query my backend. If it doesn't exist, the app starts with the login page.

All good. Except that on my iPhone, I am "disconnected" after I open the app if I haven't used a while (overnight for example). The cache is cleared. It doesn't happen on the emulator: I'm always connected day after day. It's not an expiration issue (the expiration time is 30 days). And it's hard to debug as I can't reproduce it in debug mode.

Any know issue about iOS claiming the cache? Can we "register" to such events? Any ideas on how I can pinpoint what's happening?
Tks.

Expose mechanism to control JSON serialization

I've had to wrap my usage of MonkeyCache with a facade will let's me do Get<T> and InsertObject<T> where I control how the object is de|serialized. Why? I have a couple of custom converters in play that are not easily "put on the types" via [JsonConverter] attributes.

Exposing the JsonSettings object in use would be helpful. I'd be happy to create a PR if you like.

Cached data not persisted between app sessions

I can not confirm this as a bug with MonkeyCache. However I am getting quite a few reports of users having to log in to the app after not using it for 1/2 days.

Users are considered logged in if they have a user token in the cache, and this seems to be missing after a period of the app not being used. The expireIn is set to one year.

This happens only on Android and there is no clear device or Android Api level it occurs on.

Has anyone else had this issue or an idea what could be going on? Its impossible to debug.

Breaking ABI change in sqlite-net-pcl v1.6.292

In the v1.6.292 release of sqlite-net-pcl, one of the SQLiteConnection constructor's signatures got changed. This happened to be the constructor that MonkeyCache.SQLite.Barrel was using.

This commit shows the change: praeclarum/sqlite-net@8649a68.

Since the current release of the application is built agains v1.5, having the newer version of sqlite-net-pcl installed (which is allowed by the dependency constraints), it crashes with a System.MissingMethodException.

iOS Project with MonkeyCache Azure DevOps build fails on _CompileToNative build step

I've been pulling my hair out with this. I get this error on Azure DevOps:

'''
MTOUCH : error MT2101: Can't resolve the reference 'System.String[] System.String::Split(System.Char,System.StringSplitOptions)', referenced from the method 'System.Void MonkeyCache.FileStore.Barrel::LoadIndex()' in 'mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'. [/Users/runner/runners/2.160.0/work/1/s/MyApp/MyApp.iOS/MyApp.iOS.csproj]
D
'''

Anybody experience the same and have any work around?

I have the latest Xamarin Forms, Visuual Studio for Mac, and updated all my nuget package and using efaults of SDK versions. Builds on my machine but not on Azure DevOps. The moment I add Monkey Cache it gives the above build error on Azure DevOps

MissingMethodException: CreateTable<!0>

I'm checking Barrel.Current.IsExpired(key) and I get the exception below. I have not added anything to the cache yet, my service checks if it's expired before doing anything else. Do I need to call .Add<T>() before anything else?

System.MissingMethodException: int SQLite.SQLiteConnection.CreateTable<!0>(SQLite.CreateFlags)

Support for custom Barrel names

It would be great if there could be an option to create Barrel instances that have a custom name.
I know that you can specify a custom cache directory, but that isn't really convenient if you just want to create a new Barrel in the default cache directory.
Currently the default cache directory for a Barrel is <cache dir>/<application id>/MonkeyCache. I'd suggest having a static method like Barrel.ForName(string barrelName) that would still use the default cache directory, but append barrelName to is. So, for example if you were to call Barrel.ForName("myBarrel"), the Barrel would be initialised in the directory <cache dir>/<application id>/MonkeyCache/<barrel name> or <cache dir>/<application id>/MonkeyCache-<barrel name>. Escaping may be necessary if the given custom Barrel name contains invalid path characters.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.