forked from OData/RESTier
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add TrippinInMemory sample, most requests on odata.org works well
- Loading branch information
Showing
26 changed files
with
2,636 additions
and
247 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
...ODataEndToEnd/Microsoft.OData.Service.Library/DataStoreManager/DefaultDataStoreManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Timers; | ||
|
||
namespace Microsoft.OData.Service.Library.DataStoreManager | ||
{ | ||
/// <summary> | ||
/// Default resource management class to manage resources. | ||
/// Use a dictionary to easily access the resource by <see cref="TKey"/> and make a constraint on the total number of resources. | ||
/// Use a timer for each reasource, when the resource live longer than <see cref="MaxDataStoreInstanceLifeTime"/>, it will be destroyed automatically. | ||
/// </summary> | ||
public class DefaultDataStoreManager<TKey, TDataStoreType> :IDataStoreManager<TKey, TDataStoreType> where TDataStoreType : class, new() | ||
{ | ||
/// <summary> | ||
/// The max capacity of the resource container, this is a constraint for memory cost. | ||
/// </summary> | ||
public int MaxDataStoreInstanceCapacity { get; set; } = 1000; | ||
|
||
/// <summary> | ||
/// The max life time of each resource. When the resource lives longer than that, it will be destroyed automatically. | ||
/// Besides, when the resource container is full, the resource live longest will be destroyed. | ||
/// </summary> | ||
public TimeSpan MaxDataStoreInstanceLifeTime { get; set; } = new TimeSpan(0, 15, 0); | ||
|
||
private Dictionary<TKey, DataStoreUnit> _dataStoreDict = new Dictionary<TKey, DataStoreUnit>(); | ||
|
||
public TDataStoreType ResetDataStoreInstance(TKey key) | ||
{ | ||
if (_dataStoreDict.ContainsKey(key)) | ||
{ | ||
_dataStoreDict[key] = new DataStoreUnit(key, MaxDataStoreInstanceLifeTime.TotalMilliseconds, ResouceTimeoutHandler); | ||
} | ||
else | ||
{ | ||
AddDataStoreInstance(key); | ||
} | ||
|
||
return _dataStoreDict[key].DataStore; | ||
} | ||
|
||
public TDataStoreType GetDataStoreInstance(TKey key) | ||
{ | ||
if (_dataStoreDict.ContainsKey(key)) | ||
{ | ||
_dataStoreDict[key].UpdateLastUsedDateTime(); | ||
} | ||
else | ||
{ | ||
AddDataStoreInstance(key); | ||
} | ||
|
||
return _dataStoreDict[key].DataStore; | ||
} | ||
|
||
private TDataStoreType AddDataStoreInstance(TKey key) | ||
{ | ||
if (_dataStoreDict.Count >= MaxDataStoreInstanceCapacity) | ||
{ | ||
// No resource lives longer than maxLifeTime, find the one lives longest and remove it. | ||
var minLastUsedTime = DateTime.Now; | ||
TKey minKey = default(TKey); | ||
|
||
foreach (var val in _dataStoreDict) | ||
{ | ||
var resourceLastUsedTime = val.Value.DataStoreLastUsedDateTime; | ||
if (resourceLastUsedTime < minLastUsedTime) | ||
{ | ||
minLastUsedTime = resourceLastUsedTime; | ||
minKey = val.Key; | ||
} | ||
} | ||
|
||
DeleteDataStoreInstance(minKey); | ||
} | ||
|
||
System.Diagnostics.Trace.TraceInformation("The resouce dictionary size right now is {0}", _dataStoreDict.Count); | ||
_dataStoreDict.Add(key, new DataStoreUnit(key, MaxDataStoreInstanceLifeTime.TotalMilliseconds, ResouceTimeoutHandler)); | ||
return _dataStoreDict[key].DataStore; | ||
} | ||
|
||
private DefaultDataStoreManager<TKey, TDataStoreType> DeleteDataStoreInstance(TKey key) | ||
{ | ||
if (_dataStoreDict.ContainsKey(key)) | ||
{ | ||
_dataStoreDict[key].StopTimer(); | ||
_dataStoreDict.Remove(key); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
private void ResouceTimeoutHandler(object source, EventArgs e) | ||
{ | ||
var resouceUnit = source as DataStoreUnit; | ||
if (resouceUnit != null) | ||
{ | ||
System.Diagnostics.Trace.TraceInformation(resouceUnit.DatastoreKey + " timeout occured, now destroy it!"); | ||
DeleteDataStoreInstance(resouceUnit.DatastoreKey); | ||
} | ||
} | ||
|
||
private class DataStoreUnit | ||
{ | ||
public TKey DatastoreKey { get; } | ||
|
||
public TDataStoreType DataStore { get; } | ||
|
||
public DateTime DataStoreLastUsedDateTime { get; private set; } | ||
|
||
private Timer DataStoreTimer { get; set; } | ||
|
||
private double _dataStoreLifeTime; | ||
|
||
private EventHandler _timerTimeoutHandler; | ||
|
||
public DataStoreUnit(TKey key, double dataStoreLifeTime, EventHandler dataStoreTimeoutHandler) | ||
{ | ||
DatastoreKey = key; | ||
DataStore = new TDataStoreType(); | ||
DataStoreLastUsedDateTime = DateTime.Now; | ||
_dataStoreLifeTime = dataStoreLifeTime; | ||
_timerTimeoutHandler += dataStoreTimeoutHandler; | ||
InitTimer(); | ||
} | ||
|
||
public DataStoreUnit UpdateLastUsedDateTime() | ||
{ | ||
UpdateTimer(); | ||
DataStoreLastUsedDateTime = DateTime.Now; | ||
return this; | ||
} | ||
|
||
public void StopTimer() | ||
{ | ||
DataStoreTimer.Stop(); | ||
} | ||
|
||
private Timer InitTimer() | ||
{ | ||
DataStoreTimer = new Timer(_dataStoreLifeTime); | ||
DataStoreTimer.Elapsed += (sender, args) => { _timerTimeoutHandler?.Invoke(this, args); }; | ||
DataStoreTimer.Start(); | ||
return DataStoreTimer; | ||
} | ||
|
||
private void UpdateTimer() | ||
{ | ||
DataStoreTimer.Stop(); | ||
DataStoreTimer = InitTimer(); | ||
} | ||
}; | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
test/ODataEndToEnd/Microsoft.OData.Service.Library/DataStoreManager/IDataStoreManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
||
namespace Microsoft.OData.Service.Library.DataStoreManager | ||
{ | ||
/// <summary> | ||
/// Resource management interface. | ||
/// </summary> | ||
public interface IDataStoreManager<TKey, TDataStoreType> | ||
{ | ||
TDataStoreType GetDataStoreInstance(TKey key); | ||
TDataStoreType ResetDataStoreInstance(TKey key); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
test/ODataEndToEnd/Microsoft.OData.Service.Library/Microsoft.OData.Service.Library.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{1CA9B17F-D3F8-4FC3-A992-5135DCCAB9DE}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>Microsoft.OData.Service.Library</RootNamespace> | ||
<AssemblyName>Microsoft.OData.Service.Library</AssemblyName> | ||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | ||
<HintPath>..\..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath> | ||
<Private>True</Private> | ||
</Reference> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="System.Web" /> | ||
<Reference Include="System.Xml.Linq" /> | ||
<Reference Include="System.Data.DataSetExtensions" /> | ||
<Reference Include="Microsoft.CSharp" /> | ||
<Reference Include="System.Data" /> | ||
<Reference Include="System.Net.Http" /> | ||
<Reference Include="System.Xml" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Compile Include="DataStoreManager\DefaultDataStoreManager.cs" /> | ||
<Compile Include="DataStoreManager\IDataStoreManager.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
<Compile Include="Utils\LibraryUtils.cs" /> | ||
<Compile Include="Utils\ODataSessionIdManager.cs" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<None Include="packages.config" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | ||
Other similar extension points exist, see Microsoft.Common.targets. | ||
<Target Name="BeforeBuild"> | ||
</Target> | ||
<Target Name="AfterBuild"> | ||
</Target> | ||
--> | ||
</Project> |
36 changes: 36 additions & 0 deletions
36
test/ODataEndToEnd/Microsoft.OData.Service.Library/Properties/AssemblyInfo.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
using System.Reflection; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("Microsoft.OData.Service.Library")] | ||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("")] | ||
[assembly: AssemblyProduct("Microsoft.OData.Service.Library")] | ||
[assembly: AssemblyCopyright("Copyright © 2016")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM | ||
[assembly: Guid("1ca9b17f-d3f8-4fc3-a992-5135dccab9de")] | ||
|
||
// Version information for an assembly consists of the following four values: | ||
// | ||
// Major Version | ||
// Minor Version | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.0")] | ||
[assembly: AssemblyFileVersion("1.0.0.0")] |
14 changes: 14 additions & 0 deletions
14
test/ODataEndToEnd/Microsoft.OData.Service.Library/Utils/LibraryUtils.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
||
namespace Microsoft.OData.Service.Library.Utils | ||
{ | ||
public static class LibraryUtils | ||
{ | ||
static public string GetSessionId() | ||
{ | ||
var session = System.Web.HttpContext.Current.Session; | ||
return session?.SessionID; | ||
} | ||
} | ||
} |
75 changes: 75 additions & 0 deletions
75
test/ODataEndToEnd/Microsoft.OData.Service.Library/Utils/ODataSessionIdManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
||
using System.Text.RegularExpressions; | ||
using System.Web; | ||
using System.Web.SessionState; | ||
|
||
namespace Microsoft.OData.Service.Library.Utils | ||
{ | ||
/// <summary> | ||
/// The default SessionIdManager in Azure will cause to loop 302, use custom SessionIdManager to avoid this. | ||
/// </summary> | ||
public class ODataSessionIdManager : ISessionIDManager | ||
{ | ||
private static InternalSessionIdManager _internalManager = new InternalSessionIdManager(); | ||
|
||
public string CreateSessionID(HttpContext context) | ||
{ | ||
return _internalManager.CreateSessionID(context); | ||
} | ||
|
||
public string GetSessionID(HttpContext context) | ||
{ | ||
var id = HttpContext.Current.Items["AspCookielessSession"] as string; | ||
|
||
// Azure web site does not support header "AspFilterSessionId", so we cannot get context.Items["AspCookielessSession"] | ||
// for azure web site use, Headers["X-Original-URL"] format: /(S(xxx))/odata/path. | ||
var originalUrl = HttpContext.Current.Request.Headers["X-Original-URL"]; | ||
|
||
if (!string.IsNullOrEmpty(originalUrl)) | ||
{ | ||
var match = Regex.Match(HttpContext.Current.Request.Headers["X-Original-URL"], @"/\(S\((\w+)\)\)"); | ||
if (match.Success) | ||
{ | ||
id = match.Groups[1].Value; | ||
} | ||
} | ||
|
||
return id; | ||
} | ||
|
||
public void Initialize() | ||
{ | ||
_internalManager.Initialize(); | ||
} | ||
|
||
public bool InitializeRequest(HttpContext context, bool suppressAutoDetectRedirect, out bool supportSessionIdReissue) | ||
{ | ||
return _internalManager.InitializeRequest(context, suppressAutoDetectRedirect, out supportSessionIdReissue); | ||
} | ||
|
||
public void RemoveSessionID(HttpContext context) | ||
{ | ||
_internalManager.RemoveSessionID(context); | ||
} | ||
|
||
public void SaveSessionID(HttpContext context, string id, out bool redirected, out bool cookieAdded) | ||
{ | ||
_internalManager.SaveSessionID(context, id, out redirected, out cookieAdded); | ||
} | ||
|
||
public bool Validate(string id) | ||
{ | ||
return _internalManager.Validate(id); | ||
} | ||
|
||
private class InternalSessionIdManager : SessionIDManager | ||
{ | ||
public override bool Validate(string id) | ||
{ | ||
return !string.IsNullOrEmpty(id); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.