diff options
| author | Roy Ben-Shabat <Roy@Twine-s.com> | 2019-02-27 16:49:42 +0200 |
|---|---|---|
| committer | Roy Ben-Shabat <Roy@Twine-s.com> | 2019-02-27 16:49:42 +0200 |
| commit | 2ab54573d10ca59351100ab8416178be2223fc91 (patch) | |
| tree | 9a5077998e301c1e86cf00b07ea98eca501fc4a8 /Software/Visual_Studio | |
| parent | 88a73106e8113a4a6ce224f9205e11219939798e (diff) | |
| download | Tango-2ab54573d10ca59351100ab8416178be2223fc91.tar.gz Tango-2ab54573d10ca59351100ab8416178be2223fc91.zip | |
Added support for caching on machine studio.
Diffstat (limited to 'Software/Visual_Studio')
18 files changed, 760 insertions, 121 deletions
diff --git a/Software/Visual_Studio/Build/Shortcuts/Machine Studio.lnk b/Software/Visual_Studio/Build/Shortcuts/Machine Studio.lnk Binary files differindex 6351490f4..cc5de8350 100644 --- a/Software/Visual_Studio/Build/Shortcuts/Machine Studio.lnk +++ b/Software/Visual_Studio/Build/Shortcuts/Machine Studio.lnk diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/MachineStudioSettings.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/MachineStudioSettings.cs index f7c05c1a8..e5fe63d87 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/MachineStudioSettings.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/MachineStudioSettings.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; +using Tango.BL; using Tango.Logging; using Tango.PMR.Printing; using Tango.Settings; @@ -108,6 +109,16 @@ namespace Tango.MachineStudio.Common public bool ByPassEnvironmentVersionCheck { get; set; } /// <summary> + /// Gets or sets a value indicating whether to enable database entity caching. + /// </summary> + public ObservablesContextInMemoryCachingMode CachingMode { get; set; } + + /// <summary> + /// Gets or sets the maximum cache time for a single entity (when CachingMode is set Absolute or Relative). + /// </summary> + public TimeSpan MaximumCacheTime { get; set; } + + /// <summary> /// Gets the machine service address. /// </summary> public String MachineServiceAddress @@ -136,6 +147,8 @@ namespace Tango.MachineStudio.Common Environment = WorkingEnvironment.Remote; DeploymentSlot = DeploymentSlot.DEV; JobUploadStrategy = JobUploadStrategy.Default; + MaximumCacheTime = TimeSpan.FromMinutes(5); + CachingMode = ObservablesContextInMemoryCachingMode.None; } } } diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs index d4598867c..2e2b1a014 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/App.xaml.cs @@ -84,6 +84,26 @@ namespace Tango.MachineStudio.UI exceptionTrapper = new WpfGlobalExceptionTrapper(); exceptionTrapper.Initialize(this); exceptionTrapper.ApplicationCrashed += ExceptionTrapper_ApplicationCrashed; + + //Apply Caching + if (settings.CachingMode != ObservablesContextInMemoryCachingMode.None) + { + LogManager.Log("EF Caching is enabled."); + LogManager.Log($"EF Caching mode is: {settings.CachingMode}."); + LogManager.Log($"EF Caching timeout: {settings.MaximumCacheTime.ToString()}"); + try + { + ObservablesContext.EnableInMemoryCache(settings.MaximumCacheTime, settings.CachingMode); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error while trying to activate EF caching."); + } + } + else + { + LogManager.Log("EF Caching is disabled"); + } } #region Global Exception Trapping diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/AboutView.xaml b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/AboutView.xaml index 640c3c1df..54a8349e6 100644 --- a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/AboutView.xaml +++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/Views/AboutView.xaml @@ -6,6 +6,7 @@ xmlns:vm="clr-namespace:Tango.MachineStudio.UI.ViewModels" xmlns:controls="clr-namespace:Tango.SharedUI.Controls;assembly=Tango.SharedUI" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" + xmlns:bl="clr-namespace:Tango.BL;assembly=Tango.BL" xmlns:local="clr-namespace:Tango.MachineStudio.UI.Views" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Width="600" Height="700" Background="White" d:DataContext="{d:DesignInstance Type=vm:AboutViewVM, IsDesignTimeCreatable=False}" DataContext="{Binding AboutViewVM, Source={StaticResource Locator}}"> @@ -13,6 +14,7 @@ <UserControl.Resources> <converters:VersionToShortVersionConverter x:Key="VersionToShortVersionConverter" /> <converters:EnumToDescriptionConverter x:Key="EnumToDescriptionConverter" /> + <converters:EnumToItemsSourceConverter x:Key="EnumToItemsSourceConverter" /> </UserControl.Resources> <Grid> @@ -60,6 +62,11 @@ <TextBlock><Run Text="{Binding DataSource.Address,Mode=OneWay}"></Run> <Run>(</Run><Run Foreground="Gray" Text="{Binding DataSource.Catalog,Mode=OneWay}"></Run><Run>)</Run> </TextBlock> + <TextBlock FontWeight="SemiBold">Caching Mode:</TextBlock> + <DockPanel> + <ComboBox Width="150" DockPanel.Dock="Left" ItemsSource="{Binding Source={x:Type bl:ObservablesContextInMemoryCachingMode},Converter={StaticResource EnumToItemsSourceConverter}}" SelectedValue="{Binding MachineStudioSettings.CachingMode}" SelectedValuePath="Value" DisplayMemberPath="DisplayName"></ComboBox> + <TextBlock Margin="20 0 0 0" Foreground="Gray" VerticalAlignment="Center">(Requires restart)</TextBlock> + </DockPanel> </controls:TableGrid> <DockPanel Margin="0 0 0 0"> diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config index ea49af905..15a7107bd 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.config @@ -11,6 +11,86 @@ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.2.2.0" newVersion="1.2.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.4.2.0" newVersion="1.4.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Console" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Diagnostics.StackTrace" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.19.8.16603" newVersion="3.19.8.16603" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.19.8.16603" newVersion="3.19.8.16603" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.2.2.0" newVersion="5.2.2.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" /> + </dependentAssembly> </assemblyBinding> </runtime> <entityFramework> diff --git a/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs b/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs index 94d751482..05484d67c 100644 --- a/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs +++ b/Software/Visual_Studio/Tango.BL/ObservablesContextExtension.cs @@ -1,4 +1,5 @@ -using System; +using EFCache; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.Entity; @@ -228,5 +229,24 @@ namespace Tango.BL { ObservablesContextConfiguration.ClearModelStore(); } + + /// <summary> + /// Enables the in memory cache. + /// </summary> + /// <param name="cacheTime">Maximum cache time to preserve a single entity cache.</param> + public static void EnableInMemoryCache(TimeSpan cacheTime, ObservablesContextInMemoryCachingMode mode) + { + if (mode != ObservablesContextInMemoryCachingMode.None) + { + var cache = new ObservablesContextInMemoryCache() { Expiration = cacheTime }; + + if (mode == ObservablesContextInMemoryCachingMode.Relative) + { + cache.ResetAccessTimeOnAccess = true; + } + + EntityFrameworkCache.Initialize(cache); + } + } } } diff --git a/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs b/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs new file mode 100644 index 000000000..39e6d7d9a --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCache.cs @@ -0,0 +1,221 @@ +using EFCache; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL +{ + public class ObservablesContextInMemoryCache : ICache + { + private readonly Dictionary<string, CacheEntry> _cache = new Dictionary<string, CacheEntry>(); + private readonly Dictionary<string, HashSet<string>> _entitySetToKey = new Dictionary<string, HashSet<string>>(); + + public TimeSpan Expiration { get; set; } + public bool ResetAccessTimeOnAccess { get; set; } + + public bool GetItem(string key, out object value) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + value = null; + + lock (_cache) + { + var now = DateTimeOffset.Now; + + CacheEntry entry; + if (_cache.TryGetValue(key, out entry)) + { + if (EntryExpired(entry, now)) + { + InvalidateItem(key); + } + else + { + if (ResetAccessTimeOnAccess) + { + entry.LastAccess = now; + } + value = entry.Value; + return true; + } + } + } + + return false; + } + + public void PutItem(string key, object value, IEnumerable<string> dependentEntitySets, TimeSpan slidingExpiration, DateTimeOffset absoluteExpiration) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + if (dependentEntitySets == null) + { + throw new ArgumentNullException("dependentEntitySets"); + } + + lock (_cache) + { + var entitySets = dependentEntitySets.ToArray(); + + _cache[key] = new CacheEntry(value, entitySets, slidingExpiration, absoluteExpiration); + + foreach (var entitySet in entitySets) + { + HashSet<string> keys; + + if (!_entitySetToKey.TryGetValue(entitySet, out keys)) + { + keys = new HashSet<string>(); + _entitySetToKey[entitySet] = keys; + } + + keys.Add(key); + } + } + } + + public void InvalidateSets(IEnumerable<string> entitySets) + { + if (entitySets == null) + { + throw new ArgumentNullException("entitySets"); + } + + lock (_cache) + { + var itemsToInvalidate = new HashSet<string>(); + + foreach (var entitySet in entitySets) + { + HashSet<string> keys; + + if (_entitySetToKey.TryGetValue(entitySet, out keys)) + { + itemsToInvalidate.UnionWith(keys); + + _entitySetToKey.Remove(entitySet); + } + } + + foreach (var key in itemsToInvalidate) + { + InvalidateItem(key); + } + } + } + + public void InvalidateItem(string key) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + lock (_cache) + { + CacheEntry entry; + + if (_cache.TryGetValue(key, out entry)) + { + _cache.Remove(key); + + foreach (var set in entry.EntitySets) + { + HashSet<string> keys; + if (_entitySetToKey.TryGetValue(set, out keys)) + { + keys.Remove(key); + } + } + } + } + } + + public void Purge() + { + Purge(false); + } + + public void Purge(bool removeUnexpiredItems) + { + lock (_cache) + { + var now = DateTimeOffset.Now; + var itemsToRemove = new HashSet<string>(); + + foreach (var item in _cache) + { + if (removeUnexpiredItems || EntryExpired(item.Value, now)) + { + itemsToRemove.Add(item.Key); + } + } + + foreach (var key in itemsToRemove) + { + InvalidateItem(key); + } + } + } + + public int Count + { + get { return _cache.Count; } + } + + private bool EntryExpired(CacheEntry entry, DateTimeOffset now) + { + return entry.AbsoluteExpiration < now || (now - entry.LastAccess) > Expiration; + } + + private class CacheEntry + { + private readonly object _value; + private readonly string[] _entitySets; + private readonly TimeSpan _slidingExpiration; + private readonly DateTimeOffset _absoluteExpiration; + private readonly DateTime _created; + + public CacheEntry(object value, string[] entitySets, TimeSpan slidingExpiration, + DateTimeOffset absoluteExpiration) + { + _value = value; + _entitySets = entitySets; + _slidingExpiration = slidingExpiration; + _absoluteExpiration = absoluteExpiration; + LastAccess = DateTimeOffset.Now; + } + + public object Value + { + get { return _value; } + } + + public string[] EntitySets + { + get { return _entitySets; } + } + + public TimeSpan SlidingExpiration + { + get { return _slidingExpiration; } + } + + public DateTimeOffset AbsoluteExpiration + { + get { return _absoluteExpiration; } + } + + public DateTimeOffset LastAccess { get; set; } + } + } +} diff --git a/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCachingMode.cs b/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCachingMode.cs new file mode 100644 index 000000000..e0611a1de --- /dev/null +++ b/Software/Visual_Studio/Tango.BL/ObservablesContextInMemoryCachingMode.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.BL +{ + public enum ObservablesContextInMemoryCachingMode + { + None, + Absolute, + Relative + } +} diff --git a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj index 61118b6b0..043a598c8 100644 --- a/Software/Visual_Studio/Tango.BL/Tango.BL.csproj +++ b/Software/Visual_Studio/Tango.BL/Tango.BL.csproj @@ -33,6 +33,9 @@ <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> + <Reference Include="EFCache, Version=1.1.3.0, Culture=neutral, PublicKeyToken=46c4868af4307d2c, processorArchitecture=MSIL"> + <HintPath>..\packages\EntityFramework.Cache.1.1.3\lib\net45\EFCache.dll</HintPath> + </Reference> <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath> </Reference> @@ -460,6 +463,8 @@ <Compile Include="ObservablesContextAdapter.cs" /> <Compile Include="ObservablesContextConfiguration.cs" /> <Compile Include="ObservablesContextExtension.cs" /> + <Compile Include="ObservablesContextInMemoryCache.cs" /> + <Compile Include="ObservablesContextInMemoryCachingMode.cs" /> <Compile Include="ObservablesEntitiesAdapter.cs" /> <Compile Include="ObservablesEntitiesAdapterExtension.cs" /> <Compile Include="Serialization\EntitySerializationFlags.cs" /> @@ -545,7 +550,7 @@ </Target> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> + <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.BL/packages.config b/Software/Visual_Studio/Tango.BL/packages.config index 408466746..0811e4b17 100644 --- a/Software/Visual_Studio/Tango.BL/packages.config +++ b/Software/Visual_Studio/Tango.BL/packages.config @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> + <package id="EntityFramework.Cache" version="1.1.3" targetFramework="net461" /> <package id="Google.Protobuf" version="3.4.1" targetFramework="net46" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> <package id="SimpleValidator" version="0.6.1.0" targetFramework="net46" /> diff --git a/Software/Visual_Studio/Tango.UnitTesting/App.config b/Software/Visual_Studio/Tango.UnitTesting/App.config index 1a3af14d9..074da9ac0 100644 --- a/Software/Visual_Studio/Tango.UnitTesting/App.config +++ b/Software/Visual_Studio/Tango.UnitTesting/App.config @@ -4,6 +4,24 @@ <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> </configSections> + <appSettings> + <add key="DB_ADDRESS" value="twine.database.windows.net" /> + <add key="DB_USER_NAME" value="Roy" /> + <add key="DB_PASSWORD" value="Aa123456" /> + <add key="DB_CATALOG" value="Tango_DEV" /> + <add key="STORAGE_ACCOUNT" value="DefaultEndpointsProtocol=https;AccountName=tangostorage;AccountKey=S4z/D+Yg6mwMis+bs/VpcDLA9yE1iZaYq23shQlRIi2KmM9E7JY8zdZjeAPOPdG3gONHoNDEpsgH6D4cqQ/bsA==;EndpointSuffix=core.windows.net" /> + <add key="TENANT_ID" value="2ebd63a5-bc2f-41dc-9066-4409ed5e5dd4" /> + <add key="CLIENT_ID" value="ec612854-7abc-457b-808a-5d0c5ba80c57" /> + <add key="APP_SECRET" value="54)019A7wv+#86l*PQcQWYKu%fd4Dv!@G=VhCiDI5rD+H4BTH" /> + <add key="TANGO_VERSIONS_CONTAINER" value="tango-versions-dev" /> + <add key="MACHINE_STUDIO_VERSIONS_CONTAINER" value="machine-studio-versions-dev" /> + <add key="DEPLOYMENT_SLOT" value="DEV" /> + <add key="ENVIRONMENT_GROUP" value="Tango DEV" /> + <add key="ENFORCE_MACHINE_STUDIO_VERSION" value="true" /> + <add key="JWT_TOKEN_SECRET" value="GQDstcKsx0NHjLOuXOYg5MbeJ1yT0u1iwDVTwine" /> + <add key="REFRESH_TOKENS_TABLE_NAME" value="RefreshTokens" /> + <add key="REFRESH_TOKENS_TABLE_PARTITION" value="REFRESH_TOKENS_PART" /> + </appSettings> <entityFramework> <providers> <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> @@ -14,9 +32,26 @@ </entityFramework> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> - <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" /> + <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-2.7.0.0" newVersion="2.7.0.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> @@ -59,32 +94,8 @@ <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" /> </dependentAssembly> <dependentAssembly> - <assemblyIdentity name="System.Xml.ReaderWriter" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-3.19.8.16603" newVersion="3.19.8.16603" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-3.19.8.16603" newVersion="3.19.8.16603" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="Microsoft.Data.Edm" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="Microsoft.Data.Services.Client" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> - </dependentAssembly> - <dependentAssembly> - <assemblyIdentity name="Microsoft.Data.OData" publicKeyToken="31bf3856ad364e35" culture="neutral" /> - <bindingRedirect oldVersion="0.0.0.0-5.6.4.0" newVersion="5.6.4.0" /> + <assemblyIdentity name="System.Reactive.Core" publicKeyToken="94bc3704cddfc263" culture="neutral" /> + <bindingRedirect oldVersion="0.0.0.0-3.0.3000.0" newVersion="3.0.3000.0" /> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> diff --git a/Software/Visual_Studio/Tango.UnitTesting/MachineService/MachineStudio_Controller_TST.cs b/Software/Visual_Studio/Tango.UnitTesting/MachineService/MachineStudio_Controller_TST.cs index 21ab16307..d4585388a 100644 --- a/Software/Visual_Studio/Tango.UnitTesting/MachineService/MachineStudio_Controller_TST.cs +++ b/Software/Visual_Studio/Tango.UnitTesting/MachineService/MachineStudio_Controller_TST.cs @@ -5,6 +5,7 @@ using Tango.BL; using Tango.MachineStudio.Common.Web; using Tango.Transport.Web; using System.Linq; +using System.Configuration; namespace Tango.UnitTesting.MachineService { @@ -74,5 +75,34 @@ namespace Tango.UnitTesting.MachineService Assert.IsFalse(res5.IsUpdateAvailable); } + + [TestMethod] + public void Login_with_new_user() + { + //LoadConfiguration(); + + Tango.MachineService.Controllers.MachineStudioController controller = new Tango.MachineService.Controllers.MachineStudioController(); + + + + controller.Login(new LoginRequest() + { + Email = "Mati@twine-s.com", + Password = "Futo8985", + }); + } + + //private void LoadConfiguration() + //{ + // ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); + // fileMap.ExeConfigFilename = @"web.config"; + + // Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); + + // foreach (var item in config.AppSettings.Settings.OfType<KeyValueConfigurationElement>()) + // { + // ConfigurationManager.AppSettings.Add(item.Key, item.Value); + // } + //} } } diff --git a/Software/Visual_Studio/Tango.UnitTesting/Tango.UnitTesting.csproj b/Software/Visual_Studio/Tango.UnitTesting/Tango.UnitTesting.csproj index 4e852fed8..d1bba995e 100644 --- a/Software/Visual_Studio/Tango.UnitTesting/Tango.UnitTesting.csproj +++ b/Software/Visual_Studio/Tango.UnitTesting/Tango.UnitTesting.csproj @@ -25,7 +25,7 @@ <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> - <OutputPath>..\Build\Core\Debug\</OutputPath> + <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>0</WarningLevel> @@ -35,7 +35,7 @@ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> - <OutputPath>..\Build\Core\Release\</OutputPath> + <OutputPath>bin\Release\</OutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> @@ -60,6 +60,16 @@ <HintPath>..\packages\JWT.5.0.0\lib\net46\JWT.dll</HintPath> </Reference> <Reference Include="Microsoft.CSharp" /> + <Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=3.13.5.907, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.7.10707.1513-rc\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath> + </Reference> + <Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.Platform, Version=3.13.5.907, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.5\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll</HintPath> + </Reference> + <Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms"> + <HintPath>..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.7.10707.1513-rc\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll</HintPath> + </Reference> <Reference Include="Microsoft.Office.Interop.Outlook, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c, processorArchitecture=MSIL"> <EmbedInteropTypes>True</EmbedInteropTypes> </Reference> @@ -76,6 +86,7 @@ </Reference> <Reference Include="System" /> <Reference Include="System.ComponentModel.DataAnnotations" /> + <Reference Include="System.Configuration" /> <Reference Include="System.Core" /> <Reference Include="System.Data" /> <Reference Include="System.Data.Entity.Design" /> @@ -91,6 +102,13 @@ <HintPath>..\packages\System.Data.SQLite.Linq.1.0.108.0\lib\net46\System.Data.SQLite.Linq.dll</HintPath> <Private>True</Private> </Reference> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath> + </Reference> + <Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> + <HintPath>..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll</HintPath> + </Reference> <Reference Include="TestStack.White, Version=0.13.0.0, Culture=neutral, PublicKeyToken=2672efbf3e161801, processorArchitecture=MSIL"> <HintPath>..\packages\TestStack.White.0.13.3\lib\net40\TestStack.White.dll</HintPath> </Reference> @@ -216,6 +234,10 @@ <Project>{ebb7cb9f-6af2-456b-a5dd-1b136b605d90}</Project> <Name>Tango.DBObservablesGenerator.CLI</Name> </ProjectReference> + <ProjectReference Include="..\Web\Tango.MachineService\Tango.MachineService.csproj"> + <Project>{3f09b230-5aac-4651-ba7a-19f3bdfcf701}</Project> + <Name>Tango.MachineService</Name> + </ProjectReference> </ItemGroup> <ItemGroup> <Content Include="AdvancedInstaller\DemoProject\Files\File3.txt"> @@ -242,7 +264,7 @@ <Import Project="..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.108.0\build\net46\System.Data.SQLite.Core.targets')" /> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.UnitTesting/packages.config b/Software/Visual_Studio/Tango.UnitTesting/packages.config index 0528c7ef0..e3fc2d3b6 100644 --- a/Software/Visual_Studio/Tango.UnitTesting/packages.config +++ b/Software/Visual_Studio/Tango.UnitTesting/packages.config @@ -5,6 +5,9 @@ <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> <package id="Google.Protobuf" version="3.4.1" targetFramework="net46" /> <package id="JWT" version="5.0.0" targetFramework="net461" /> + <package id="Microsoft.AspNet.WebApi" version="5.2.3" targetFramework="net461" /> + <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net461" /> + <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net461" /> <package id="MSTest.TestAdapter" version="1.1.11" targetFramework="net45" /> <package id="MSTest.TestFramework" version="1.1.11" targetFramework="net45" /> <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" /> diff --git a/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml b/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml index 6c1f5ed51..ab76a9745 100644 --- a/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml +++ b/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml @@ -20,8 +20,9 @@ <StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center"> <TextBlock HorizontalAlignment="Center" Margin="0 0 0 10" x:Name="txtStatus"></TextBlock> <ProgressBar x:Name="prog" VerticalAlignment="Center" Height="15" Width="700"></ProgressBar> - <Button x:Name="btnStart" Click="btnStart_Click" HorizontalAlignment="Center" Padding="30 10" Margin="0 10 0 0">START</Button> - <Button x:Name="btnChange" Click="btnChange_Click" HorizontalAlignment="Center" Padding="30 10" Margin="0 10 0 0">CHANGE</Button> + <Button x:Name="btnStart" Click="btnStart_Click" HorizontalAlignment="Center" Padding="30 10" Margin="0 10 0 0">LOAD JOBS</Button> + <Button x:Name="btnChange" Click="btnChange_Click" HorizontalAlignment="Center" Padding="30 10" Margin="0 10 0 0">CHANGE JOB</Button> + <Button x:Name="btnListen" Click="btnListen_Click" HorizontalAlignment="Center" Padding="30 10" Margin="0 10 0 0">START LISTEN</Button> </StackPanel> </Grid> </Window> diff --git a/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml.cs b/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml.cs index 4ac7bffa2..ca676e277 100644 --- a/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml.cs +++ b/Software/Visual_Studio/Utilities/Tango.UITests/MainWindow.xaml.cs @@ -36,6 +36,7 @@ using System.Security.Permissions; using TableDependency.SqlClient.Base; using TableDependency.SqlClient; using TableDependency.SqlClient.Base.EventArgs; +using TableDependency.SqlClient.Base.Abstracts; namespace Tango.UITests { @@ -44,93 +45,85 @@ namespace Tango.UITests /// </summary> public partial class MainWindow : Window { + private ITableDependency _dep; + + private DataSource _dataSource; + public MainWindow() { + _dataSource = new DataSource() + { + Address = "twine.database.windows.net", + Catalog = "Tango_DEV", + Type = DataSourceType.SQLServer, + UserName = "Roy", + Password = "Aa123456", + IntegratedSecurity = false, + }; + InitializeComponent(); - EntityFrameworkCache.Initialize(new InMemoryCache()); + EntityFrameworkCache.Initialize(new MyMemoryCache() { Expiration = TimeSpan.FromMinutes(1) }); + this.Closing += MainWindow_Closing; } - private static string _con = "data source=localhost\\SQLEXPRESS; initial catalog=Tango; integrated security=False;User Id=SqlDependency;Password=Aa123456"; + private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + if (_dep != null) + { + _dep.Stop(); + _dep.Dispose(); + } + } private void btnStart_Click(object sender, RoutedEventArgs e) { - //var dataSource = new DataSource() - //{ - // Address = "localhost\\SQLEXPRESS", - // Catalog = "Tango", - // Type = DataSourceType.SQLServer, - // IntegratedSecurity = false, - // UserName = "Developer", - // Password = "Aa123456", - //}; + Stopwatch watch = Stopwatch.StartNew(); - //var connection = dataSource.ToConnection(); + using (ObservablesContext db = ObservablesContext.CreateDefault(_dataSource)) + { + var users = db.Users.ToList(); + var jobs = new JobsCollectionBuilder(db).SetAll().WithSegments().WithBrushStops().Build(); + var first_job = jobs.First(); + + if (first_job.Name == "Changed Name 2") + { + Debug.WriteLine("Changed and cached !!!"); + } + else + { + Debug.WriteLine("Not working."); + } + } - String str = _con; + Debug.WriteLine($"Time to complete: {watch.Elapsed.TotalSeconds} seconds"); + } + + private void btnChange_Click(object sender, RoutedEventArgs e) + { + using (ObservablesContext db = ObservablesContext.CreateDefault(_dataSource)) + { + var jobs = new JobsCollectionBuilder(db).SetAll().WithSegments().WithBrushStops().Build(); + var first_job = jobs.First(); + first_job.Name = "Changed Name 2"; + db.SaveChanges(); + } + } - //var mapper = new ModelToTableMapper<User>(); - //mapper.AddMapping(c => c.ID, "ID"); - //mapper.AddMapping(c => c.Email, "EMAIL"); + private void btnListen_Click(object sender, RoutedEventArgs e) + { + String str = _dataSource.ToConnection().ConnectionString; var dep = new SqlTableDependency<DAL.Remote.DB.USER>(str, "USERS", "dbo"); dep.TraceLevel = TraceLevel.Verbose; - dep.TraceListener = new TextWriterTraceListener(Console.Out); + dep.TraceListener = new TextWriterTraceListener(Console.Out); dep.OnChanged += Changed; dep.Start(); - //SqlClientPermission clientPermission = - // new SqlClientPermission(PermissionState.Unrestricted); - //clientPermission.Demand(); - - //System.Data.SqlClient.SqlDependency.Start(str); - - //String commandText = "SELECT [dbo].[USERS].[EMAIL] FROM [dbo].[USERS];"; - //SqlCommand command = new SqlCommand(commandText, connection as SqlConnection); - //command.Notification = null; - //command.CommandType = CommandType.Text; - - //command.Connection.Open(); - - //SqlDependency dependency = new SqlDependency(command); - //dependency.OnChange += (s, args) => - //{ - - //}; - - //command.ExecuteReader(); - //String a = "!23"; - - //Stopwatch watch = Stopwatch.StartNew(); - - //using (ObservablesContext db = ObservablesContext.CreateDefault(new DataSource() - //{ - // Address = "localhost\\SQLEXPRESS", - // Catalog = "Tango", - // Type = DataSourceType.SQLServer, - // UserName = "Roy", - // Password = "Aa123456", - // IntegratedSecurity = true, - //})) - //{ - // var users = db.Users.ToList(); - // var jobs = new JobsCollectionBuilder(db).SetAll().WithSegments().WithBrushStops().Build(); - // var first_job = jobs.First(); - - // if (first_job.Name == "Changed Name 2") - // { - // Debug.WriteLine("Changed and cached !!!"); - // } - // else - // { - // Debug.WriteLine("Not working."); - // } - //} - - //Debug.WriteLine($"Time to complete: {watch.Elapsed.TotalSeconds} seconds"); + _dep = dep; } private void Changed(object sender, RecordChangedEventArgs<DAL.Remote.DB.USER> e) @@ -141,24 +134,5 @@ namespace Tango.UITests Console.WriteLine(changedEntity.ToJsonString()); } - - private void btnChange_Click(object sender, RoutedEventArgs e) - { - using (ObservablesContext db = ObservablesContext.CreateDefault(new DataSource() - { - Address = "twine.database.windows.net", - Catalog = "Tango_DEV", - Type = DataSourceType.SQLServer, - UserName = "Roy", - Password = "Aa123456", - IntegratedSecurity = false, - })) - { - var jobs = new JobsCollectionBuilder(db).SetAll().WithSegments().WithBrushStops().Build(); - var first_job = jobs.First(); - first_job.Name = "Changed Name 2"; - db.SaveChanges(); - } - } } } diff --git a/Software/Visual_Studio/Utilities/Tango.UITests/MyMemoryCache.cs b/Software/Visual_Studio/Utilities/Tango.UITests/MyMemoryCache.cs new file mode 100644 index 000000000..0a3583f54 --- /dev/null +++ b/Software/Visual_Studio/Utilities/Tango.UITests/MyMemoryCache.cs @@ -0,0 +1,215 @@ + +namespace EFCache +{ + using System; + using System.Linq; + using System.Collections.Generic; + + public class MyMemoryCache : ICache + { + private readonly Dictionary<string, CacheEntry> _cache = new Dictionary<string, CacheEntry>(); + private readonly Dictionary<string, HashSet<string>> _entitySetToKey = new Dictionary<string, HashSet<string>>(); + + public TimeSpan Expiration { get; set; } + + public bool GetItem(string key, out object value) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + value = null; + + lock (_cache) + { + var now = DateTimeOffset.Now; + + CacheEntry entry; + if (_cache.TryGetValue(key, out entry)) + { + if (EntryExpired(entry, now)) + { + InvalidateItem(key); + } + else + { + //entry.LastAccess = now; + value = entry.Value; + return true; + } + } + } + + return false; + } + + public void PutItem(string key, object value, IEnumerable<string> dependentEntitySets, TimeSpan slidingExpiration, DateTimeOffset absoluteExpiration) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + if (dependentEntitySets == null) + { + throw new ArgumentNullException("dependentEntitySets"); + } + + lock (_cache) + { + var entitySets = dependentEntitySets.ToArray(); + + _cache[key] = new CacheEntry(value, entitySets, slidingExpiration, absoluteExpiration); + + foreach (var entitySet in entitySets) + { + HashSet<string> keys; + + if (!_entitySetToKey.TryGetValue(entitySet, out keys)) + { + keys = new HashSet<string>(); + _entitySetToKey[entitySet] = keys; + } + + keys.Add(key); + } + } + } + + public void InvalidateSets(IEnumerable<string> entitySets) + { + if (entitySets == null) + { + throw new ArgumentNullException("entitySets"); + } + + lock (_cache) + { + var itemsToInvalidate = new HashSet<string>(); + + foreach (var entitySet in entitySets) + { + HashSet<string> keys; + + if (_entitySetToKey.TryGetValue(entitySet, out keys)) + { + itemsToInvalidate.UnionWith(keys); + + _entitySetToKey.Remove(entitySet); + } + } + + foreach (var key in itemsToInvalidate) + { + InvalidateItem(key); + } + } + } + + public void InvalidateItem(string key) + { + if (key == null) + { + throw new ArgumentNullException("key"); + } + + lock (_cache) + { + CacheEntry entry; + + if (_cache.TryGetValue(key, out entry)) + { + _cache.Remove(key); + + foreach (var set in entry.EntitySets) + { + HashSet<string> keys; + if (_entitySetToKey.TryGetValue(set, out keys)) + { + keys.Remove(key); + } + } + } + } + } + + public void Purge() + { + Purge(false); + } + + public void Purge(bool removeUnexpiredItems) + { + lock (_cache) + { + var now = DateTimeOffset.Now; + var itemsToRemove = new HashSet<string>(); + + foreach (var item in _cache) + { + if (removeUnexpiredItems || EntryExpired(item.Value, now)) + { + itemsToRemove.Add(item.Key); + } + } + + foreach (var key in itemsToRemove) + { + InvalidateItem(key); + } + } + } + + public int Count + { + get { return _cache.Count; } + } + + private bool EntryExpired(CacheEntry entry, DateTimeOffset now) + { + return entry.AbsoluteExpiration < now || (now - entry.LastAccess) > Expiration; + } + + private class CacheEntry + { + private readonly object _value; + private readonly string[] _entitySets; + private readonly TimeSpan _slidingExpiration; + private readonly DateTimeOffset _absoluteExpiration; + private readonly DateTime _created; + + public CacheEntry(object value, string[] entitySets, TimeSpan slidingExpiration, + DateTimeOffset absoluteExpiration) + { + _value = value; + _entitySets = entitySets; + _slidingExpiration = slidingExpiration; + _absoluteExpiration = absoluteExpiration; + LastAccess = DateTimeOffset.Now; + } + + public object Value + { + get { return _value; } + } + + public string[] EntitySets + { + get { return _entitySets; } + } + + public TimeSpan SlidingExpiration + { + get { return _slidingExpiration; } + } + + public DateTimeOffset AbsoluteExpiration + { + get { return _absoluteExpiration; } + } + + public DateTimeOffset LastAccess { get; set; } + } + } +}
\ No newline at end of file diff --git a/Software/Visual_Studio/Utilities/Tango.UITests/Tango.UITests.csproj b/Software/Visual_Studio/Utilities/Tango.UITests/Tango.UITests.csproj index 7daf19294..87643ac2b 100644 --- a/Software/Visual_Studio/Utilities/Tango.UITests/Tango.UITests.csproj +++ b/Software/Visual_Studio/Utilities/Tango.UITests/Tango.UITests.csproj @@ -99,6 +99,7 @@ </Compile> </ItemGroup> <ItemGroup> + <Compile Include="MyMemoryCache.cs" /> <Compile Include="Properties\AssemblyInfo.cs"> <SubType>Code</SubType> </Compile> @@ -182,7 +183,7 @@ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> + <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file |
