PageRenderTime 30ms CodeModel.GetById 2ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/MVVMSidekick/MVVMSidekick.Shared/Storages.cs

https://github.com/zoujuny/MVVM-Sidekick
C# | 824 lines | 568 code | 222 blank | 34 comment | 17 complexity | 988c77132f24bd03135a7641bca95f0f MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Text;
  5using System.ComponentModel;
  6using System.Linq.Expressions;
  7using System.Runtime.Serialization;
  8using System.Reflection;
  9using System.Threading.Tasks;
 10using System.Threading;
 11using System.Windows.Input;
 12using MVVMSidekick.ViewModels;
 13using MVVMSidekick.Commands;
 14using System.Runtime.CompilerServices;
 15using MVVMSidekick.Reactive;
 16using System.Reactive.Linq;
 17using System.Reactive.Subjects;
 18using System.Reactive;
 19using MVVMSidekick.EventRouting;
 20using MVVMSidekick.Utilities;
 21using System.Collections.ObjectModel;
 22using System.Collections.Specialized;
 23using System.IO;
 24using System.Collections;
 25
 26#if NETFX_CORE
 27using Windows.UI.Xaml;
 28using Windows.UI.Xaml.Data;
 29using Windows.UI.Xaml.Controls;
 30using System.Collections.Concurrent;
 31using Windows.UI.Xaml.Navigation;
 32
 33using Windows.UI.Xaml.Controls.Primitives;
 34using Windows.Storage;
 35
 36#elif WPF
 37using System.Windows;
 38using System.Windows.Controls;
 39using System.Windows.Data;
 40using System.Collections.Concurrent;
 41using System.Windows.Navigation;
 42
 43using MVVMSidekick.Views;
 44using System.Windows.Controls.Primitives;
 45
 46
 47#elif SILVERLIGHT_5||SILVERLIGHT_4
 48using System.Windows;
 49using System.Windows.Controls;
 50using System.Windows.Data;
 51using System.Windows.Navigation;
 52using System.Windows.Controls.Primitives;
 53using System.IO.IsolatedStorage;
 54#elif WINDOWS_PHONE_8||WINDOWS_PHONE_7
 55using System.Windows;
 56using System.Windows.Controls;
 57using Microsoft.Phone.Controls;
 58using System.Windows.Data;
 59using System.Windows.Navigation;
 60using System.Windows.Controls.Primitives;
 61using System.IO.IsolatedStorage;
 62#endif
 63
 64
 65namespace MVVMSidekick
 66{
 67
 68    namespace Storages
 69    {
 70        /// <summary>
 71        /// <para>Simple storage interface, for persistence.</para>
 72        /// <para>简单的持久化存储类型接口</para>
 73        /// </summary>
 74        /// <typeparam name="T">
 75        /// <para>The Type needs to be save/load</para>
 76        /// <para>需要存取的类型</para>
 77        /// </typeparam>
 78        public interface IStorage<T>
 79        {
 80            /// <summary>
 81            /// <para>Ignore current changes, load from storage</para>
 82            /// <para>忽略当前值的变化,从持久化存储中读取</para>
 83            /// </summary>
 84            /// <returns>Async Task</returns>
 85            System.Threading.Tasks.Task<T> RefreshAsync();
 86            /// <summary>
 87            /// <para>Save current changes to storage</para>
 88            /// <para>把当前值的变化写入持久化存储中</para>
 89            /// </summary>
 90            /// <returns>Async Task</returns>
 91            System.Threading.Tasks.Task SaveAsync(T value);
 92
 93            /// <summary>
 94            /// <para>Current value</para>
 95            /// <para>当前值</para>
 96            /// </summary>
 97            T Value { get; }
 98        }
 99
100
101
102
103        /// <summary>
104        /// <para>Simple storage interface, for persistence.</para>
105        /// <para>简单的持久化存储类型接口</para>
106        /// </summary>
107        /// <typeparam name="TToken">
108        /// <para>The Token/token Type needs to be save/load</para>
109        /// <para>需要存取的凭据类型</para>
110        /// </typeparam>
111        /// <typeparam name="TValue">
112        /// <para>The Value Type needs to be save/load</para>
113        /// <para>需要存取的类型</para>
114        /// </typeparam>
115        public interface IStorageHub<TToken, TValue>
116        {
117
118            System.Threading.Tasks.Task<TValue> LoadAsync(TToken token, bool forceRefresh);
119
120            System.Threading.Tasks.Task SaveAsync(TToken token, TValue value);
121
122        }
123
124        public class StorageHub<TToken, TValue> : IStorageHub<TToken, TValue>
125        {
126            public StorageHub(Func<TToken, IStorage<TValue>> storageFactory, Func<Task<TToken[]>> storageTokensSelector = null)
127            {
128                _storageFactory = storageFactory;
129                _storageTokensSelector = storageTokensSelector;
130            }
131
132
133            IStorage<TValue> GetOrCreatStorage(TToken token)
134            {
135
136                return _dic.GetOrAdd(token, _storageFactory);
137            }
138
139
140            Func<TToken, IStorage<TValue>> _storageFactory;
141            Func<Task<TToken[]>> _storageTokensSelector;
142
143            public async Task<TToken[]> GetExistsTokens()
144            {
145                if (_storageTokensSelector != null)
146                {
147                    return await _storageTokensSelector();
148                }
149                else
150                {
151                    throw new NotImplementedException("Current storageTokensSelector is not set in constructor. ");
152
153                }
154
155            }
156
157
158            ConcurrentDictionary<TToken, IStorage<TValue>> _dic = new ConcurrentDictionary<TToken, IStorage<TValue>>();
159
160            public async Task<TValue> LoadAsync(TToken token, bool forceRefresh)
161            {
162                var storage = GetOrCreatStorage(token);
163                if (forceRefresh)
164                {
165                    return await storage.RefreshAsync();
166                }
167                else
168                {
169                    return storage.Value;
170                }
171
172            }
173
174            public async Task SaveAsync(TToken token, TValue value)
175            {
176                var storage = GetOrCreatStorage(token);
177
178
179                await storage.SaveAsync(value);
180
181            }
182
183            #region Json
184
185#if NETFX_CORE
186            public static StorageHub<TToken, TValue> CreateJsonDatacontractFileStorageHub(
187                Func<TToken, string> fileNameFactory,
188                StorageFolder folder = null,
189                Func<Task<TToken[]>> storageTokensSelector = null)
190            {
191
192
193
194                var hub = new JsonDataContractStreamStorageHub<TToken, TValue>(
195                   async (tp, tk) =>
196                   {
197                       folder = folder ?? Windows.Storage.ApplicationData.Current.LocalFolder;
198                       switch (tp)
199                       {
200                           case StreamOpenType.Read:
201                               {
202                                   var file = await folder.CreateFileAsync(fileNameFactory(tk), CreationCollisionOption.OpenIfExists);
203
204                                   return await file.OpenStreamForReadAsync();
205                               }
206
207                           case StreamOpenType.Write:
208                               {
209                                   var file = await folder.CreateFileAsync(fileNameFactory(tk), CreationCollisionOption.ReplaceExisting);
210
211                                   return await file.OpenStreamForWriteAsync();
212                               }
213
214                           default:
215                               return null;
216
217                       }
218
219                   },
220                storageTokensSelector
221                );
222                return hub;
223
224            }
225
226#elif WPF
227            public static StorageHub<TToken, TValue> CreateJsonDatacontractFileStorageHub(
228                Func<TToken, string> fileNameFactory,
229                string folder = null,
230                Func<Task<TToken[]>> storageTokensSelector = null)
231            {
232
233
234
235                var hub = new JsonDataContractStreamStorageHub<TToken, TValue>(
236                   async (tp, tk) =>
237                   {
238                       folder = folder ?? Environment.CurrentDirectory;
239                       var filepath = Path.Combine(folder, fileNameFactory(tk));
240
241
242                       switch (tp)
243                       {
244                           case StreamOpenType.Read:
245
246                               return await TaskExHelper.FromResult(new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read));
247
248                           case StreamOpenType.Write:
249                               return await TaskExHelper.FromResult(new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
250
251
252                           default:
253                               return null;
254
255                       }
256
257                   },
258                   storageTokensSelector
259                );
260                return hub;
261
262            }
263#elif WINDOWS_PHONE_8|| WINDOWS_PHONE_7
264              public static StorageHub<TToken, TValue> CreateJsonDatacontractIsolatedStorageHub(
265                Func<TToken, string> fileNameFactory,
266                IsolatedStorageFile folder = null,
267                Func<Task<TToken[]>> storageTokensSelector = null)
268        {
269
270
271 
272            var hub = new JsonDataContractStreamStorageHub<TToken, TValue>(
273               async (tp, tk) =>
274               {
275               
276                   folder = folder ?? IsolatedStorageFile.GetUserStoreForApplication();
277
278        
279                  
280                   var filepath=fileNameFactory(tk);
281                   switch (tp)
282                   {
283                       case StreamOpenType.Read:
284
285                           return folder.OpenFile(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
286
287                       case StreamOpenType.Write:
288                           return folder.OpenFile(filepath, FileMode.Create, FileAccess.Write, FileShare.None);
289
290
291                       default:
292                           return null;
293
294                   }
295
296               },
297                storageTokensSelector
298            );
299            return hub;
300
301        }
302
303#elif SILVERLIGHT_5
304            public static StorageHub<TToken, TValue> CreateJsonDatacontractFileStorageHub(
305                Func<TToken, string> fileNameFactory,
306                string folder = null,
307                Func<Task<TToken[]>> storageTokensSelector = null)
308            {
309
310
311
312                var hub = new JsonDataContractStreamStorageHub<TToken, TValue>(
313                   async (tp, tk) =>
314                   {
315                       folder = folder ?? Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
316                       var filepath = Path.Combine(folder, fileNameFactory(tk));
317
318                       switch (tp)
319                       {
320                           case StreamOpenType.Read:
321
322                               return new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
323
324                           case StreamOpenType.Write:
325                               return new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
326
327
328                           default:
329                               return null;
330
331                       }
332
333                   },
334                    storageTokensSelector 
335                );
336                return hub;
337
338            }
339    
340        public static StorageHub<TToken, TValue> CreateJsonDatacontractIsolatedStorageHub(
341                Func<TToken, string> fileNameFactory,
342                IsolatedStorageFile folder = null,
343                Func<Task<TToken[]>> storageTokensSelector = null)
344        {
345
346
347 
348            var hub = new JsonDataContractStreamStorageHub<TToken, TValue>(
349               async (tp, tk) =>
350               {
351                   await TaskEx.Yield();
352                   folder = folder ?? IsolatedStorageFile.GetUserStoreForApplication();
353
354        
355                  
356                   var filepath=fileNameFactory(tk);
357                   switch (tp)
358                   {
359                       case StreamOpenType.Read:
360
361                           return folder.OpenFile(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
362
363                       case StreamOpenType.Write:
364                           return folder.OpenFile(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
365
366
367                       default:
368                           return null;
369
370                   }
371
372               },
373                storageTokensSelector
374            );
375            return hub;
376
377        }
378
379#endif
380            #endregion
381
382
383            #region Xml
384
385#if NETFX_CORE
386            public static StorageHub<TToken, TValue> CreateXmlDatacontractFileStorageHub(
387                Func<TToken, string> fileNameFactory,
388                StorageFolder folder = null,
389                Func<Task<TToken[]>> storageTokensSelector = null)
390            {
391
392
393
394                var hub = new XmlDataContractStreamStorageHub<TToken, TValue>(
395                   async (tp, tk) =>
396                   {
397                       folder = folder ?? Windows.Storage.ApplicationData.Current.LocalFolder;
398                       switch (tp)
399                       {
400                           case StreamOpenType.Read:
401                               {
402                                   var file = await folder.CreateFileAsync(fileNameFactory(tk), CreationCollisionOption.OpenIfExists);
403
404                                   return await file.OpenStreamForReadAsync();
405                               }
406
407                           case StreamOpenType.Write:
408                               {
409                                   var file = await folder.CreateFileAsync(fileNameFactory(tk), CreationCollisionOption.ReplaceExisting);
410
411                                   return await file.OpenStreamForWriteAsync();
412                               }
413
414                           default:
415                               return null;
416
417                       }
418
419                   },
420                storageTokensSelector
421                );
422                return hub;
423
424            }
425
426#elif WPF
427            public static StorageHub<TToken, TValue> CreateXmlDatacontractFileStorageHub(
428                Func<TToken, string> fileNameFactory,
429                string folder = null,
430                Func<Task<TToken[]>> storageTokensSelector = null)
431            {
432
433
434
435                var hub = new XmlDataContractStreamStorageHub<TToken, TValue>(
436                   async (tp, tk) =>
437                   {
438                       folder = folder ?? Environment.CurrentDirectory;
439                       var filepath = Path.Combine(folder, fileNameFactory(tk));
440
441
442                       switch (tp)
443                       {
444                           case StreamOpenType.Read:
445
446                               return await TaskExHelper.FromResult(new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read));
447
448                           case StreamOpenType.Write:
449                               return await TaskExHelper.FromResult(new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
450
451
452                           default:
453                               return null;
454
455                       }
456
457                   },
458                   storageTokensSelector
459                );
460                return hub;
461
462            }
463#elif WINDOWS_PHONE_8|| WINDOWS_PHONE_7
464              public static StorageHub<TToken, TValue> CreateXmlDatacontractIsolatedStorageHub(
465                Func<TToken, string> fileNameFactory,
466                IsolatedStorageFile folder = null,
467                Func<Task<TToken[]>> storageTokensSelector = null)
468        {
469
470
471 
472            var hub = new XmlDataContractStreamStorageHub<TToken, TValue>(
473               async (tp, tk) =>
474               {
475               
476                   folder = folder ?? IsolatedStorageFile.GetUserStoreForApplication();
477
478        
479                  
480                   var filepath=fileNameFactory(tk);
481                   switch (tp)
482                   {
483                       case StreamOpenType.Read:
484
485                           return folder.OpenFile(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
486
487                       case StreamOpenType.Write:
488
489                           return folder.OpenFile(filepath, FileMode.Create, FileAccess.Write, FileShare.None);
490
491
492                       default:
493                           return null;
494
495                   }
496
497               },
498                storageTokensSelector
499            );
500            return hub;
501
502        }
503
504#elif SILVERLIGHT_5
505            public static StorageHub<TToken, TValue> CreateXmlDatacontractFileStorageHub(
506                Func<TToken, string> fileNameFactory,
507                string folder = null,
508                Func<Task<TToken[]>> storageTokensSelector = null)
509            {
510
511
512
513                var hub = new XmlDataContractStreamStorageHub<TToken, TValue>(
514                   async (tp, tk) =>
515                   {
516                       folder = folder ?? Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
517                       var filepath = Path.Combine(folder, fileNameFactory(tk));
518
519                       switch (tp)
520                       {
521                           case StreamOpenType.Read:
522
523                               return new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
524
525                           case StreamOpenType.Write:
526                               return new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
527
528
529                           default:
530                               return null;
531
532                       }
533
534                   },
535                    storageTokensSelector 
536                );
537                return hub;
538
539            }
540    
541        public static StorageHub<TToken, TValue> CreateXmlDatacontractIsolatedStorageHub(
542                Func<TToken, string> fileNameFactory,
543                IsolatedStorageFile folder = null,
544                Func<Task<TToken[]>> storageTokensSelector = null)
545        {
546
547
548 
549            var hub = new XmlDataContractStreamStorageHub<TToken, TValue>(
550               async (tp, tk) =>
551               {
552                   await TaskEx.Yield();
553                   folder = folder ?? IsolatedStorageFile.GetUserStoreForApplication();
554
555        
556                  
557                   var filepath=fileNameFactory(tk);
558                   switch (tp)
559                   {
560                       case StreamOpenType.Read:
561
562                           return folder.OpenFile(filepath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read);
563
564                       case StreamOpenType.Write:
565                           return folder.OpenFile(filepath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
566
567
568                       default:
569                           return null;
570
571                   }
572
573               },
574                storageTokensSelector
575            );
576            return hub;
577
578        }
579
580#endif
581
582            #endregion
583
584        }
585
586
587        public enum StreamOpenType
588        {
589            Read,
590            Write
591        }
592
593        public class JsonDataContractStreamStorageHub<TToken, TValue> : StorageHub<TToken, TValue>
594        {
595            public JsonDataContractStreamStorageHub(Func<StreamOpenType, TToken, Task<Stream>> streamOpener, Func<Task<TToken[]>> storageTokensSelector = null)
596                : base
597                    (tk => new JsonDataContractStreamStorage<TValue>(async tp => await streamOpener(tp, tk)), storageTokensSelector)
598            {
599
600
601            }
602        }
603
604
605        public class JsonDataContractStreamStorage<TValue> : IStorage<TValue>
606        {
607#if NET45
608            ConcurrentExclusiveSchedulerPair _sch = new ConcurrentExclusiveSchedulerPair();
609#else
610            TaskScheduler _sch = new LimitedConcurrencyLevelTaskScheduler(1);
611#endif
612            public JsonDataContractStreamStorage(Func<StreamOpenType, Task<Stream>> streamOpener, params Type[] knownTypes)
613            {
614                _streamOpener = streamOpener;
615                _knownTypes = knownTypes;
616            }
617
618            Func<StreamOpenType, Task<Stream>> _streamOpener;
619
620            Type[] _knownTypes;
621
622            public Type[] KnownTypes
623            {
624                get { return _knownTypes; }
625                set { _knownTypes = value; }
626            }
627
628            public async Task<TValue> RefreshAsync()
629            {
630                var kts = _knownTypes;
631                return await await
632                       Task.Factory.StartNew(
633                           new Func<Task<TValue>>(
634                           async () =>
635                           {
636                               var ms = new MemoryStream();
637                               var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(TValue), kts);
638                               using (var strm = await _streamOpener(StreamOpenType.Read))
639                               {
640                                   await strm.CopyToAsync(ms);
641
642                               }
643                               if (ms.Length == 0)
644                               {
645                                   return default(TValue);
646                               }
647                               ms.Position = 0;
648
649                               var obj = (TValue)ser.ReadObject(ms);
650                               Value = obj;
651                               return obj;
652
653                           }),
654                            CancellationToken.None,
655                            TaskCreationOptions.None ,
656#if NET45
657 _sch.ConcurrentScheduler
658#else
659 _sch
660#endif
661
662);
663
664
665
666            }
667
668            public async Task SaveAsync(TValue value)
669            {
670                var kts = _knownTypes;
671                await await Task.Factory.StartNew(
672                        async () =>
673                        {
674                            var ms = new MemoryStream();
675                            var ser = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(TValue), kts);
676                            Value = value;
677                            ser.WriteObject(ms, value);
678                            ms.Position = 0;
679                            using (var strm = await _streamOpener(StreamOpenType.Write))
680                            {
681                                await ms.CopyToAsync(strm);
682                                await strm.FlushAsync();
683
684                            }
685                        },
686                        CancellationToken.None,
687                        TaskCreationOptions.None,
688#if NET45
689 _sch.ExclusiveScheduler
690#else
691                    _sch
692#endif
693
694
695);
696
697            }
698
699
700            public TValue Value
701            {
702                get;
703                private set;
704            }
705        }
706        public class XmlDataContractStreamStorageHub<TToken, TValue> : StorageHub<TToken, TValue>
707        {
708            public XmlDataContractStreamStorageHub(Func<StreamOpenType, TToken, Task<Stream>> streamOpener, Func<Task<TToken[]>> storageTokensSelector = null)
709                : base
710                    (tk => new XmlDataContractStreamStorage<TValue>(async tp => await streamOpener(tp, tk)), storageTokensSelector)
711            {
712
713
714            }
715        }
716
717
718        public class XmlDataContractStreamStorage<TValue> : IStorage<TValue>
719        {
720#if NET45
721            ConcurrentExclusiveSchedulerPair _sch = new ConcurrentExclusiveSchedulerPair();
722#else
723            TaskScheduler _sch = new LimitedConcurrencyLevelTaskScheduler(1);
724#endif
725            public XmlDataContractStreamStorage(Func<StreamOpenType, Task<Stream>> streamOpener, params Type[] knownTypes)
726            {
727                _streamOpener = streamOpener;
728                _knownTypes = knownTypes;
729            }
730
731            Func<StreamOpenType, Task<Stream>> _streamOpener;
732
733            Type[] _knownTypes;
734
735            public Type[] KnownTypes
736            {
737                get { return _knownTypes; }
738                set { _knownTypes = value; }
739            }
740
741            public async Task<TValue> RefreshAsync()
742            {
743                var kts = _knownTypes;
744                return await await
745                       Task.Factory.StartNew(
746                           async () =>
747                           {
748                               var ms = new MemoryStream();
749                               var ser = new System.Runtime.Serialization.DataContractSerializer(typeof(TValue), kts);
750                               using (var strm = await _streamOpener(StreamOpenType.Read))
751                               {
752                                   await strm.CopyToAsync(ms);
753
754                               }
755                               if (ms.Length == 0)
756                               {
757                                   return default(TValue);
758                               }
759                               ms.Position = 0;
760
761                               var obj = (TValue)ser.ReadObject(ms);
762                               Value = obj;
763                               return obj;
764
765                           },
766                            CancellationToken.None,
767                            TaskCreationOptions.AttachedToParent,
768#if NET45
769 _sch.ConcurrentScheduler
770#else
771 _sch
772#endif
773
774);
775
776
777
778            }
779
780            public async Task SaveAsync(TValue value)
781            {
782                var kts = _knownTypes;
783                await await Task.Factory.StartNew(
784                        async () =>
785                        {
786                            var ms = new MemoryStream();
787                            var ser = new System.Runtime.Serialization.DataContractSerializer(typeof(TValue), kts);
788                            Value = value;
789                            ser.WriteObject(ms, value);
790                            ms.Position = 0;
791                            using (var strm = await _streamOpener(StreamOpenType.Write))
792                            {
793                                await ms.CopyToAsync(strm);
794                                await strm.FlushAsync();
795
796                            }
797                        },
798                        CancellationToken.None,
799                        TaskCreationOptions.None,
800#if NET45
801 _sch.ExclusiveScheduler
802#else
803                    _sch
804#endif
805
806
807);
808
809            }
810
811
812            public TValue Value
813            {
814                get;
815                private set;
816            }
817        }
818
819    }
820
821
822
823
824}