├── .gitignore ├── Build.cmd ├── LICENSE ├── Orleans.Storage.MongoDB.sln ├── Orleans.Storage.MongoDB ├── .nuget │ ├── NuGet.Config │ ├── NuGet.exe │ └── NuGet.targets ├── JsonConverter.cs ├── MongoDBStorage.cs ├── Orleans.Storage.MongoDB.csproj ├── Orleans.Storage.MongoDB.nuspec ├── Properties │ └── AssemblyInfo.cs └── packages.config └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | [Rr]eleases/ 14 | x64/ 15 | x86/ 16 | build/ 17 | bld/ 18 | [Bb]in/ 19 | [Oo]bj/ 20 | 21 | # Roslyn cache directories 22 | *.ide/ 23 | 24 | # MSTest test Results 25 | [Tt]est[Rr]esult*/ 26 | [Bb]uild[Ll]og.* 27 | 28 | #NUNIT 29 | *.VisualState.xml 30 | TestResult.xml 31 | 32 | # Build Results of an ATL Project 33 | [Dd]ebugPS/ 34 | [Rr]eleasePS/ 35 | dlldata.c 36 | 37 | *_i.c 38 | *_p.c 39 | *_i.h 40 | *.ilk 41 | *.meta 42 | *.obj 43 | *.pch 44 | *.pdb 45 | *.pgc 46 | *.pgd 47 | *.rsp 48 | *.sbr 49 | *.tlb 50 | *.tli 51 | *.tlh 52 | *.tmp 53 | *.tmp_proj 54 | *.log 55 | *.vspscc 56 | *.vssscc 57 | .builds 58 | *.pidb 59 | *.svclog 60 | *.scc 61 | 62 | # Chutzpah Test files 63 | _Chutzpah* 64 | 65 | # Visual C++ cache files 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opensdf 70 | *.sdf 71 | *.cachefile 72 | 73 | # Visual Studio profiler 74 | *.psess 75 | *.vsp 76 | *.vspx 77 | 78 | # TFS 2012 Local Workspace 79 | $tf/ 80 | 81 | # Guidance Automation Toolkit 82 | *.gpState 83 | 84 | # ReSharper is a .NET coding add-in 85 | _ReSharper*/ 86 | *.[Rr]e[Ss]harper 87 | *.DotSettings.user 88 | 89 | # JustCode is a .NET coding addin-in 90 | .JustCode 91 | 92 | # TeamCity is a build add-in 93 | _TeamCity* 94 | 95 | # DotCover is a Code Coverage Tool 96 | *.dotCover 97 | 98 | # NCrunch 99 | _NCrunch_* 100 | .*crunch*.local.xml 101 | 102 | # MightyMoose 103 | *.mm.* 104 | AutoTest.Net/ 105 | 106 | # Web workbench (sass) 107 | .sass-cache/ 108 | 109 | # Installshield output folder 110 | [Ee]xpress/ 111 | 112 | # DocProject is a documentation generator add-in 113 | DocProject/buildhelp/ 114 | DocProject/Help/*.HxT 115 | DocProject/Help/*.HxC 116 | DocProject/Help/*.hhc 117 | DocProject/Help/*.hhk 118 | DocProject/Help/*.hhp 119 | DocProject/Help/Html2 120 | DocProject/Help/html 121 | 122 | # Click-Once directory 123 | publish/ 124 | 125 | # Publish Web Output 126 | *.[Pp]ublish.xml 127 | *.azurePubxml 128 | # TODO: Comment the next line if you want to checkin your web deploy settings 129 | # but database connection strings (with potential passwords) will be unencrypted 130 | *.pubxml 131 | *.publishproj 132 | 133 | # NuGet Packages 134 | *.nupkg 135 | # The packages folder can be ignored because of Package Restore 136 | **/packages/* 137 | # except build/, which is used as an MSBuild target. 138 | !**/packages/build/ 139 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 140 | #!**/packages/repositories.config 141 | 142 | # Windows Azure Build Output 143 | csx/ 144 | *.build.csdef 145 | 146 | # Windows Store app package directory 147 | AppPackages/ 148 | 149 | # Others 150 | sql/ 151 | *.Cache 152 | ClientBin/ 153 | [Ss]tyle[Cc]op.* 154 | ~$* 155 | *~ 156 | *.dbmdl 157 | *.dbproj.schemaview 158 | *.pfx 159 | *.publishsettings 160 | node_modules/ 161 | 162 | # RIA/Silverlight projects 163 | Generated_Code/ 164 | 165 | # Backup & report files from converting an old project file 166 | # to a newer Visual Studio version. Backup files are not needed, 167 | # because we have git ;-) 168 | _UpgradeReport_Files/ 169 | Backup*/ 170 | UpgradeLog*.XML 171 | UpgradeLog*.htm 172 | 173 | # SQL Server files 174 | *.mdf 175 | *.ldf 176 | 177 | # Business Intelligence projects 178 | *.rdl.data 179 | *.bim.layout 180 | *.bim_*.settings 181 | 182 | # Microsoft Fakes 183 | FakesAssemblies/ 184 | -------------------------------------------------------------------------------- /Build.cmd: -------------------------------------------------------------------------------- 1 | @REM NOTE: This script must be run from a Visual Studio command prompt window 2 | 3 | @setlocal 4 | @ECHO off 5 | 6 | SET CMDHOME=%~dp0. 7 | if "%FrameworkDir%" == "" set FrameworkDir=%WINDIR%\Microsoft.NET\Framework 8 | if "%FrameworkVersion%" == "" set FrameworkVersion=v4.0.30319 9 | 10 | SET MSBUILDEXEDIR=%FrameworkDir%\%FrameworkVersion% 11 | SET MSBUILDEXE=%MSBUILDEXEDIR%\MSBuild.exe 12 | SET NUGETEXE=NUGET.exe 13 | 14 | set PROJ=%CMDHOME%\Orleans.Storage.MongoDB.sln 15 | 16 | @echo ===== Building %PROJ% ===== 17 | 18 | @echo Build Debug ============================== 19 | 20 | SET CONFIGURATION=Debug 21 | 22 | "%MSBUILDEXE%" /p:Configuration=%CONFIGURATION% "%PROJ%" 23 | @if ERRORLEVEL 1 GOTO :ErrorStop 24 | @echo BUILD ok for %CONFIGURATION% %PROJ% 25 | 26 | @echo Build Release ============================ 27 | 28 | SET CONFIGURATION=Release 29 | 30 | "%MSBUILDEXE%" /p:Configuration=%CONFIGURATION% "%PROJ%" 31 | @if ERRORLEVEL 1 GOTO :ErrorStop 32 | @echo BUILD ok for %CONFIGURATION% %PROJ% 33 | @echo ===== wait for generate nupkg ===== 34 | del %CMDHOME%\*.nupkg 35 | "%NUGETEXE%" pack Orleans.Storage.MongoDB\Orleans.Storage.MongoDB.csproj -Prop Configuration=%CONFIGURATION% 36 | @echo ===== wait for generate nupkg ===== 37 | "%NUGETEXE%" push *.nupkg -s http://10.0.0.200/ 38 | @echo ===== press any key ... ===== 39 | pause -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 涛 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orleans.Storage.MongoDB", "Orleans.Storage.MongoDB\Orleans.Storage.MongoDB.csproj", "{57A79748-F261-4098-B59B-3B0050C4C7C4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {57A79748-F261-4098-B59B-3B0050C4C7C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {57A79748-F261-4098-B59B-3B0050C4C7C4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {57A79748-F261-4098-B59B-3B0050C4C7C4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {57A79748-F261-4098-B59B-3B0050C4C7C4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/witterlee/Orleans.Storage.MongoDB/1bad271c34df24ed9d69bb5172797b6b7c172704/Orleans.Storage.MongoDB/.nuget/NuGet.exe -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | 32 | 33 | 34 | 35 | $(SolutionDir).nuget 36 | 37 | 38 | 39 | packages.$(MSBuildProjectName.Replace(' ', '_')).config 40 | 41 | 42 | 43 | 44 | 45 | $(PackagesProjectConfig) 46 | 47 | 48 | 49 | 50 | packages.config 51 | 52 | 53 | 54 | 55 | 56 | 57 | $(NuGetToolsPath)\NuGet.exe 58 | @(PackageSource) 59 | 60 | "$(NuGetExePath)" 61 | mono --runtime=v4.0.30319 $(NuGetExePath) 62 | 63 | $(TargetDir.Trim('\\')) 64 | 65 | -RequireConsent 66 | -NonInteractive 67 | 68 | "$(SolutionDir) " 69 | "$(SolutionDir)" 70 | 71 | 72 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) 73 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols 74 | 75 | 76 | 77 | RestorePackages; 78 | $(BuildDependsOn); 79 | 80 | 81 | 82 | 83 | $(BuildDependsOn); 84 | BuildPackage; 85 | 86 | 87 | 88 | 89 | 90 | 91 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | 113 | 115 | 116 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/JsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Newtonsoft.Json; 8 | using Newtonsoft.Json.Converters; 9 | 10 | namespace Orleans.Storage.MongoDB 11 | { 12 | public class UnixDateTimeConverter : DateTimeConverterBase 13 | { 14 | private DateTime initialTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); 15 | 16 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 17 | { 18 | if (value is DateTime) 19 | { 20 | DateTime currentValue = ((DateTime)value).ToUniversalTime(); 21 | TimeSpan span = currentValue - initialTime; 22 | writer.WriteValue(span.TotalSeconds); 23 | } 24 | else 25 | throw new ArgumentException("Must provide a valid datetime struct", "value"); 26 | 27 | } 28 | 29 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 30 | { 31 | try 32 | { 33 | long ticks = Convert.ToInt64(reader.Value); 34 | return initialTime.AddSeconds(ticks); 35 | } 36 | catch { } 37 | 38 | try 39 | { 40 | return Convert.ToDateTime(reader.Value.ToString()); 41 | } 42 | catch { } 43 | 44 | if (objectType == typeof(DateTime?)) return null; 45 | else 46 | throw new Exception("can not read value from json"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/MongoDBStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using MongoDB.Bson; 5 | using MongoDB.Bson.Serialization; 6 | using MongoDB.Driver; 7 | using Newtonsoft.Json; 8 | using Orleans.Providers; 9 | using Orleans.Runtime; 10 | using MongoDBBson = MongoDB.Bson; 11 | using System.Collections.Concurrent; 12 | using System.Collections.Generic; 13 | 14 | 15 | namespace Orleans.Storage.MongoDB 16 | { 17 | /// 18 | /// A MongoDB storage provider. 19 | /// 20 | /// 21 | /// The storage provider should be included in a deployment by adding this line to the Orleans server configuration file: 22 | /// 23 | /// 24 | /// and this line to any grain that uses it: 25 | /// 26 | /// [StorageProvider(ProviderName = "MongoDBStore")] 27 | /// 28 | /// The name 'MongoDBStore' is an arbitrary choice. 29 | /// 30 | public class MongoDBStorage : IStorageProvider 31 | { 32 | private const string DATA_CONNECTION_STRING = "ConnectionString"; 33 | private const string DATABASE_NAME_PROPERTY = "Database"; 34 | private const string DELETE_ON_CLEAR_PROPERTY = "DeleteStateOnClear"; 35 | private const string USE_GUID_AS_STORAGE_KEY = "UseGuidAsStorageKey"; 36 | private const string USE_ONE_COLLECTION = "UseOneCollection"; 37 | 38 | /// 39 | /// Logger object 40 | /// 41 | public Logger Log { get; protected set; } 42 | /// 43 | /// Database name 44 | /// 45 | public string Name { get; set; } 46 | 47 | /// 48 | /// Database connection string 49 | /// 50 | public string ConnectionString { get; set; } 51 | 52 | /// 53 | /// Database name 54 | /// 55 | public string Database { get; set; } 56 | 57 | /// 58 | /// use grain's guid key as the storage key,default is true 59 | /// default is true,use guid as the storeage key, else false use like GrainReference=40011c8c7bcc4141b3569464533a06a203ffffff9c20d2b7 as the key 60 | /// 61 | public bool UseGuidAsStorageKey { get; protected set; } 62 | 63 | /// 64 | /// Initializes the storage provider. 65 | /// 66 | /// The name of this provider instance. 67 | /// A Orleans runtime object managing all storage providers. 68 | /// Configuration info for this provider instance. 69 | /// Completion promise for this operation. 70 | public Task Init(string name, IProviderRuntime providerRuntime, IProviderConfiguration config) 71 | { 72 | Log = providerRuntime.GetLogger(this.GetType().FullName); 73 | 74 | this.Name = name; 75 | 76 | if (!config.Properties.ContainsKey(DATA_CONNECTION_STRING) || 77 | !config.Properties.ContainsKey(DATABASE_NAME_PROPERTY)) 78 | { 79 | throw new ArgumentException("ConnectionString Or Database property not set"); 80 | } 81 | 82 | this.ConnectionString = config.Properties[DATA_CONNECTION_STRING]; 83 | this.Database = config.Properties[DATABASE_NAME_PROPERTY]; 84 | 85 | this.UseGuidAsStorageKey = !config.Properties.ContainsKey(USE_GUID_AS_STORAGE_KEY) || 86 | "true".Equals(config.Properties[USE_GUID_AS_STORAGE_KEY], 87 | StringComparison.OrdinalIgnoreCase); 88 | 89 | DataManager = new GrainStateMongoDataManager(Database, ConnectionString); 90 | 91 | return TaskDone.Done; 92 | } 93 | private GrainStateMongoDataManager DataManager { get; set; } 94 | /// 95 | /// Closes the storage provider during silo shutdown. 96 | /// 97 | /// Completion promise for this operation. 98 | public Task Close() 99 | { 100 | DataManager = null; 101 | return TaskDone.Done; 102 | } 103 | 104 | /// 105 | /// Reads persisted state from the backing store and deserializes it into the the target 106 | /// grain state object. 107 | /// 108 | /// A string holding the name of the grain class. 109 | /// Represents the long-lived identity of the grain. 110 | /// A reference to an object to hold the persisted state of the grain. 111 | /// Completion promise for this operation. 112 | public async Task ReadStateAsync(string grainType, GrainReference grainReference, GrainState grainState) 113 | { 114 | if (DataManager == null) throw new ArgumentException("DataManager property not initialized"); 115 | 116 | string extendKey; 117 | 118 | var key = this.UseGuidAsStorageKey ? grainReference.GetPrimaryKey(out extendKey).ToString() : grainReference.ToKeyString(); 119 | 120 | var entityData = await DataManager.ReadAsync(grainType, key); 121 | 122 | if (!string.IsNullOrEmpty(entityData)) 123 | { 124 | ConvertFromStorageFormat(grainState, entityData); 125 | } 126 | } 127 | 128 | /// 129 | /// Writes the persisted state from a grain state object into its backing store. 130 | /// 131 | /// A string holding the name of the grain class. 132 | /// Represents the long-lived identity of the grain. 133 | /// A reference to an object holding the persisted state of the grain. 134 | /// Completion promise for this operation. 135 | public Task WriteStateAsync(string grainType, GrainReference grainReference, GrainState grainState) 136 | { 137 | if (DataManager == null) throw new ArgumentException("DataManager property not initialized"); 138 | 139 | string extendKey; 140 | 141 | var key = this.UseGuidAsStorageKey ? grainReference.GetPrimaryKey(out extendKey).ToString() : grainReference.ToKeyString(); 142 | 143 | return DataManager.WriteAsync(grainType, key, grainState); 144 | } 145 | 146 | /// 147 | /// Removes grain state from its backing store, if found. 148 | /// 149 | /// A string holding the name of the grain class. 150 | /// Represents the long-lived identity of the grain. 151 | /// An object holding the persisted state of the grain. 152 | /// 153 | public Task ClearStateAsync(string grainType, GrainReference grainReference, GrainState grainState) 154 | { 155 | if (DataManager == null) throw new ArgumentException("DataManager property not initialized"); 156 | 157 | string extendKey; 158 | 159 | var key = this.UseGuidAsStorageKey ? grainReference.GetPrimaryKey(out extendKey).ToString() : grainReference.ToKeyString(); 160 | 161 | return DataManager.DeleteAsync(grainType, key); 162 | } 163 | 164 | /// 165 | /// Constructs a grain state instance by deserializing a JSON document. 166 | /// 167 | /// Grain state to be populated for storage. 168 | /// JSON storage format representaiton of the grain state. 169 | protected static void ConvertFromStorageFormat(GrainState grainState, string entityData) 170 | { 171 | object data = JsonConvert.DeserializeObject(entityData, grainState.GetType(), GrainStateMongoDataManager.JsonSetting); 172 | var dict = ((GrainState)data).AsDictionary(); 173 | grainState.SetAll(dict); 174 | } 175 | } 176 | 177 | /// 178 | /// Interfaces with a MongoDB database driver. 179 | /// 180 | internal class GrainStateMongoDataManager 181 | { 182 | private static ConcurrentDictionary registerIndexMap = new ConcurrentDictionary(); 183 | 184 | public static JsonSerializerSettings JsonSetting = new JsonSerializerSettings() 185 | { 186 | NullValueHandling = NullValueHandling.Ignore, 187 | Converters = new List() { new UnixDateTimeConverter() } 188 | }; 189 | /// 190 | /// Constructor 191 | /// 192 | /// A database name. 193 | /// A MongoDB database connection string. 194 | public GrainStateMongoDataManager(string databaseName, string connectionString) 195 | { 196 | MongoClient client = new MongoClient(connectionString); 197 | _database = client.GetDatabase(databaseName); 198 | } 199 | 200 | /// 201 | /// Deletes a file representing a grain state object. 202 | /// 203 | /// The type of the grain state object. 204 | /// The grain id string. 205 | /// Completion promise for this operation. 206 | public Task DeleteAsync(string collectionName, string key) 207 | { 208 | var collection = _database.GetCollection(collectionName); 209 | if (collection == null) 210 | return TaskDone.Done; 211 | 212 | var query = BsonDocument.Parse("{key:\"" + key + "\"}"); 213 | collection.FindOneAndDeleteAsync(query); 214 | 215 | return TaskDone.Done; 216 | } 217 | 218 | /// 219 | /// Reads a file representing a grain state object. 220 | /// 221 | /// The type of the grain state object. 222 | /// The grain id string. 223 | /// Completion promise for this operation. 224 | public async Task ReadAsync(string collectionName, string key) 225 | { 226 | var collection = await GetCollection(collectionName); 227 | 228 | if (collection == null) 229 | return null; 230 | 231 | var query = BsonDocument.Parse("{__key:\"" + key + "\"}"); 232 | using (var cursor = await collection.FindAsync(query)) 233 | { 234 | var existing = (await cursor.ToListAsync()).FirstOrDefault(); 235 | 236 | if (existing == null) 237 | return null; 238 | 239 | existing.Remove("_id"); 240 | existing.Remove("__key"); 241 | 242 | return existing.ToJson(); 243 | } 244 | } 245 | 246 | /// 247 | /// Writes a file representing a grain state object. 248 | /// 249 | /// The type of the grain state object. 250 | /// The grain id string. 251 | /// The grain state data to be stored./ 252 | /// Completion promise for this operation. 253 | public async Task WriteAsync(string collectionName, string key, GrainState entityData) 254 | { 255 | var collection = await GetCollection(collectionName); 256 | 257 | var query = BsonDocument.Parse("{__key:\"" + key + "\"}"); 258 | 259 | using (var cursor = await collection.FindAsync(query)) 260 | { 261 | var existing = (await cursor.ToListAsync()).FirstOrDefault(); 262 | 263 | var json = JsonConvert.SerializeObject(entityData, JsonSetting); 264 | 265 | var doc = BsonSerializer.Deserialize(json); 266 | doc["__key"] = key; 267 | 268 | if (existing != null) 269 | { 270 | doc["_id"] = existing["_id"]; 271 | await collection.ReplaceOneAsync(query, doc); 272 | 273 | } 274 | else 275 | { 276 | await collection.InsertOneAsync(doc); 277 | } 278 | } 279 | } 280 | 281 | private async Task> GetCollection(string name) 282 | { 283 | var collection = _database.GetCollection(name); 284 | 285 | if (!registerIndexMap.ContainsKey(name)) 286 | { 287 | using (var cursor = await collection.Indexes.ListAsync()) 288 | { 289 | var indexes = await cursor.ToListAsync(); 290 | if (indexes.Count(index => index["name"] == "__key_1") == 0) 291 | { 292 | var keys = Builders.IndexKeys.Ascending("__key"); 293 | await collection.Indexes.CreateOneAsync(keys, 294 | new CreateIndexOptions() { Unique = true, Version = 1 }); 295 | } 296 | registerIndexMap.TryAdd(name, true); 297 | } 298 | } 299 | return collection; 300 | } 301 | 302 | private readonly IMongoDatabase _database; 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/Orleans.Storage.MongoDB.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {57A79748-F261-4098-B59B-3B0050C4C7C4} 8 | Library 9 | Properties 10 | Orleans.Storage.MongoDB 11 | Orleans.Storage.MongoDB 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | False 35 | ..\packages\MongoDB.Bson.2.0.1\lib\net45\MongoDB.Bson.dll 36 | 37 | 38 | False 39 | ..\packages\MongoDB.Driver.2.0.1\lib\net45\MongoDB.Driver.dll 40 | 41 | 42 | False 43 | ..\packages\MongoDB.Driver.Core.2.0.1\lib\net45\MongoDB.Driver.Core.dll 44 | 45 | 46 | False 47 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll 48 | 49 | 50 | ..\packages\Microsoft.Orleans.Core.1.0.10\lib\net45\Orleans.dll 51 | True 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 84 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/Orleans.Storage.MongoDB.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | https://github.com/weitaolee/Orleans.Storage.MongoDB/blob/master/LICENSE 10 | https://github.com/weitaolee/Orleans.Storage.MongoDB 11 | false 12 | $description$ 13 | First Publish 14 | Copyright 2015 15 | Orleans Storage MongoDB 16 | 17 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Orleans.Storage.MongoDB")] 9 | [assembly: AssemblyDescription("Orleans MongoDB Storage Provider")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Orleans.Storage.MongoDB")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("6b263fbc-443a-40c4-8723-e5599cae92ce")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.*")] 36 | -------------------------------------------------------------------------------- /Orleans.Storage.MongoDB/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Orleans.Storage.MongoDB 2 | Orleans Storage MongoDB Provider 3 | 4 | ## USE CASE 5 | 6 | ###### 1. ServerConfiguration.xml 7 | ```xml 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ``` 19 | 20 | If you have MongoDB running on your local machine, then this should work with no modifications. 21 | 22 | If you have MongoDB running on a remote machine, then you will have to update "localhost" to match the machine name. 23 | 24 | ###### 2. Code 25 | ```csharp 26 | [StorageProvider(ProviderName = "MongoDBStorage")] 27 | public class BankAccount : IGrain,IBankAccount 28 | { 29 | } 30 | ``` 31 | --------------------------------------------------------------------------------