{"action":"created","comment":{"url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/comments/40507167","id":40507167,"diff_hunk":"@@ -0,0 +1,287 @@\n+﻿/*\n+ * Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)\n+ * See https://github.com/aspnet-contrib/AspNet.Caching.Stores\n+ * for more information concerning the license and the contributors participating to this project.\n+ */\n+\n+using System;\n+using System.Linq;\n+using System.Threading.Tasks;\n+using Microsoft.Framework.Caching.Distributed;\n+using Microsoft.Framework.Caching.Memory;\n+using Microsoft.Framework.OptionsModel;\n+using MongoDB.Bson;\n+using MongoDB.Driver;\n+\n+namespace AspNet.Caching.MongoDb {\n+    public sealed class MongoDbCache : IDistributedCache {\n+\n+        private readonly MongoDbCacheOptions _options;\n+\n+        private IMongoClient _client;\n+\n+        public MongoDbCache(IOptions<MongoDbCacheOptions> optionsAccessor = null) {\n+            _options = optionsAccessor?.Value ?? new MongoDbCacheOptions();\n+\n+            if (string.IsNullOrWhiteSpace(_options.ConnectionString)) {\n+                throw new InvalidOperationException(\"The MongoDB connection string must be nonempty.\");\n+            }\n+\n+            if (string.IsNullOrWhiteSpace(_options.Database)) {\n+                throw new InvalidOperationException(\"The MongoDB database name must be nonempty.\");\n+            }\n+\n+            if (string.IsNullOrWhiteSpace(_options.Collection)) {\n+                throw new InvalidOperationException(\"The MongoDB collection name must be nonempty.\");\n+            }\n+\n+            if (_options.DefaultRelativeExpiration < TimeSpan.Zero)\n+            {\n+                throw new InvalidOperationException(\"The default relative expiration value must be a positive time span.\");\n+            }\n+        }\n+\n+        public void Connect() {\n+            ConnectAsync().GetAwaiter().GetResult();\n+        }\n+\n+        private bool CreateMongoClientSynchronized() {\n+            lock (_options.ConnectionString) {\n+                if (_client != null) return true;\n+                _client = new MongoClient(_options.ConnectionString);\n+                return false;\n+            }\n+        }\n+\n+        private async Task<IMongoCollection<BsonDocument>>  GetCollectionAsync() {\n+            await ConnectAsync();\n+            return _client.GetDatabase(_options.Database)\n+                .GetCollection<BsonDocument>(_options.Collection);\n+        }\n+\n+        public async Task ConnectAsync() {\n+            var connectionAlreadyEstablished = CreateMongoClientSynchronized();\n+            if (connectionAlreadyEstablished) {\n+                return;\n+            }\n+\n+            var collection = _client.GetDatabase(_options.Database)\n+                .GetCollection<BsonDocument>(_options.Collection);\n+\n+            // Create the index to expire on the \"expire at\" value\n+            await collection.Indexes.CreateOneAsync(\n+                Builders<BsonDocument>.IndexKeys.Ascending(MongoDbConstants.ExpireAt),\n+                new CreateIndexOptions {\n+                    ExpireAfter = TimeSpan.FromSeconds(0)\n+                });\n+\n+            // Create the index to expire on the \"sliding expiration\" value\n+            await collection.Indexes.CreateOneAsync(\n+                Builders<BsonDocument>.IndexKeys.Ascending(MongoDbConstants.SlidingExpireAt),\n+                new CreateIndexOptions {\n+                    ExpireAfter = TimeSpan.FromSeconds(0)\n+                });\n+        }\n+\n+        public byte[] Get(string key) {\n+            if (key == null) {\n+                throw new ArgumentNullException(nameof(key));\n+            }\n+\n+            return GetAsync(key).Result;\n+        }\n+\n+        public async Task<byte[]> GetAsync(string key) {\n+            if (key == null) {\n+                throw new ArgumentNullException(nameof(key));\n+            }\n+\n+            var filter = GetIdMatchFilter(key);\n+            var projection = Builders<BsonDocument>.Projection\n+                .Include(MongoDbConstants.CacheData)\n+                .Include(MongoDbConstants.ExpireAt)\n+                .Include(MongoDbConstants.SlidingExpireAt)\n+                .Include(MongoDbConstants.SlidingExpiration);\n+\n+            var collection = await GetCollectionAsync();\n+            var list = await collection.Find(filter).Project(projection).ToListAsync();","path":"src/AspNet.Caching.MongoDb/MongoDbCache.cs","position":null,"original_position":107,"commit_id":"67dd020a501c84f91ea87683501250bfb0350ffd","original_commit_id":"c1ac4014863be20e53f1098b0314d0556b772f6e","user":{"login":"sunsided","id":495335,"avatar_url":"https://avatars.githubusercontent.com/u/495335?v=3","gravatar_id":"","url":"https://api.github.com/users/sunsided","html_url":"https://github.com/sunsided","followers_url":"https://api.github.com/users/sunsided/followers","following_url":"https://api.github.com/users/sunsided/following{/other_user}","gists_url":"https://api.github.com/users/sunsided/gists{/gist_id}","starred_url":"https://api.github.com/users/sunsided/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunsided/subscriptions","organizations_url":"https://api.github.com/users/sunsided/orgs","repos_url":"https://api.github.com/users/sunsided/repos","events_url":"https://api.github.com/users/sunsided/events{/privacy}","received_events_url":"https://api.github.com/users/sunsided/received_events","type":"User","site_admin":false},"body":"I moved the projection construction out of the methods into private member variables to help things a bit there.\r\n\r\nSadly on my box the numbers are way off and tend to be inconsistent between runs. I tried a different approach (`FindAsync()`) only to find out that it was faster 50% of the time and slower on the rest by about the same 10%. ¯\\\\\\_(ツ)_/¯","created_at":"2015-09-27T17:57:11Z","updated_at":"2015-09-27T17:57:11Z","html_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores/pull/1#discussion_r40507167","pull_request_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1","_links":{"self":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/comments/40507167"},"html":{"href":"https://github.com/aspnet-contrib/AspNet.Caching.Stores/pull/1#discussion_r40507167"},"pull_request":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1"}}},"pull_request":{"url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1","id":45728952,"html_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores/pull/1","diff_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores/pull/1.diff","patch_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores/pull/1.patch","issue_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues/1","number":1,"state":"open","locked":false,"title":"Sunsided/mongodb","user":{"login":"sunsided","id":495335,"avatar_url":"https://avatars.githubusercontent.com/u/495335?v=3","gravatar_id":"","url":"https://api.github.com/users/sunsided","html_url":"https://github.com/sunsided","followers_url":"https://api.github.com/users/sunsided/followers","following_url":"https://api.github.com/users/sunsided/following{/other_user}","gists_url":"https://api.github.com/users/sunsided/gists{/gist_id}","starred_url":"https://api.github.com/users/sunsided/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunsided/subscriptions","organizations_url":"https://api.github.com/users/sunsided/orgs","repos_url":"https://api.github.com/users/sunsided/repos","events_url":"https://api.github.com/users/sunsided/events{/privacy}","received_events_url":"https://api.github.com/users/sunsided/received_events","type":"User","site_admin":false},"body":"Here we go, the MongoDB implementation ported from the other PR. :grin: \r\n\r\nI had to leave out unit tests because I'm unable to get the xunit runner working, some sort of framework incompatibilities. I'm not nightly enough for that it would seem. There's a sample ported from the redis one of the original repo, though.","created_at":"2015-09-22T23:15:01Z","updated_at":"2015-09-27T17:57:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1f31e80fc88d9a217948574b0b208b5b57b59903","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1/commits","review_comments_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1/comments","review_comment_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/comments{/number}","comments_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues/1/comments","statuses_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/statuses/67dd020a501c84f91ea87683501250bfb0350ffd","head":{"label":"sunsided:sunsided/mongodb","ref":"sunsided/mongodb","sha":"67dd020a501c84f91ea87683501250bfb0350ffd","user":{"login":"sunsided","id":495335,"avatar_url":"https://avatars.githubusercontent.com/u/495335?v=3","gravatar_id":"","url":"https://api.github.com/users/sunsided","html_url":"https://github.com/sunsided","followers_url":"https://api.github.com/users/sunsided/followers","following_url":"https://api.github.com/users/sunsided/following{/other_user}","gists_url":"https://api.github.com/users/sunsided/gists{/gist_id}","starred_url":"https://api.github.com/users/sunsided/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunsided/subscriptions","organizations_url":"https://api.github.com/users/sunsided/orgs","repos_url":"https://api.github.com/users/sunsided/repos","events_url":"https://api.github.com/users/sunsided/events{/privacy}","received_events_url":"https://api.github.com/users/sunsided/received_events","type":"User","site_admin":false},"repo":{"id":42963920,"name":"AspNet.Caching.Stores","full_name":"sunsided/AspNet.Caching.Stores","owner":{"login":"sunsided","id":495335,"avatar_url":"https://avatars.githubusercontent.com/u/495335?v=3","gravatar_id":"","url":"https://api.github.com/users/sunsided","html_url":"https://github.com/sunsided","followers_url":"https://api.github.com/users/sunsided/followers","following_url":"https://api.github.com/users/sunsided/following{/other_user}","gists_url":"https://api.github.com/users/sunsided/gists{/gist_id}","starred_url":"https://api.github.com/users/sunsided/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunsided/subscriptions","organizations_url":"https://api.github.com/users/sunsided/orgs","repos_url":"https://api.github.com/users/sunsided/repos","events_url":"https://api.github.com/users/sunsided/events{/privacy}","received_events_url":"https://api.github.com/users/sunsided/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/sunsided/AspNet.Caching.Stores","description":"Additional stores for ASP.NET 5 caching module","fork":true,"url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores","forks_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/forks","keys_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/teams","hooks_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/hooks","issue_events_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/issues/events{/number}","events_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/events","assignees_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/assignees{/user}","branches_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/branches{/branch}","tags_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/tags","blobs_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/git/refs{/sha}","trees_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/statuses/{sha}","languages_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/languages","stargazers_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/stargazers","contributors_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/contributors","subscribers_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/subscribers","subscription_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/subscription","commits_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/commits{/sha}","git_commits_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/git/commits{/sha}","comments_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/comments{/number}","issue_comment_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/issues/comments{/number}","contents_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/contents/{+path}","compare_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/merges","archive_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/downloads","issues_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/issues{/number}","pulls_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/pulls{/number}","milestones_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/milestones{/number}","notifications_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/labels{/name}","releases_url":"https://api.github.com/repos/sunsided/AspNet.Caching.Stores/releases{/id}","created_at":"2015-09-22T22:11:57Z","updated_at":"2015-09-27T16:20:11Z","pushed_at":"2015-09-27T17:33:49Z","git_url":"git://github.com/sunsided/AspNet.Caching.Stores.git","ssh_url":"git@github.com:sunsided/AspNet.Caching.Stores.git","clone_url":"https://github.com/sunsided/AspNet.Caching.Stores.git","svn_url":"https://github.com/sunsided/AspNet.Caching.Stores","homepage":null,"size":0,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"sunsided/mongodb"}},"base":{"label":"aspnet-contrib:dev","ref":"dev","sha":"695fa5b6f1358272d99a1da1e175e840f6883459","user":{"login":"aspnet-contrib","id":7998081,"avatar_url":"https://avatars.githubusercontent.com/u/7998081?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet-contrib","html_url":"https://github.com/aspnet-contrib","followers_url":"https://api.github.com/users/aspnet-contrib/followers","following_url":"https://api.github.com/users/aspnet-contrib/following{/other_user}","gists_url":"https://api.github.com/users/aspnet-contrib/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet-contrib/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet-contrib/subscriptions","organizations_url":"https://api.github.com/users/aspnet-contrib/orgs","repos_url":"https://api.github.com/users/aspnet-contrib/repos","events_url":"https://api.github.com/users/aspnet-contrib/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet-contrib/received_events","type":"Organization","site_admin":false},"repo":{"id":42962436,"name":"AspNet.Caching.Stores","full_name":"aspnet-contrib/AspNet.Caching.Stores","owner":{"login":"aspnet-contrib","id":7998081,"avatar_url":"https://avatars.githubusercontent.com/u/7998081?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet-contrib","html_url":"https://github.com/aspnet-contrib","followers_url":"https://api.github.com/users/aspnet-contrib/followers","following_url":"https://api.github.com/users/aspnet-contrib/following{/other_user}","gists_url":"https://api.github.com/users/aspnet-contrib/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet-contrib/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet-contrib/subscriptions","organizations_url":"https://api.github.com/users/aspnet-contrib/orgs","repos_url":"https://api.github.com/users/aspnet-contrib/repos","events_url":"https://api.github.com/users/aspnet-contrib/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet-contrib/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores","description":"Additional stores for ASP.NET 5 caching module","fork":false,"url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores","forks_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/forks","keys_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/teams","hooks_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/hooks","issue_events_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues/events{/number}","events_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/events","assignees_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/assignees{/user}","branches_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/branches{/branch}","tags_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/tags","blobs_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/git/refs{/sha}","trees_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/statuses/{sha}","languages_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/languages","stargazers_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/stargazers","contributors_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/contributors","subscribers_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/subscribers","subscription_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/subscription","commits_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/commits{/sha}","git_commits_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/git/commits{/sha}","comments_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/comments{/number}","issue_comment_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues/comments{/number}","contents_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/contents/{+path}","compare_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/merges","archive_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/downloads","issues_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues{/number}","pulls_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls{/number}","milestones_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/milestones{/number}","notifications_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/labels{/name}","releases_url":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/releases{/id}","created_at":"2015-09-22T21:38:05Z","updated_at":"2015-09-23T17:02:01Z","pushed_at":"2015-09-27T17:33:49Z","git_url":"git://github.com/aspnet-contrib/AspNet.Caching.Stores.git","ssh_url":"git@github.com:aspnet-contrib/AspNet.Caching.Stores.git","clone_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores.git","svn_url":"https://github.com/aspnet-contrib/AspNet.Caching.Stores","homepage":null,"size":0,"stargazers_count":2,"watchers_count":2,"language":"Batchfile","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":2,"default_branch":"dev"}},"_links":{"self":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1"},"html":{"href":"https://github.com/aspnet-contrib/AspNet.Caching.Stores/pull/1"},"issue":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues/1"},"comments":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/issues/1/comments"},"review_comments":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1/comments"},"review_comment":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/pulls/1/commits"},"statuses":{"href":"https://api.github.com/repos/aspnet-contrib/AspNet.Caching.Stores/statuses/67dd020a501c84f91ea87683501250bfb0350ffd"}}}}