Skip to content

Commit c8867d9

Browse files
committed
Implement Microsoft.Extensions.Caching.Distributed.IDistributedCache using ServiceStack.Redis.Core
1 parent fbc7301 commit c8867d9

File tree

8 files changed

+320
-1
lines changed

8 files changed

+320
-1
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
# ServiceStackRedisCache
1+
# ServiceStackRedisCache
2+
3+
Distributed cache implementation of Microsoft.Extensions.Caching.Distributed.IDistributedCache using ServiceStack.Redis.

ServiceStackRedisCache.sln

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio 14
3+
VisualStudioVersion = 14.0.25420.1
4+
MinimumVisualStudioVersion = 10.0.40219.1
5+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5A04042D-438D-407B-B239-0CAD6A2BD8C2}"
6+
EndProject
7+
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.Caching.ServiceStackRedis", "src\Microsoft.Extensions.Caching.ServiceStackRedis\Microsoft.Extensions.Caching.ServiceStackRedis.xproj", "{5694BC38-B266-447E-A743-DA1139FCB257}"
8+
EndProject
9+
Global
10+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
11+
Debug|Any CPU = Debug|Any CPU
12+
Release|Any CPU = Release|Any CPU
13+
EndGlobalSection
14+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
15+
{5694BC38-B266-447E-A743-DA1139FCB257}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
16+
{5694BC38-B266-447E-A743-DA1139FCB257}.Debug|Any CPU.Build.0 = Debug|Any CPU
17+
{5694BC38-B266-447E-A743-DA1139FCB257}.Release|Any CPU.ActiveCfg = Release|Any CPU
18+
{5694BC38-B266-447E-A743-DA1139FCB257}.Release|Any CPU.Build.0 = Release|Any CPU
19+
EndGlobalSection
20+
GlobalSection(SolutionProperties) = preSolution
21+
HideSolutionNode = FALSE
22+
EndGlobalSection
23+
GlobalSection(NestedProjects) = preSolution
24+
{5694BC38-B266-447E-A743-DA1139FCB257} = {5A04042D-438D-407B-B239-0CAD6A2BD8C2}
25+
EndGlobalSection
26+
EndGlobal
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
5+
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
6+
</PropertyGroup>
7+
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
8+
<PropertyGroup Label="Globals">
9+
<ProjectGuid>5694bc38-b266-447e-a743-da1139fcb257</ProjectGuid>
10+
<RootNamespace>Microsoft.Extensions.Caching.ServiceStackRedis</RootNamespace>
11+
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
12+
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
13+
</PropertyGroup>
14+
<PropertyGroup>
15+
<SchemaVersion>2.0</SchemaVersion>
16+
</PropertyGroup>
17+
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
18+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Reflection;
5+
using System.Resources;
6+
7+
[assembly: AssemblyMetadata("Serviceable", "True")]
8+
[assembly: NeutralResourcesLanguage("en-us")]
9+
[assembly: AssemblyCompany("Microsoft Corporation.")]
10+
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
11+
[assembly: AssemblyProduct("Microsoft .NET Extensions")]
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using System;
2+
using System.Text;
3+
using System.Threading.Tasks;
4+
using Microsoft.Extensions.Caching.Distributed;
5+
using Microsoft.Extensions.Options;
6+
using ServiceStack.Redis;
7+
using ServiceStack.Redis.Generic;
8+
using System.IO;
9+
10+
namespace Microsoft.Extensions.Caching.ServiceStackRedis
11+
{
12+
public class ServiceStackRedisCache : IDistributedCache, IDisposable
13+
{
14+
private readonly IRedisNativeClient _cache;
15+
private readonly ServiceStackRedisCacheOptions _options;
16+
17+
public ServiceStackRedisCache(IOptions<ServiceStackRedisCacheOptions> optionsAccessor)
18+
{
19+
if (optionsAccessor == null)
20+
{
21+
throw new ArgumentNullException(nameof(optionsAccessor));
22+
}
23+
24+
_options = optionsAccessor.Value;
25+
26+
var host = $"{_options.Password}@{_options.Host}:{_options.Port}";
27+
var manager = new RedisManagerPool(host);
28+
var client = manager.GetClient() as IRedisNativeClient;
29+
if (client == null)
30+
{
31+
throw new ArgumentNullException(nameof(client));
32+
}
33+
_cache = client;
34+
}
35+
36+
public byte[] Get(string key)
37+
{
38+
if (key == null)
39+
{
40+
throw new ArgumentNullException(nameof(key));
41+
}
42+
43+
if (_cache.Exists(key) == 1)
44+
{
45+
return _cache.Get(key);
46+
}
47+
48+
return null;
49+
}
50+
51+
public async Task<byte[]> GetAsync(string key)
52+
{
53+
return Get(key);
54+
}
55+
56+
public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
57+
{
58+
if (key == null)
59+
{
60+
throw new ArgumentNullException(nameof(key));
61+
}
62+
63+
if (value == null)
64+
{
65+
throw new ArgumentNullException(nameof(value));
66+
}
67+
68+
if (options == null)
69+
{
70+
throw new ArgumentNullException(nameof(options));
71+
}
72+
73+
var expireInSeconds = GetExpireInSeconds(options);
74+
if (expireInSeconds > 0)
75+
{
76+
_cache.SetEx(key, expireInSeconds, value);
77+
_cache.SetEx(GetExpirationKey(key), expireInSeconds, Encoding.UTF8.GetBytes(expireInSeconds.ToString()));
78+
}
79+
else
80+
{
81+
_cache.Set(key, value);
82+
}
83+
}
84+
85+
public async Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options)
86+
{
87+
Set(key, value, options);
88+
}
89+
90+
public void Refresh(string key)
91+
{
92+
if (key == null)
93+
{
94+
throw new ArgumentNullException(nameof(key));
95+
}
96+
97+
if (_cache.Exists(key) == 1)
98+
{
99+
var value = _cache.Get(key);
100+
if (value != null)
101+
{
102+
var expirationValue = _cache.Get(GetExpirationKey(key));
103+
if (expirationValue != null)
104+
{
105+
_cache.Expire(key, int.Parse(Encoding.UTF8.GetString(expirationValue)));
106+
}
107+
}
108+
}
109+
}
110+
111+
public async Task RefreshAsync(string key)
112+
{
113+
if (key == null)
114+
{
115+
throw new ArgumentNullException(nameof(key));
116+
}
117+
118+
Refresh(key);
119+
}
120+
121+
public void Remove(string key)
122+
{
123+
if (key == null)
124+
{
125+
throw new ArgumentNullException(nameof(key));
126+
}
127+
128+
_cache.Del(key);
129+
}
130+
131+
public async Task RemoveAsync(string key)
132+
{
133+
Remove(key);
134+
}
135+
136+
public void Dispose()
137+
{
138+
if (_cache != null)
139+
{
140+
_cache.Dispose();
141+
}
142+
}
143+
144+
private int GetExpireInSeconds(DistributedCacheEntryOptions options)
145+
{
146+
if (options.SlidingExpiration.HasValue)
147+
{
148+
return (int)options.SlidingExpiration.Value.TotalSeconds;
149+
}
150+
else if (options.AbsoluteExpiration.HasValue)
151+
{
152+
return (int)options.AbsoluteExpirationRelativeToNow.Value.TotalSeconds;
153+
}
154+
else
155+
{
156+
return 0;
157+
}
158+
}
159+
160+
private string GetExpirationKey(string key)
161+
{
162+
return key + $"-{nameof(DistributedCacheEntryOptions)}";
163+
}
164+
}
165+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Microsoft.Extensions.Options;
5+
6+
namespace Microsoft.Extensions.Caching.ServiceStackRedis
7+
{
8+
public class ServiceStackRedisCacheOptions : IOptions<ServiceStackRedisCacheOptions>
9+
{
10+
public string Host { get; set; }
11+
12+
public int Port { get; set; } = 6379;
13+
14+
public string Password { get; set; }
15+
16+
ServiceStackRedisCacheOptions IOptions<ServiceStackRedisCacheOptions>.Value
17+
{
18+
get { return this; }
19+
}
20+
}
21+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using Microsoft.Extensions.Caching.Distributed;
3+
using Microsoft.Extensions.Caching.ServiceStackRedis;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection.Extensions;
6+
7+
namespace Microsoft.Extensions.DependencyInjection
8+
{
9+
public static class RedisCacheServiceCollectionExtensions
10+
{
11+
/// <returns>The <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
12+
public static IServiceCollection AddDistributedServiceStackRedisCache(this IServiceCollection services, Action<ServiceStackRedisCacheOptions> setupAction)
13+
{
14+
if (services == null)
15+
{
16+
throw new ArgumentNullException(nameof(services));
17+
}
18+
19+
if (setupAction == null)
20+
{
21+
throw new ArgumentNullException(nameof(setupAction));
22+
}
23+
24+
services.AddOptions();
25+
services.Configure(setupAction);
26+
services.Add(ServiceDescriptor.Transient<IDistributedCache, ServiceStackRedisCache>());
27+
28+
return services;
29+
}
30+
31+
public static IServiceCollection AddDistributedServiceStackRedisCache(this IServiceCollection services, IConfigurationSection section)
32+
{
33+
if (services == null)
34+
{
35+
throw new ArgumentNullException(nameof(services));
36+
}
37+
38+
if (section == null)
39+
{
40+
throw new ArgumentNullException(nameof(section));
41+
}
42+
43+
services.Configure<ServiceStackRedisCacheOptions>(section);
44+
45+
services.Add(ServiceDescriptor.Transient<IDistributedCache, ServiceStackRedisCache>());
46+
47+
return services;
48+
}
49+
}
50+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"version": "1.0.0.1",
3+
"description": "Distributed cache implementation of Microsoft.Extensions.Caching.Distributed.IDistributedCache using ServiceStack.Redis.Core",
4+
"packOptions": {
5+
"repository": {
6+
"type": "git",
7+
"url": "https://github.com/cnblogs/ServiceStackRedisCache"
8+
},
9+
"tags": [
10+
"cache",
11+
"redis",
12+
"distributedcache"
13+
]
14+
},
15+
"dependencies": {
16+
"Microsoft.Extensions.Caching.Abstractions": "1.1.0",
17+
"Microsoft.Extensions.Configuration.Abstractions": "1.1.0",
18+
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
19+
"Microsoft.Extensions.Options": "1.1.0",
20+
"NETStandard.Library": "1.6.1",
21+
"ServiceStack.Redis.Core": "1.0.30"
22+
},
23+
"frameworks": {
24+
"netstandard1.6": { }
25+
}
26+
}

0 commit comments

Comments
 (0)