|
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 41 KiB |
@ -0,0 +1,57 @@ |
|||
using System; |
|||
using Microsoft.Extensions.FileProviders; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Caching; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
[Dependency(ReplaceServices = true)] |
|||
public class CachedBundleDynamicFileProvider : DynamicFileProvider |
|||
{ |
|||
protected IDistributedCache<InMemoryFileInfoCacheItem> Cache { get; } |
|||
protected IOptions<AbpBundlingOptions> BundlingOptions { get; } |
|||
|
|||
public CachedBundleDynamicFileProvider( |
|||
IDistributedCache<InMemoryFileInfoCacheItem> cache, |
|||
IOptions<AbpBundlingOptions> bundlingOptions) |
|||
{ |
|||
Cache = cache; |
|||
BundlingOptions = bundlingOptions; |
|||
} |
|||
|
|||
public override IFileInfo GetFileInfo(string? subpath) |
|||
{ |
|||
var fileInfo = base.GetFileInfo(subpath); |
|||
|
|||
if (!subpath.IsNullOrWhiteSpace() && fileInfo is NotFoundFileInfo && |
|||
subpath.Contains(BundlingOptions.Value.BundleFolderName, StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
var filePath = NormalizePath(subpath); |
|||
var cacheItem = Cache.Get(filePath); |
|||
if (cacheItem == null) |
|||
{ |
|||
return fileInfo; |
|||
} |
|||
|
|||
fileInfo = new InMemoryFileInfo(filePath, cacheItem.FileContent, cacheItem.Name); |
|||
DynamicFiles.AddOrUpdate(filePath, fileInfo, (key, value) => fileInfo); |
|||
} |
|||
|
|||
return fileInfo; |
|||
} |
|||
|
|||
public override void AddOrUpdate(IFileInfo fileInfo) |
|||
{ |
|||
var filePath = fileInfo.GetVirtualOrPhysicalPathOrNull(); |
|||
Cache.GetOrAdd(filePath!, () => new InMemoryFileInfoCacheItem(filePath!, fileInfo.ReadBytes(), fileInfo.Name)); |
|||
base.AddOrUpdate(fileInfo); |
|||
} |
|||
|
|||
public override bool Delete(string filePath) |
|||
{ |
|||
Cache.Remove(filePath); |
|||
return base.Delete(filePath); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using System; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
[Serializable] |
|||
[IgnoreMultiTenancy] |
|||
public class InMemoryFileInfoCacheItem |
|||
{ |
|||
public InMemoryFileInfoCacheItem(string dynamicPath, byte[] fileContent, string name) |
|||
{ |
|||
DynamicPath = dynamicPath; |
|||
Name = name; |
|||
FileContent = fileContent; |
|||
} |
|||
|
|||
public string DynamicPath { get; set; } |
|||
|
|||
public string Name { get; set; } |
|||
|
|||
public byte[] FileContent { get; set; } |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection; |
|||
|
|||
public static class AbpEfCoreDbContextOptionsBuilderExtensions |
|||
{ |
|||
public static DbContextOptionsBuilder AddAbpDbContextOptionsExtension(this DbContextOptionsBuilder optionsBuilder) |
|||
{ |
|||
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(new AbpDbContextOptionsExtension()); |
|||
return optionsBuilder; |
|||
} |
|||
|
|||
public static DbContextOptionsBuilder<TContext> AddAbpDbContextOptionsExtension<TContext>(this DbContextOptionsBuilder<TContext> optionsBuilder) |
|||
where TContext : DbContext |
|||
{ |
|||
((IDbContextOptionsBuilderInfrastructure) optionsBuilder).AddOrUpdateExtension(new AbpDbContextOptionsExtension()); |
|||
return optionsBuilder; |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.EntityFrameworkCore.Query.SqlExpressions; |
|||
using Volo.Abp; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection; |
|||
|
|||
public static class AbpEfCoreModelBuilderExtensions |
|||
{ |
|||
public static ModelBuilder ConfigureSoftDeleteDbFunction(this ModelBuilder modelBuilder, MethodInfo methodInfo, AbpEfCoreCurrentDbContext abpEfCoreCurrentDbContext) |
|||
{ |
|||
modelBuilder.HasDbFunction(methodInfo) |
|||
.HasTranslation(args => |
|||
{ |
|||
// (bool isDeleted, bool boolParam)
|
|||
var isDeleted = args[0]; |
|||
var boolParam = args[1]; |
|||
|
|||
if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled<ISoftDelete>() == true) |
|||
{ |
|||
// IsDeleted == false
|
|||
return new SqlBinaryExpression( |
|||
ExpressionType.Equal, |
|||
isDeleted, |
|||
new SqlConstantExpression(Expression.Constant(false), boolParam.TypeMapping), |
|||
boolParam.Type, |
|||
boolParam.TypeMapping); |
|||
} |
|||
|
|||
// empty where sql
|
|||
return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping); |
|||
}); |
|||
|
|||
return modelBuilder; |
|||
} |
|||
|
|||
public static ModelBuilder ConfigureMultiTenantDbFunction(this ModelBuilder modelBuilder, MethodInfo methodInfo, AbpEfCoreCurrentDbContext abpEfCoreCurrentDbContext) |
|||
{ |
|||
modelBuilder.HasDbFunction(methodInfo) |
|||
.HasTranslation(args => |
|||
{ |
|||
// (Guid? tenantId, int? currentTenantId)
|
|||
var tenantId = args[0]; |
|||
var currentTenantId = args[1]; |
|||
var boolParam = args[2]; |
|||
|
|||
if (abpEfCoreCurrentDbContext.Context?.DataFilter.IsEnabled<IMultiTenant>() == true) |
|||
{ |
|||
// TenantId == CurrentTenantId
|
|||
return new SqlBinaryExpression( |
|||
ExpressionType.Equal, |
|||
tenantId, |
|||
currentTenantId, |
|||
boolParam.Type, |
|||
boolParam.TypeMapping); |
|||
} |
|||
|
|||
// empty where sql
|
|||
return new SqlConstantExpression(Expression.Constant(true), boolParam.TypeMapping); |
|||
}); |
|||
|
|||
return modelBuilder; |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Microsoft.EntityFrameworkCore.Query; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore; |
|||
|
|||
public class AbpDbContextOptionsExtension : IDbContextOptionsExtension |
|||
{ |
|||
public void ApplyServices(IServiceCollection services) |
|||
{ |
|||
var serviceDescriptor = services.FirstOrDefault(x => x.ServiceType == typeof(ICompiledQueryCacheKeyGenerator)); |
|||
if (serviceDescriptor != null && serviceDescriptor.ImplementationType != null) |
|||
{ |
|||
services.Remove(serviceDescriptor); |
|||
services.AddScoped(serviceDescriptor.ImplementationType); |
|||
services.Add(ServiceDescriptor.Scoped<ICompiledQueryCacheKeyGenerator>(provider => |
|||
ActivatorUtilities.CreateInstance<AbpCompiledQueryCacheKeyGenerator>(provider, |
|||
provider.GetRequiredService(serviceDescriptor.ImplementationType) |
|||
.As<ICompiledQueryCacheKeyGenerator>()))); |
|||
} |
|||
|
|||
services.Replace(ServiceDescriptor.Scoped<IAsyncQueryProvider, AbpEntityQueryProvider>()); |
|||
services.AddSingleton(typeof(AbpEfCoreCurrentDbContext)); |
|||
} |
|||
|
|||
public void Validate(IDbContextOptions options) |
|||
{ |
|||
} |
|||
|
|||
public DbContextOptionsExtensionInfo Info => new AbpOptionsExtensionInfo(this); |
|||
|
|||
private class AbpOptionsExtensionInfo : DbContextOptionsExtensionInfo |
|||
{ |
|||
public AbpOptionsExtensionInfo(IDbContextOptionsExtension extension) |
|||
: base(extension) |
|||
{ |
|||
} |
|||
|
|||
public override bool IsDatabaseProvider => false; |
|||
|
|||
public override int GetServiceProviderHashCode() |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) |
|||
{ |
|||
return other is AbpOptionsExtensionInfo; |
|||
} |
|||
|
|||
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo) |
|||
{ |
|||
} |
|||
|
|||
public override string LogFragment => "AbpOptionsExtension"; |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
using System.Linq.Expressions; |
|||
using System.Threading; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Microsoft.EntityFrameworkCore.Query.Internal; |
|||
using Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore; |
|||
|
|||
#pragma warning disable EF1001
|
|||
public class AbpEntityQueryProvider : EntityQueryProvider |
|||
{ |
|||
protected AbpEfCoreCurrentDbContext AbpEfCoreCurrentDbContext { get; } |
|||
protected ICurrentDbContext CurrentDbContext { get; } |
|||
|
|||
public AbpEntityQueryProvider( |
|||
IQueryCompiler queryCompiler, |
|||
AbpEfCoreCurrentDbContext abpEfCoreCurrentDbContext, |
|||
ICurrentDbContext currentDbContext) |
|||
: base(queryCompiler) |
|||
{ |
|||
AbpEfCoreCurrentDbContext = abpEfCoreCurrentDbContext; |
|||
CurrentDbContext = currentDbContext; |
|||
} |
|||
|
|||
public override object Execute(Expression expression) |
|||
{ |
|||
using (AbpEfCoreCurrentDbContext.Use(CurrentDbContext.Context as IAbpEfCoreDbFunctionContext)) |
|||
{ |
|||
return base.Execute(expression); |
|||
} |
|||
} |
|||
|
|||
public override TResult Execute<TResult>(Expression expression) |
|||
{ |
|||
using (AbpEfCoreCurrentDbContext.Use(CurrentDbContext.Context as IAbpEfCoreDbFunctionContext)) |
|||
{ |
|||
return base.Execute<TResult>(expression); |
|||
} |
|||
} |
|||
|
|||
public override TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = new CancellationToken()) |
|||
{ |
|||
using (AbpEfCoreCurrentDbContext.Use(CurrentDbContext.Context as IAbpEfCoreDbFunctionContext)) |
|||
{ |
|||
return base.ExecuteAsync<TResult>(expression, cancellationToken); |
|||
} |
|||
} |
|||
} |
|||
#pragma warning restore EF1001
|
|||
@ -0,0 +1,59 @@ |
|||
using System; |
|||
using System.Linq.Expressions; |
|||
using Microsoft.EntityFrameworkCore.Infrastructure; |
|||
using Microsoft.EntityFrameworkCore.Query; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
public class AbpCompiledQueryCacheKeyGenerator : ICompiledQueryCacheKeyGenerator |
|||
{ |
|||
protected ICompiledQueryCacheKeyGenerator InnerCompiledQueryCacheKeyGenerator { get; } |
|||
protected ICurrentDbContext CurrentContext { get; } |
|||
|
|||
public AbpCompiledQueryCacheKeyGenerator( |
|||
ICompiledQueryCacheKeyGenerator innerCompiledQueryCacheKeyGenerator, |
|||
ICurrentDbContext currentContext) |
|||
{ |
|||
InnerCompiledQueryCacheKeyGenerator = innerCompiledQueryCacheKeyGenerator; |
|||
CurrentContext = currentContext; |
|||
} |
|||
|
|||
public virtual object GenerateCacheKey(Expression query, bool async) |
|||
{ |
|||
var cacheKey = InnerCompiledQueryCacheKeyGenerator.GenerateCacheKey(query, async); |
|||
if (CurrentContext.Context is IAbpEfCoreDbFunctionContext abpEfCoreDbFunctionContext) |
|||
{ |
|||
return new AbpCompiledQueryCacheKey(cacheKey, abpEfCoreDbFunctionContext.GetCompiledQueryCacheKey()); |
|||
} |
|||
|
|||
return cacheKey; |
|||
} |
|||
|
|||
private readonly struct AbpCompiledQueryCacheKey : IEquatable<AbpCompiledQueryCacheKey> |
|||
{ |
|||
private readonly object _compiledQueryCacheKey; |
|||
private readonly string _currentFilterCacheKey; |
|||
|
|||
public AbpCompiledQueryCacheKey(object compiledQueryCacheKey, string currentFilterCacheKey) |
|||
{ |
|||
_compiledQueryCacheKey = compiledQueryCacheKey; |
|||
_currentFilterCacheKey = currentFilterCacheKey; |
|||
} |
|||
|
|||
public override bool Equals(object? obj) |
|||
{ |
|||
return obj is AbpCompiledQueryCacheKey key && Equals(key); |
|||
} |
|||
|
|||
public bool Equals(AbpCompiledQueryCacheKey other) |
|||
{ |
|||
return _compiledQueryCacheKey.Equals(other._compiledQueryCacheKey) && |
|||
_currentFilterCacheKey == other._currentFilterCacheKey; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return HashCode.Combine(_compiledQueryCacheKey, _currentFilterCacheKey); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using System.Threading; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
public class AbpEfCoreCurrentDbContext |
|||
{ |
|||
private readonly AsyncLocal<IAbpEfCoreDbFunctionContext?> _current = new AsyncLocal<IAbpEfCoreDbFunctionContext?>(); |
|||
|
|||
public IAbpEfCoreDbFunctionContext? Context => _current.Value; |
|||
|
|||
public IDisposable Use(IAbpEfCoreDbFunctionContext? context) |
|||
{ |
|||
var previousValue = Context; |
|||
_current.Value = context; |
|||
return new DisposeAction(() => |
|||
{ |
|||
_current.Value = previousValue; |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
public static class AbpEfCoreDataFilterDbFunctionMethods |
|||
{ |
|||
public const string NotSupportedExceptionMessage = "Your EF Core database provider does not support 'User-defined function mapping'." + |
|||
"Please set 'UseDbFunction' of 'AbpEfCoreGlobalFilterOptions' to false to disable it." + |
|||
"See https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping for more information." ; |
|||
|
|||
public static bool SoftDeleteFilter(bool isDeleted, bool boolParam) |
|||
{ |
|||
throw new NotSupportedException(NotSupportedExceptionMessage); |
|||
} |
|||
|
|||
public static MethodInfo SoftDeleteFilterMethodInfo => typeof(AbpEfCoreDataFilterDbFunctionMethods).GetMethod(nameof(SoftDeleteFilter))!; |
|||
|
|||
public static bool MultiTenantFilter(Guid? tenantId, Guid? currentTenantId, bool boolParam) |
|||
{ |
|||
throw new NotSupportedException(NotSupportedExceptionMessage); |
|||
} |
|||
|
|||
public static MethodInfo MultiTenantFilterMethodInfo => typeof(AbpEfCoreDataFilterDbFunctionMethods).GetMethod(nameof(MultiTenantFilter))!; |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
public class AbpEfCoreGlobalFilterOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Use User-defined function mapping to filter data.
|
|||
/// https://learn.microsoft.com/en-us/ef/core/querying/user-defined-function-mapping
|
|||
/// </summary>
|
|||
public bool UseDbFunction { get; set; } |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.GlobalFilters; |
|||
|
|||
public interface IAbpEfCoreDbFunctionContext |
|||
{ |
|||
IAbpLazyServiceProvider LazyServiceProvider { get; set; } |
|||
|
|||
ICurrentTenant CurrentTenant { get; } |
|||
|
|||
IDataFilter DataFilter { get; } |
|||
|
|||
string GetCompiledQueryCacheKey(); |
|||
} |
|||
@ -1,6 +1,12 @@ |
|||
document.addEventListener('DOMContentLoaded', function (event) { |
|||
document.addEventListener("DOMContentLoaded", function (event) { |
|||
setTimeout(function () { |
|||
window.clientName = document.getElementById("redirectButton").getAttribute("cname"); |
|||
window.location = document.getElementById('redirectButton').getAttribute('href'); |
|||
}, 3000); |
|||
var redirectButton = document.getElementById("redirectButton"); |
|||
|
|||
if(!redirectButton){ |
|||
return; |
|||
} |
|||
|
|||
redirectButton.getAttribute("cname"); |
|||
redirectButton.getAttribute("href"); |
|||
}, 3000) |
|||
}); |
|||
|
|||