Repository: VahidN/EFSecondLevelCache.Core
Branch: master
Commit: 1de038417ba2
Files: 107
Total size: 396.0 KB
Directory structure:
gitextract_jukctmgq/
├── .gitattributes
├── .github/
│ ├── issue_template.md
│ ├── lock.yml
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── EFSecondLevelCache.Core.sln
├── LICENSE.md
├── README.md
├── global.json
├── src/
│ ├── EFSecondLevelCache.Core/
│ │ ├── Contracts/
│ │ │ ├── EFCacheDebugInfo.cs
│ │ │ ├── EFCacheKey.cs
│ │ │ ├── EFQueryDebugView.cs
│ │ │ ├── IEFCacheKeyHashProvider.cs
│ │ │ ├── IEFCacheKeyProvider.cs
│ │ │ └── IEFCacheServiceProvider.cs
│ │ ├── EFAsyncEnumerable.cs
│ │ ├── EFAsyncEnumerator.cs
│ │ ├── EFAsyncTaskEnumerable.cs
│ │ ├── EFAsyncTaskEnumerator.cs
│ │ ├── EFCacheKeyHashProvider.cs
│ │ ├── EFCacheKeyProvider3x.cs
│ │ ├── EFCachePolicy.cs
│ │ ├── EFCacheServiceProvider.cs
│ │ ├── EFCachedDbSet.cs
│ │ ├── EFCachedDbSetExtensions.cs
│ │ ├── EFCachedQueryExtensions.cs
│ │ ├── EFCachedQueryProvider.cs
│ │ ├── EFCachedQueryable.cs
│ │ ├── EFChangeTrackerExtensions.cs
│ │ ├── EFMaterializer.cs
│ │ ├── EFQueryExpressionVisitor.cs
│ │ ├── EFSecondLevelCache.Core.csproj
│ │ ├── EFServiceCollectionExtensions.cs
│ │ ├── EFStaticServiceProvider.cs
│ │ ├── ParallelExtensions.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── XxHashUnsafe.cs
│ │ ├── _0-restore.bat
│ │ └── _1-dotnet_pack.bat
│ └── Tests/
│ ├── EFSecondLevelCache.Core.AspNetCoreSample/
│ │ ├── App_Data/
│ │ │ └── .gitkeep.txt
│ │ ├── Controllers/
│ │ │ └── HomeController.cs
│ │ ├── DataLayer/
│ │ │ ├── Entities/
│ │ │ │ ├── Post.cs
│ │ │ │ ├── Product.cs
│ │ │ │ ├── Tag.cs
│ │ │ │ ├── TagProduct.cs
│ │ │ │ └── User.cs
│ │ │ ├── SampleContext.cs
│ │ │ └── Utils/
│ │ │ ├── ApplicationDbContextSeedData.cs
│ │ │ └── DBInitialization.cs
│ │ ├── EFSecondLevelCache.Core.AspNetCoreSample.csproj
│ │ ├── Migrations/
│ │ │ ├── 20191022095356_V2019_10_22_1323.Designer.cs
│ │ │ ├── 20191022095356_V2019_10_22_1323.cs
│ │ │ └── SampleContextModelSnapshot.cs
│ │ ├── Models/
│ │ │ └── PostDto.cs
│ │ ├── Others/
│ │ │ └── TestUtils.cs
│ │ ├── Profiles/
│ │ │ └── PostProfile.cs
│ │ ├── Program.cs
│ │ ├── Properties/
│ │ │ └── launchSettings.json
│ │ ├── Startup.cs
│ │ ├── _0-restore.bat
│ │ ├── _1-dotnet_run.bat
│ │ ├── _update_db.bat
│ │ ├── appsettings.json
│ │ ├── web.config
│ │ └── wwwroot/
│ │ └── App_Data/
│ │ └── .gitkeep
│ ├── EFSecondLevelCache.Core.NET46Sample/
│ │ └── EFSecondLevelCache.Core.NET46Sample/
│ │ ├── App.config
│ │ ├── DataLayer/
│ │ │ ├── ConfigureServices.cs
│ │ │ ├── Entities/
│ │ │ │ └── Post.cs
│ │ │ └── SampleContext.cs
│ │ ├── EFSecondLevelCache.Core.NET46Sample.csproj
│ │ ├── Program.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ └── packages.config
│ ├── EFSecondLevelCache.Core.PerformanceTests/
│ │ ├── BenchmarkTests.cs
│ │ ├── EFSecondLevelCache.Core.PerformanceTests.csproj
│ │ ├── Program.cs
│ │ ├── SampleContext.cs
│ │ ├── TestsServiceProvider.cs
│ │ ├── _0-restore.bat
│ │ ├── _1-dotnet_run.bat
│ │ └── app_data/
│ │ └── .gitkeep
│ ├── EFSecondLevelCache.Core.Tests/
│ │ ├── EFCacheServiceProviderTests.cs
│ │ ├── EFCachedQueryProviderAsyncTests.cs
│ │ ├── EFCachedQueryProviderBasicTests.cs
│ │ ├── EFCachedQueryProviderInvalidationTests.cs
│ │ ├── EFSecondLevelCache.Core.Tests.csproj
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── TestsBase.cs
│ │ ├── XxHashTests.cs
│ │ ├── _0-restore.bat
│ │ └── _1-dotnet_test.bat
│ └── Issues/
│ ├── Issue15/
│ │ ├── ConfigureServices.cs
│ │ ├── Issue15.csproj
│ │ ├── Payment.cs
│ │ ├── Program.cs
│ │ ├── SampleContext.cs
│ │ └── app_data/
│ │ └── .git.keep
│ └── Issue43/
│ ├── Issue43.csproj
│ ├── Program.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_run.bat
│ └── app_data/
│ └── .git.keep
├── tag-it.bat
└── update-dependencies.bat
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
================================================
FILE: .github/issue_template.md
================================================
# Summary of the issue
## Environment
```
.NET Core SDK version:
Microsoft.EntityFrameworkCore version:
EFSecondLevelCache.Core version:
```
## Example code/Steps to reproduce:
```
paste your core code
```
## Output:
```
Exception message:
Full Stack trace:
```
================================================
FILE: .github/lock.yml
================================================
daysUntilLock: 90
skipCreatedBefore: false
exemptLabels: []
lockLabel: false
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related problems.
setLockReason: true
================================================
FILE: .github/workflows/build.yml
================================================
name: .NET Core Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 3.1.101
- name: Build DNTCaptcha.Core lib
run: dotnet build ./src/EFSecondLevelCache.Core/EFSecondLevelCache.Core.csproj --configuration Release
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
/.idea
/src/Tests/EFSecondLevelCache.Core.PerformanceTests/BenchmarkDotNet.Artifacts
================================================
FILE: .vscode/launch.json
================================================
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)-Issue43",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/Tests/Issues/Issue43/bin/Debug/netcoreapp3.1/Issue43.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "internalConsole"
},
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceRoot}/src/Tests/EFSecondLevelCache.Core.AspNetCoreSample/bin/Debug/netcoreapp3.1/EFSecondLevelCache.Core.AspNetCoreSample.dll",
"args": [],
"cwd": "${workspaceRoot}/src/Tests/EFSecondLevelCache.Core.AspNetCoreSample",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart",
"launchBrowser": {
"enabled": true,
"args": "${auto-detect-url}",
"windows": {
"command": "cmd.exe",
"args": "/C start ${auto-detect-url}"
},
"osx": {
"command": "open"
},
"linux": {
"command": "xdg-open"
}
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceRoot}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"workbench.colorCustomizations": {
"activityBar.background": "#7295b1",
"activityBar.activeBorder": "#e8d6e0",
"activityBar.foreground": "#15202b",
"activityBar.inactiveForeground": "#15202b99",
"activityBarBadge.background": "#e8d6e0",
"activityBarBadge.foreground": "#15202b",
"titleBar.activeBackground": "#557c9b",
"titleBar.inactiveBackground": "#557c9b99",
"titleBar.activeForeground": "#e7e7e7",
"titleBar.inactiveForeground": "#e7e7e799",
"statusBar.background": "#557c9b",
"statusBarItem.hoverBackground": "#7295b1",
"statusBar.foreground": "#e7e7e7"
},
"peacock.color": "#557c9b"
}
================================================
FILE: .vscode/tasks.json
================================================
{
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"args": [
"${workspaceRoot}/src/Tests/EFSecondLevelCache.Core.AspNetCoreSample/EFSecondLevelCache.Core.AspNetCoreSample.csproj"
],
"isBuildCommand": true,
"problemMatcher": "$msCompile"
}
]
}
================================================
FILE: EFSecondLevelCache.Core.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0C0EA45E-C765-4D41-A1DA-EDDC8F239A5B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{312DDEFA-6800-4297-9B38-0C458BB28FED}"
ProjectSection(SolutionItems) = preProject
LICENSE.md = LICENSE.md
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFSecondLevelCache.Core", "src\EFSecondLevelCache.Core\EFSecondLevelCache.Core.csproj", "{755D6A18-E67A-4E14-8289-BD33A901C52B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFSecondLevelCache.Core.Tests", "src\Tests\EFSecondLevelCache.Core.Tests\EFSecondLevelCache.Core.Tests.csproj", "{5475D985-85D6-4DD2-899E-8E8B333B0070}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EFSecondLevelCache.Core.AspNetCoreSample", "src\Tests\EFSecondLevelCache.Core.AspNetCoreSample\EFSecondLevelCache.Core.AspNetCoreSample.csproj", "{EB8B44EC-D677-47B3-8A72-3E340BFDF0DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFSecondLevelCache.Core.NET46Sample", "src\Tests\EFSecondLevelCache.Core.NET46Sample\EFSecondLevelCache.Core.NET46Sample\EFSecondLevelCache.Core.NET46Sample.csproj", "{CEE7F26B-7A7E-4021-A37F-F9625EAF85CE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{4D31E9D7-B686-44FF-8BCD-C17BA26A0333}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Issues", "Issues", "{EDE35C41-BFB7-492F-A8FD-C13FB276486C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Issue15", "src\Tests\Issues\Issue15\Issue15.csproj", "{767215E4-AF19-4AD0-968C-532BE14AF75A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFSecondLevelCache.Core.PerformanceTests", "src\Tests\EFSecondLevelCache.Core.PerformanceTests\EFSecondLevelCache.Core.PerformanceTests.csproj", "{01DE3CF0-AA97-43B3-B95C-45184DF223CB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Issue43", "src\Tests\Issues\Issue43\Issue43.csproj", "{65D28CEA-604F-4283-BDEE-9D6B669A37E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{755D6A18-E67A-4E14-8289-BD33A901C52B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{755D6A18-E67A-4E14-8289-BD33A901C52B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{755D6A18-E67A-4E14-8289-BD33A901C52B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{755D6A18-E67A-4E14-8289-BD33A901C52B}.Release|Any CPU.Build.0 = Release|Any CPU
{5475D985-85D6-4DD2-899E-8E8B333B0070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5475D985-85D6-4DD2-899E-8E8B333B0070}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5475D985-85D6-4DD2-899E-8E8B333B0070}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5475D985-85D6-4DD2-899E-8E8B333B0070}.Release|Any CPU.Build.0 = Release|Any CPU
{EB8B44EC-D677-47B3-8A72-3E340BFDF0DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB8B44EC-D677-47B3-8A72-3E340BFDF0DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB8B44EC-D677-47B3-8A72-3E340BFDF0DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB8B44EC-D677-47B3-8A72-3E340BFDF0DE}.Release|Any CPU.Build.0 = Release|Any CPU
{CEE7F26B-7A7E-4021-A37F-F9625EAF85CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CEE7F26B-7A7E-4021-A37F-F9625EAF85CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CEE7F26B-7A7E-4021-A37F-F9625EAF85CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CEE7F26B-7A7E-4021-A37F-F9625EAF85CE}.Release|Any CPU.Build.0 = Release|Any CPU
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Debug|x64.ActiveCfg = Debug|x64
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Debug|x64.Build.0 = Debug|x64
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Debug|x86.ActiveCfg = Debug|x86
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Debug|x86.Build.0 = Debug|x86
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Release|Any CPU.Build.0 = Release|Any CPU
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Release|x64.ActiveCfg = Release|x64
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Release|x64.Build.0 = Release|x64
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Release|x86.ActiveCfg = Release|x86
{767215E4-AF19-4AD0-968C-532BE14AF75A}.Release|x86.Build.0 = Release|x86
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Release|Any CPU.Build.0 = Release|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Debug|x64.ActiveCfg = Debug|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Debug|x64.Build.0 = Debug|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Debug|x86.ActiveCfg = Debug|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Debug|x86.Build.0 = Debug|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Release|x64.ActiveCfg = Release|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Release|x64.Build.0 = Release|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Release|x86.ActiveCfg = Release|Any CPU
{01DE3CF0-AA97-43B3-B95C-45184DF223CB}.Release|x86.Build.0 = Release|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Release|Any CPU.Build.0 = Release|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Debug|x64.ActiveCfg = Debug|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Debug|x64.Build.0 = Debug|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Debug|x86.ActiveCfg = Debug|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Debug|x86.Build.0 = Debug|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Release|x64.ActiveCfg = Release|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Release|x64.Build.0 = Release|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Release|x86.ActiveCfg = Release|Any CPU
{65D28CEA-604F-4283-BDEE-9D6B669A37E1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{755D6A18-E67A-4E14-8289-BD33A901C52B} = {0C0EA45E-C765-4D41-A1DA-EDDC8F239A5B}
{5475D985-85D6-4DD2-899E-8E8B333B0070} = {0C0EA45E-C765-4D41-A1DA-EDDC8F239A5B}
{EB8B44EC-D677-47B3-8A72-3E340BFDF0DE} = {0C0EA45E-C765-4D41-A1DA-EDDC8F239A5B}
{CEE7F26B-7A7E-4021-A37F-F9625EAF85CE} = {0C0EA45E-C765-4D41-A1DA-EDDC8F239A5B}
{4D31E9D7-B686-44FF-8BCD-C17BA26A0333} = {0C0EA45E-C765-4D41-A1DA-EDDC8F239A5B}
{EDE35C41-BFB7-492F-A8FD-C13FB276486C} = {4D31E9D7-B686-44FF-8BCD-C17BA26A0333}
{767215E4-AF19-4AD0-968C-532BE14AF75A} = {EDE35C41-BFB7-492F-A8FD-C13FB276486C}
{01DE3CF0-AA97-43B3-B95C-45184DF223CB} = {4D31E9D7-B686-44FF-8BCD-C17BA26A0333}
{65D28CEA-604F-4283-BDEE-9D6B669A37E1} = {EDE35C41-BFB7-492F-A8FD-C13FB276486C}
EndGlobalSection
EndGlobal
================================================
FILE: LICENSE.md
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# [Announcing a better Second Level Caching Library!](https://github.com/VahidN/EFSecondLevelCache.Core/issues/67)
# EFSecondLevelCache.Core
Entity Framework Core Second Level Caching Library.
Second level caching is a query cache. The results of EF commands will be stored in the cache, so that the same EF commands will retrieve their data from the cache rather than executing them against the database again.
## Install via NuGet
To install EFSecondLevelCache.Core, run the following command in the Package Manager Console:
[](https://github.com/VahidN/EFSecondLevelCache.Core)
```
PM> Install-Package EFSecondLevelCache.Core
```
You can also view the [package page](http://www.nuget.org/packages/EFSecondLevelCache.Core/) on NuGet.
This library also uses the [CacheManager.Core](https://github.com/MichaCo/CacheManager), as a highly configurable cache manager.
To use its in-memory caching mechanism, add these entries to the `.csproj` file:
```xml
```
And to get the latest versions of these libraries you can run the following command in the Package Manager Console:
```
PM> Update-Package
```
## Usage
1- [Register the required services](/src/Tests/EFSecondLevelCache.Core.AspNetCoreSample/Startup.cs) of `EFSecondLevelCache.Core` and also `CacheManager.Core`
```csharp
namespace EFSecondLevelCache.Core.AspNetCoreSample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddEFSecondLevelCache();
// Add an in-memory cache service provider
services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
services.AddSingleton(typeof(ICacheManagerConfiguration),
new CacheManager.Core.ConfigurationBuilder()
.WithJsonSerializer()
.WithMicrosoftMemoryCacheHandle(instanceName: "MemoryCache1")
.WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10))
.Build());
}
}
}
```
If you want to use the Redis as the preferred cache provider, first install the `CacheManager.StackExchange.Redis` package and then register its required services:
```csharp
// Add Redis cache service provider
var jss = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
const string redisConfigurationKey = "redis";
services.AddSingleton(typeof(ICacheManagerConfiguration),
new CacheManager.Core.ConfigurationBuilder()
.WithJsonSerializer(serializationSettings: jss, deserializationSettings: jss)
.WithUpdateMode(CacheUpdateMode.Up)
.WithRedisConfiguration(redisConfigurationKey, config =>
{
config.WithAllowAdmin()
.WithDatabase(0)
.WithEndpoint("localhost", 6379)
// Enables keyspace notifications to react on eviction/expiration of items.
// Make sure that all servers are configured correctly and 'notify-keyspace-events' is at least set to 'Exe', otherwise CacheManager will not retrieve any events.
// See https://redis.io/topics/notifications#configuration for configuration details.
.EnableKeyspaceEvents();
})
.WithMaxRetries(100)
.WithRetryTimeout(50)
.WithRedisCacheHandle(redisConfigurationKey)
.WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10))
.Build());
services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
```
2- [Setting up the cache invalidation](/src/Tests/EFSecondLevelCache.Core.AspNetCoreSample/DataLayer/SampleContext.cs) by overriding the SaveChanges method to prevent stale reads:
```csharp
namespace EFSecondLevelCache.Core.AspNetCoreSample.DataLayer
{
public class SampleContext : DbContext
{
public SampleContext(DbContextOptions options) : base(options)
{ }
public virtual DbSet Posts { get; set; }
public override int SaveChanges()
{
var changedEntityNames = this.GetChangedEntityNames();
this.ChangeTracker.AutoDetectChangesEnabled = false; // for performance reasons, to avoid calling DetectChanges() again.
var result = base.SaveChanges();
this.ChangeTracker.AutoDetectChangesEnabled = true;
this.GetService().InvalidateCacheDependencies(changedEntityNames);
return result;
}
}
}
```
3- Then to cache the results of the normal queries like:
```csharp
var products = context.Products.Include(x => x.Tags).FirstOrDefault();
```
We can use the new `Cacheable()` extension method:
```csharp
// If you don't specify the `EFCachePolicy`, the global `new CacheManager.Core.ConfigurationBuilder().WithExpiration()` setting will be used automatically.
var products = context.Products.Include(x => x.Tags).Cacheable().FirstOrDefault(); // Async methods are supported too.
// Or you can specify the `EFCachePolicy` explicitly to override the global settings.
var post1 = context.Posts
.Where(x => x.Id > 0)
.OrderBy(x => x.Id)
.Cacheable(CacheExpirationMode.Sliding, TimeSpan.FromMinutes(5))
.FirstOrDefault();
// NOTE: It's better to add the `Cacheable()` method before the materialization methods such as `ToList()` or `FirstOrDefault()` to cover the whole expression tree.
```
Also AutoMapper's `ProjectTo()` method is supported:
```csharp
var posts = context.Posts
.Where(x => x.Id > 0)
.OrderBy(x => x.Id)
.Cacheable()
.ProjectTo(configuration: _mapper.ConfigurationProvider)
.ToList();
```
## Guidance
### When to use
Good candidates for query caching are global site settings and public data, such as infrequently changing articles or comments. It can also be beneficial to cache data specific to a user so long as the cache expires frequently enough relative to the size of the user base that memory consumption remains acceptable. Small, per-user data that frequently exceeds the cache's lifetime, such as a user's photo path, is better held in user claims, which are stored in cookies, than in this cache.
### Scope
This cache is scoped to the application, not the current user. It does not use session variables. Accordingly, when retriveing cached per-user data, be sure queries in include code such as `.Where(x => .... && x.UserId == id)`.
### Invalidation
This cache is updated when an entity is changed (insert, update, or delete) via a DbContext that uses this library. If the database is updated through some other means, such as a stored procedure or trigger, the cache becomes stale.
================================================
FILE: global.json
================================================
{
"sdk": {
"version": "3.1.101"
}
}
================================================
FILE: src/EFSecondLevelCache.Core/Contracts/EFCacheDebugInfo.cs
================================================
namespace EFSecondLevelCache.Core.Contracts
{
///
/// Stores the debug information of the caching process.
///
public class EFCacheDebugInfo
{
///
/// Stores information of the computed key of the input LINQ query.
///
public EFCacheKey EFCacheKey { set; get; }
///
/// Determines this query is using the 2nd level cache or not.
///
public bool IsCacheHit { set; get; }
}
}
================================================
FILE: src/EFSecondLevelCache.Core/Contracts/EFCacheKey.cs
================================================
using System.Collections.Generic;
namespace EFSecondLevelCache.Core.Contracts
{
///
/// Stores information of the computed key of the input LINQ query.
///
public class EFCacheKey
{
///
/// The computed key of the input LINQ query.
///
public string Key { set; get; }
///
/// Hash of the input LINQ query's computed key.
///
public string KeyHash { set; get; }
///
/// Determines which entities are used in this LINQ query.
/// This array will be used to invalidate the related cache of all related queries automatically.
///
public ISet CacheDependencies { set; get; }
///
/// Stores information of the computed key of the input LINQ query.
///
public EFCacheKey()
{
CacheDependencies = new HashSet();
}
///
/// Equals
///
///
///
public override bool Equals(object obj)
{
var efCacheKey = obj as EFCacheKey;
if (efCacheKey == null)
return false;
return this.KeyHash == efCacheKey.KeyHash;
}
///
/// GetHashCode
///
///
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = hash * 23 + KeyHash.GetHashCode();
return hash;
}
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/Contracts/EFQueryDebugView.cs
================================================
using System.Collections.Generic;
namespace EFSecondLevelCache.Core.Contracts
{
///
/// Expression and its Dependencies
///
public class EFQueryDebugView
{
///
/// Dependency items.
///
public ISet Types { set; get; }
///
/// Expression to a readable string.
///
public string DebugView { set; get; }
}
}
================================================
FILE: src/EFSecondLevelCache.Core/Contracts/IEFCacheKeyHashProvider.cs
================================================
namespace EFSecondLevelCache.Core.Contracts
{
///
/// The CacheKey Hash Provider Contract.
///
public interface IEFCacheKeyHashProvider
{
///
/// Computes the unique hash of the input.
///
/// the input data to hash
/// Hashed data
string ComputeHash(string data);
}
}
================================================
FILE: src/EFSecondLevelCache.Core/Contracts/IEFCacheKeyProvider.cs
================================================
using System.Linq;
using System.Linq.Expressions;
namespace EFSecondLevelCache.Core.Contracts
{
///
/// CacheKeyProvider Contract.
///
public interface IEFCacheKeyProvider
{
///
/// Gets an EF query and returns its hash to store in the cache.
///
/// The EF query.
/// An expression tree that represents a LINQ query.
/// If you think the computed hash of the query is not enough, set this value.
/// Information of the computed key of the input LINQ query.
EFCacheKey GetEFCacheKey(IQueryable query, Expression expression, string saltKey = "");
}
}
================================================
FILE: src/EFSecondLevelCache.Core/Contracts/IEFCacheServiceProvider.cs
================================================
using System.Collections.Generic;
namespace EFSecondLevelCache.Core.Contracts
{
///
/// Cache Service Provider Contract.
///
public interface IEFCacheServiceProvider
{
///
/// Removes the cached entries added by this library.
///
void ClearAllCachedEntries();
///
/// Gets a cached entry by key.
///
/// key to find
/// cached value
object GetValue(string cacheKey);
///
/// Adds a new item to the cache.
///
/// key
/// value
/// cache dependencies
/// Defines the expiration mode of the cache item. If you set it to null, the global `new CacheManager.Core.ConfigurationBuilder().WithExpiration()` setting will be used automatically.
void InsertValue(string cacheKey, object value, ISet rootCacheKeys, EFCachePolicy cachePolicy);
///
/// Invalidates all of the cache entries which are dependent on any of the specified root keys.
///
/// cache dependencies
void InvalidateCacheDependencies(string[] rootCacheKeys);
///
/// Some cache providers won't accept null values.
/// So we need a custom Null object here. It should be defined `static readonly` in your code.
///
object NullObject { get; }
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFAsyncEnumerable.cs
================================================
using System.Collections.Generic;
using System.Threading;
namespace EFSecondLevelCache.Core
{
///
/// Asynchronous version of the IEnumerable interface, allowing elements of the enumerable sequence to be retrieved asynchronously.
///
public class EFAsyncEnumerable : IAsyncEnumerable
{
private readonly IEnumerator _inner;
///
/// Asynchronous version of the IEnumerable interface
///
public EFAsyncEnumerable(IEnumerator inner)
{
_inner = inner;
}
///
/// Gets an asynchronous enumerator over the sequence.
///
public IAsyncEnumerator GetEnumerator()
{
return new EFAsyncEnumerator(_inner);
}
///
/// Gets an asynchronous enumerator over the sequence.
///
public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
{
return new EFAsyncEnumerator(_inner);
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFAsyncEnumerator.cs
================================================
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace EFSecondLevelCache.Core
{
///
/// Asynchronous version of the IEnumerator of T interface that allows elements to be retrieved asynchronously.
///
///
public class EFAsyncEnumerator : IAsyncEnumerator
{
private readonly IEnumerator _inner;
///
/// Asynchronous version of the IEnumerator of T interface that allows elements to be retrieved asynchronously.
///
/// The inner IEnumerator
public EFAsyncEnumerator(IEnumerator inner)
{
_inner = inner;
}
///
/// Gets the current element in the iteration.
///
public T Current => _inner.Current;
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
_inner.Dispose();
}
///
/// Advances the enumerator to the next element in the sequence, returning the result asynchronously.
///
/// A System.Threading.CancellationToken to observe while waiting for the task to complete.
/// A task that represents the asynchronous operation. The task result contains true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the sequence.
public Task MoveNext(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.FromResult(_inner.MoveNext());
}
///
/// Advances the enumerator to the next element in the sequence, returning the result asynchronously.
///
/// A task that represents the asynchronous operation. The task result contains true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the sequence.
public ValueTask MoveNextAsync()
{
return new ValueTask(_inner.MoveNext());
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public ValueTask DisposeAsync()
{
_inner.Dispose();
return default;
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFAsyncTaskEnumerable.cs
================================================
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace EFSecondLevelCache.Core
{
///
/// Asynchronous version of the IEnumerable interface, allowing elements of the enumerable sequence to be retrieved asynchronously.
///
public class EFAsyncTaskEnumerable : IAsyncEnumerable
{
private readonly Task _task;
///
/// Asynchronous version of the IEnumerable interface.
///
public EFAsyncTaskEnumerable(Task task)
{
_task = task;
}
///
/// Gets an asynchronous enumerator over the sequence.
///
public IAsyncEnumerator GetEnumerator() => new EFAsyncTaskEnumerator(_task);
///
/// Gets an asynchronous enumerator over the sequence.
///
public IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken())
{
return new EFAsyncTaskEnumerator(_task);
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFAsyncTaskEnumerator.cs
================================================
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace EFSecondLevelCache.Core
{
///
/// Asynchronous version of the IEnumerator interface, allowing elements to be retrieved asynchronously.
///
public sealed class EFAsyncTaskEnumerator : IAsyncEnumerator
{
private readonly Task _task;
private bool _moved;
///
/// Asynchronous version of the IEnumerator interface
///
public EFAsyncTaskEnumerator(Task task)
{
_task = task;
}
///
/// Gets the current element in the iteration.
///
public T Current => !_moved ? default(T) : _task.Result;
///
/// Advances the enumerator to the next element in the sequence, returning the result asynchronously.
///
public async Task MoveNext(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (!_moved)
{
await _task.ConfigureAwait(false);
_moved = true;
return _moved;
}
return false;
}
///
/// Advances the enumerator to the next element in the sequence, returning the result asynchronously.
///
public ValueTask MoveNextAsync()
{
return new ValueTask(MoveNext(new CancellationToken()));
}
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public ValueTask DisposeAsync()
{
return default;
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFCacheKeyHashProvider.cs
================================================
using System;
using EFSecondLevelCache.Core.Contracts;
namespace EFSecondLevelCache.Core
{
///
/// Computes the unique hash of the input, using the xxHash algorithm.
///
public class EFCacheKeyHashProvider : IEFCacheKeyHashProvider
{
///
/// Computes the unique hash of the input.
///
/// the input data to hash
/// Hashed data using the xxHash algorithm
public string ComputeHash(string data)
{
if(string.IsNullOrWhiteSpace(data))
throw new ArgumentNullException(nameof(data));
return $"{XxHashUnsafe.ComputeHash(data):X}";
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFCacheKeyProvider3x.cs
================================================
using System.Linq;
using System.Linq.Expressions;
using EFSecondLevelCache.Core.Contracts;
using System;
using CacheManager.Core;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore;
namespace EFSecondLevelCache.Core
{
///
/// A custom cache key provider for EF queries.
///
public class EFCacheKeyProvider : IEFCacheKeyProvider
{
private static readonly TypeInfo _queryCompilerTypeInfo = typeof(QueryCompiler).GetTypeInfo();
private static readonly FieldInfo _queryCompilerField =
typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryCompiler");
private static readonly FieldInfo _queryContextFactoryField =
_queryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryContextFactory");
private static readonly FieldInfo _loggerField =
_queryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_logger");
private static readonly TimeSpan _slidingExpirationTimeSpan = TimeSpan.FromMinutes(7);
private static readonly ICacheManager _keysCacheManager =
EFStaticServiceProvider.Instance.GetRequiredService>();
private readonly IEFCacheKeyHashProvider _cacheKeyHashProvider;
///
/// A custom cache key provider for EF queries.
///
/// Provides the custom hashing algorithm.
public EFCacheKeyProvider(IEFCacheKeyHashProvider cacheKeyHashProvider)
{
_cacheKeyHashProvider = cacheKeyHashProvider;
}
///
/// Gets an EF query and returns its hashed key to store in the cache.
///
/// The EF query.
/// An expression tree that represents a LINQ query.
/// If you think the computed hash of the query is not enough, set this value.
/// Information of the computed key of the input LINQ query.
public EFCacheKey GetEFCacheKey(IQueryable query, Expression expression, string saltKey = "")
{
var queryCompiler = (QueryCompiler)_queryCompilerField.GetValue(query.Provider);
var (expressionKeyHash, modifiedExpression) = getExpressionKeyHash(queryCompiler, _cacheKeyHashProvider, expression);
var cachedKey = _keysCacheManager.Get(expressionKeyHash);
if (cachedKey != null)
{
return cachedKey;
}
var expressionPrinter = new ExpressionPrinter();
var sql = expressionPrinter.PrintDebug(modifiedExpression);
var expressionVisitorResult = EFQueryExpressionVisitor.GetDebugView(expression);
var key = $"{sql};{expressionVisitorResult.DebugView};{saltKey}";
var keyHash = _cacheKeyHashProvider.ComputeHash(key);
var cacheKey = new EFCacheKey
{
Key = key,
KeyHash = keyHash,
CacheDependencies = expressionVisitorResult.Types
};
setCache(expressionKeyHash, cacheKey);
return cacheKey;
}
private static void setCache(string expressionKeyHash, EFCacheKey value)
{
_keysCacheManager.Add(
new CacheItem(expressionKeyHash, value, ExpirationMode.Sliding, _slidingExpirationTimeSpan));
}
private static (string ExpressionKeyHash, Expression ModifiedExpression) getExpressionKeyHash(
QueryCompiler queryCompiler,
IEFCacheKeyHashProvider cacheKeyHashProvider,
Expression expression)
{
var queryContextFactory = (IQueryContextFactory)_queryContextFactoryField.GetValue(queryCompiler);
var queryContext = queryContextFactory.Create();
var logger = (IDiagnosticsLogger)_loggerField.GetValue(queryCompiler);
expression = queryCompiler.ExtractParameters(expression, queryContext, logger, parameterize: false);
var expressionKey = $"{ExpressionEqualityComparer.Instance.GetHashCode(expression)};";
var parameterValues = queryContext.ParameterValues;
if (parameterValues.Any())
{
expressionKey = parameterValues.Aggregate(expressionKey,
(current, item) => current + $"{item.Key}={item.Value?.GetHashCode()};");
}
return (cacheKeyHashProvider.ComputeHash(expressionKey), expression);
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFCachePolicy.cs
================================================
using System;
namespace EFSecondLevelCache.Core
{
///
/// Defines the supported expiration modes for cache items.
///
public enum CacheExpirationMode
{
///
/// Defines absolute expiration. The item will expire after the expiration timeout.
///
Absolute,
///
/// Defines sliding expiration. The expiration timeout will be refreshed on every access.
///
Sliding
}
///
/// EFCachePolicy determines the Expiration time of the cache.
/// If you don't define it, the global `new CacheManager.Core.ConfigurationBuilder().WithExpiration()` setting will be used automatically.
///
public class EFCachePolicy
{
///
/// Defines the expiration mode of the cache item.
/// Its default value is Absolute.
///
public CacheExpirationMode ExpirationMode { set; get; }
///
/// The expiration timeout.
/// Its default value is 20 minutes later.
///
///
public TimeSpan Timeout { set; get; } = TimeSpan.FromMinutes(20);
///
/// If you think the computed hash of the query to calculate the cache-key is not enough, set this value.
/// Its default value is string.Empty.
///
public string SaltKey { set; get; } = string.Empty;
///
/// EFCachePolicy determines the Expiration time of the cache.
///
public EFCachePolicy() { }
///
/// EFCachePolicy determines the Expiration time of the cache.
///
/// Defines the expiration mode of the cache item.
/// The expiration timeout.
public EFCachePolicy(CacheExpirationMode expirationMode, TimeSpan timeout)
{
ExpirationMode = expirationMode;
Timeout = timeout;
}
///
/// EFCachePolicy determines the Expiration time of the cache.
///
/// Defines the expiration mode of the cache item.
/// The expiration timeout.
/// If you think the computed hash of the query to calculate the cache-key is not enough, set this value.
public EFCachePolicy(CacheExpirationMode expirationMode, TimeSpan timeout, string saltKey)
{
ExpirationMode = expirationMode;
Timeout = timeout;
SaltKey = saltKey;
}
}
}
================================================
FILE: src/EFSecondLevelCache.Core/EFCacheServiceProvider.cs
================================================
using System.Collections.Generic;
using System.Threading;
using Microsoft.Extensions.DependencyInjection;
using CacheManager.Core;
using EFSecondLevelCache.Core.Contracts;
namespace EFSecondLevelCache.Core
{
///
/// Using ICacheManager as a cache service.
///
public class EFCacheServiceProvider : IEFCacheServiceProvider
{
private static readonly EFCacheKey _nullObject = new EFCacheKey();
private static readonly ICacheManager> _dependenciesCacheManager =
EFStaticServiceProvider.Instance.GetRequiredService>>();
private static readonly ICacheManager