mirror of https://github.com/abpframework/abp.git
405 changed files with 10230 additions and 4439 deletions
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53450/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Authentication.OAuth": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53451/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53760/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.MultiTenancy": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53763/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:52302/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.Client": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:52303/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:61183/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.Bootstrap": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"launchUrl": "http://localhost:5000", |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53762/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.Bundling": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53765/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:56918/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.TenantSwitch": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:56919/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53766/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.Packages": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53768/" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy |
|||
{ |
|||
public class UppyScriptContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/uppy/uppy.min.js"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Uppy |
|||
{ |
|||
public class UppyStyleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/libs/uppy/uppy.min.css"); |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:50398/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:50399/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:51544/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:51545/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53761/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI.Widgets": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53764/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:55913/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc.UI": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"launchUrl": "http://localhost:5000", |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53767/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Mvc": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53769/" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Microsoft.AspNetCore.Mvc.DataAnnotations; |
|||
using Microsoft.Extensions.Localization; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.DataAnnotations |
|||
{ |
|||
public class AbpValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider |
|||
{ |
|||
private readonly ValidationAttributeAdapterProvider _defaultAdapter; |
|||
|
|||
public AbpValidationAttributeAdapterProvider(ValidationAttributeAdapterProvider defaultAdapter) |
|||
{ |
|||
_defaultAdapter = defaultAdapter; |
|||
} |
|||
|
|||
public virtual IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer) |
|||
{ |
|||
var type = attribute.GetType(); |
|||
|
|||
if (type == typeof(DynamicStringLengthAttribute)) |
|||
{ |
|||
return new DynamicStringLengthAttributeAdapter((DynamicStringLengthAttribute) attribute, stringLocalizer); |
|||
} |
|||
|
|||
return _defaultAdapter.GetAttributeAdapter(attribute, stringLocalizer); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
using System; |
|||
using System.Globalization; |
|||
using Microsoft.AspNetCore.Mvc.DataAnnotations; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; |
|||
using Microsoft.Extensions.Localization; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.DataAnnotations |
|||
{ |
|||
public class DynamicStringLengthAttributeAdapter : AttributeAdapterBase<DynamicStringLengthAttribute> |
|||
{ |
|||
private readonly string _max; |
|||
private readonly string _min; |
|||
|
|||
public DynamicStringLengthAttributeAdapter( |
|||
DynamicStringLengthAttribute attribute, |
|||
IStringLocalizer stringLocalizer) |
|||
: base(attribute, stringLocalizer) |
|||
{ |
|||
_max = Attribute.MaximumLength.ToString(CultureInfo.InvariantCulture); |
|||
_min = Attribute.MinimumLength.ToString(CultureInfo.InvariantCulture); |
|||
} |
|||
|
|||
public override void AddValidation(ClientModelValidationContext context) |
|||
{ |
|||
Check.NotNull(context, nameof(context)); |
|||
|
|||
MergeAttribute(context.Attributes, "data-val", "true"); |
|||
MergeAttribute(context.Attributes, "data-val-length", GetErrorMessage(context)); |
|||
|
|||
if (Attribute.MaximumLength != int.MaxValue) |
|||
{ |
|||
MergeAttribute(context.Attributes, "data-val-length-max", _max); |
|||
} |
|||
|
|||
if (Attribute.MinimumLength != 0) |
|||
{ |
|||
MergeAttribute(context.Attributes, "data-val-length-min", _min); |
|||
} |
|||
} |
|||
|
|||
public override string GetErrorMessage(ModelValidationContextBase validationContext) |
|||
{ |
|||
Check.NotNull(validationContext, nameof(validationContext)); |
|||
|
|||
return GetErrorMessage( |
|||
validationContext.ModelMetadata, |
|||
validationContext.ModelMetadata.GetDisplayName(), |
|||
Attribute.MaximumLength, |
|||
Attribute.MinimumLength |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:61851/", |
|||
"sslPort": 44301 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.Serilog": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:5001;http://localhost:5000" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53900/", |
|||
"sslPort": 44362 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.SignalR": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:5001;http://localhost:5000" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53783/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore.TestBase": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53784/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:53374/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.AspNetCore": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:53375/" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
using System.Text.RegularExpressions; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.BlobStoring.Azure |
|||
{ |
|||
public class AzureBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency |
|||
{ |
|||
/// <summary>
|
|||
///https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names
|
|||
/// </summary>
|
|||
public virtual string NormalizeContainerName(string containerName) |
|||
{ |
|||
// All letters in a container name must be lowercase.
|
|||
containerName = containerName.ToLower(); |
|||
|
|||
// Container names can contain only letters, numbers, and the dash (-) character.
|
|||
containerName = Regex.Replace(containerName, "[^a-z0-9-]", string.Empty); |
|||
|
|||
// Every dash (-) character must be immediately preceded and followed by a letter or number;
|
|||
// consecutive dashes are not permitted in container names.
|
|||
// Container names must start or end with a letter or number
|
|||
containerName = Regex.Replace(containerName, "-{2,}", "-"); |
|||
containerName = Regex.Replace(containerName, "^-", string.Empty); |
|||
containerName = Regex.Replace(containerName, "-$", string.Empty); |
|||
|
|||
// Container names must be from 3 through 63 characters long.
|
|||
if (containerName.Length < 3) |
|||
{ |
|||
var length = containerName.Length; |
|||
for (var i = 0; i < 3 - length; i++) |
|||
{ |
|||
containerName += "0"; |
|||
} |
|||
} |
|||
|
|||
if (containerName.Length > 63) |
|||
{ |
|||
containerName = containerName.Substring(0, 63); |
|||
} |
|||
|
|||
return containerName; |
|||
} |
|||
|
|||
/// <summary>
|
|||
///https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#blob-names
|
|||
/// </summary>
|
|||
public virtual string NormalizeBlobName(string blobName) |
|||
{ |
|||
return blobName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using System; |
|||
using System.Runtime; |
|||
using System.Runtime.InteropServices; |
|||
using System.Text.RegularExpressions; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public class FileSystemBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency |
|||
{ |
|||
private readonly IOSPlatformProvider _iosPlatformProvider; |
|||
|
|||
public FileSystemBlobNamingNormalizer(IOSPlatformProvider iosPlatformProvider) |
|||
{ |
|||
_iosPlatformProvider = iosPlatformProvider; |
|||
} |
|||
|
|||
public virtual string NormalizeContainerName(string containerName) |
|||
{ |
|||
return Normalize(containerName); |
|||
} |
|||
|
|||
public virtual string NormalizeBlobName(string blobName) |
|||
{ |
|||
return Normalize(blobName); |
|||
} |
|||
|
|||
protected virtual string Normalize(string fileName) |
|||
{ |
|||
var os = _iosPlatformProvider.GetCurrentOSPlatform(); |
|||
if (os == OSPlatform.Windows) |
|||
{ |
|||
// A filename cannot contain any of the following characters: \ / : * ? " < > |
|
|||
// In order to support the directory included in the blob name, remove / and \
|
|||
fileName = Regex.Replace(fileName, "[:\\*\\?\"<>\\|]", string.Empty); |
|||
} |
|||
|
|||
return fileName; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.Abp.BlobStoring |
|||
{ |
|||
public interface IBlobNamingNormalizer |
|||
{ |
|||
string NormalizeContainerName(string containerName); |
|||
|
|||
string NormalizeBlobName(string blobName); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,25 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.Caching.StackExchangeRedis</AssemblyName> |
|||
<PackageId>Volo.Abp.Caching.StackExchangeRedis</PackageId> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="3.1.5" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using Microsoft.Extensions.Caching.Distributed; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.DependencyInjection.Extensions; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.Caching.StackExchangeRedis |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpCachingModule) |
|||
)] |
|||
public class AbpCachingStackExchangeRedisModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
context.Services.AddStackExchangeRedisCache(options => |
|||
{ |
|||
var redisConfiguration = configuration["Redis:Configuration"]; |
|||
if (!redisConfiguration.IsNullOrEmpty()) |
|||
{ |
|||
options.Configuration = configuration["Redis:Configuration"]; |
|||
} |
|||
}); |
|||
|
|||
context.Services.Replace(ServiceDescriptor.Singleton<IDistributedCache, AbpRedisCache>()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,294 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Caching.Distributed; |
|||
using Microsoft.Extensions.Caching.StackExchangeRedis; |
|||
using Microsoft.Extensions.Options; |
|||
using StackExchange.Redis; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Caching.StackExchangeRedis |
|||
{ |
|||
[DisableConventionalRegistration] |
|||
public class AbpRedisCache : RedisCache, ICacheSupportsMultipleItems |
|||
{ |
|||
protected static readonly string SetScript; |
|||
protected static readonly string AbsoluteExpirationKey; |
|||
protected static readonly string SlidingExpirationKey; |
|||
protected static readonly string DataKey; |
|||
protected static readonly long NotPresent; |
|||
|
|||
private static readonly FieldInfo RedisDatabaseField; |
|||
private static readonly MethodInfo ConnectMethod; |
|||
private static readonly MethodInfo ConnectAsyncMethod; |
|||
private static readonly MethodInfo MapMetadataMethod; |
|||
private static readonly MethodInfo GetAbsoluteExpirationMethod; |
|||
private static readonly MethodInfo GetExpirationInSecondsMethod; |
|||
|
|||
protected IDatabase RedisDatabase => GetRedisDatabase(); |
|||
private IDatabase _redisDatabase; |
|||
|
|||
protected string Instance { get; } |
|||
|
|||
static AbpRedisCache() |
|||
{ |
|||
var type = typeof(RedisCache); |
|||
|
|||
RedisDatabaseField = type.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic); |
|||
|
|||
ConnectMethod = type.GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic); |
|||
|
|||
ConnectAsyncMethod = type.GetMethod("ConnectAsync", BindingFlags.Instance | BindingFlags.NonPublic); |
|||
|
|||
MapMetadataMethod = type.GetMethod("MapMetadata", BindingFlags.Instance | BindingFlags.NonPublic); |
|||
|
|||
GetAbsoluteExpirationMethod = type.GetMethod("GetAbsoluteExpiration", BindingFlags.Static | BindingFlags.NonPublic); |
|||
|
|||
GetExpirationInSecondsMethod = type.GetMethod("GetExpirationInSeconds", BindingFlags.Static | BindingFlags.NonPublic); |
|||
|
|||
SetScript = type.GetField("SetScript", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString(); |
|||
|
|||
AbsoluteExpirationKey = type.GetField("AbsoluteExpirationKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString(); |
|||
|
|||
SlidingExpirationKey = type.GetField("SlidingExpirationKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString(); |
|||
|
|||
DataKey = type.GetField("DataKey", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).ToString(); |
|||
|
|||
NotPresent = type.GetField("NotPresent", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null).To<int>(); |
|||
} |
|||
|
|||
public AbpRedisCache(IOptions<RedisCacheOptions> optionsAccessor) |
|||
: base(optionsAccessor) |
|||
{ |
|||
Instance = optionsAccessor.Value.InstanceName ?? string.Empty; |
|||
} |
|||
|
|||
protected virtual void Connect() |
|||
{ |
|||
if (GetRedisDatabase() != null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
ConnectMethod.Invoke(this, Array.Empty<object>()); |
|||
} |
|||
|
|||
protected virtual Task ConnectAsync(CancellationToken token = default) |
|||
{ |
|||
if (GetRedisDatabase() != null) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
return (Task) ConnectAsyncMethod.Invoke(this, new object[] {token}); |
|||
} |
|||
|
|||
public byte[][] GetMany( |
|||
IEnumerable<string> keys) |
|||
{ |
|||
keys = Check.NotNull(keys, nameof(keys)); |
|||
|
|||
return GetAndRefreshMany(keys, true); |
|||
} |
|||
|
|||
public async Task<byte[][]> GetManyAsync( |
|||
IEnumerable<string> keys, |
|||
CancellationToken token = default) |
|||
{ |
|||
keys = Check.NotNull(keys, nameof(keys)); |
|||
|
|||
return await GetAndRefreshManyAsync(keys, true, token); |
|||
} |
|||
|
|||
public void SetMany( |
|||
IEnumerable<KeyValuePair<string, byte[]>> items, |
|||
DistributedCacheEntryOptions options) |
|||
{ |
|||
Connect(); |
|||
|
|||
Task.WaitAll(PipelineSetMany(items, options)); |
|||
} |
|||
|
|||
public async Task SetManyAsync( |
|||
IEnumerable<KeyValuePair<string, byte[]>> items, |
|||
DistributedCacheEntryOptions options, |
|||
CancellationToken token = default) |
|||
{ |
|||
token.ThrowIfCancellationRequested(); |
|||
|
|||
await ConnectAsync(token); |
|||
|
|||
await Task.WhenAll(PipelineSetMany(items, options)); |
|||
} |
|||
|
|||
protected virtual byte[][] GetAndRefreshMany( |
|||
IEnumerable<string> keys, |
|||
bool getData) |
|||
{ |
|||
Connect(); |
|||
|
|||
var keyArray = keys.Select(key => Instance + key).ToArray(); |
|||
RedisValue[][] results; |
|||
|
|||
if (getData) |
|||
{ |
|||
results = RedisDatabase.HashMemberGetMany(keyArray, AbsoluteExpirationKey, |
|||
SlidingExpirationKey, DataKey); |
|||
} |
|||
else |
|||
{ |
|||
results = RedisDatabase.HashMemberGetMany(keyArray, AbsoluteExpirationKey, |
|||
SlidingExpirationKey); |
|||
} |
|||
|
|||
Task.WaitAll(PipelineRefreshManyAndOutData(keyArray, results, out var bytes)); |
|||
|
|||
return bytes; |
|||
} |
|||
|
|||
protected virtual async Task<byte[][]> GetAndRefreshManyAsync( |
|||
IEnumerable<string> keys, |
|||
bool getData, |
|||
CancellationToken token = default) |
|||
{ |
|||
token.ThrowIfCancellationRequested(); |
|||
|
|||
await ConnectAsync(token); |
|||
|
|||
var keyArray = keys.Select(key => Instance + key).ToArray(); |
|||
RedisValue[][] results; |
|||
|
|||
if (getData) |
|||
{ |
|||
results = await RedisDatabase.HashMemberGetManyAsync(keyArray, AbsoluteExpirationKey, |
|||
SlidingExpirationKey, DataKey); |
|||
} |
|||
else |
|||
{ |
|||
results = await RedisDatabase.HashMemberGetManyAsync(keyArray, AbsoluteExpirationKey, |
|||
SlidingExpirationKey); |
|||
} |
|||
|
|||
await Task.WhenAll(PipelineRefreshManyAndOutData(keyArray, results, out var bytes)); |
|||
|
|||
return bytes; |
|||
} |
|||
|
|||
protected virtual Task[] PipelineRefreshManyAndOutData( |
|||
string[] keys, |
|||
RedisValue[][] results, |
|||
out byte[][] bytes) |
|||
{ |
|||
bytes = new byte[keys.Length][]; |
|||
var tasks = new Task[keys.Length]; |
|||
|
|||
for (var i = 0; i < keys.Length; i++) |
|||
{ |
|||
if (results[i].Length >= 2) |
|||
{ |
|||
MapMetadata(results[i], out DateTimeOffset? absExpr, out TimeSpan? sldExpr); |
|||
|
|||
if (sldExpr.HasValue) |
|||
{ |
|||
TimeSpan? expr; |
|||
|
|||
if (absExpr.HasValue) |
|||
{ |
|||
var relExpr = absExpr.Value - DateTimeOffset.Now; |
|||
expr = relExpr <= sldExpr.Value ? relExpr : sldExpr; |
|||
} |
|||
else |
|||
{ |
|||
expr = sldExpr; |
|||
} |
|||
|
|||
tasks[i] = RedisDatabase.KeyExpireAsync(keys[i], expr); |
|||
} |
|||
else |
|||
{ |
|||
tasks[i] = Task.CompletedTask; |
|||
} |
|||
} |
|||
|
|||
if (results[i].Length >= 3 && results[i][2].HasValue) |
|||
{ |
|||
bytes[i] = results[i][2]; |
|||
} |
|||
else |
|||
{ |
|||
bytes[i] = null; |
|||
} |
|||
} |
|||
|
|||
return tasks; |
|||
} |
|||
|
|||
protected virtual Task[] PipelineSetMany( |
|||
IEnumerable<KeyValuePair<string, byte[]>> items, |
|||
DistributedCacheEntryOptions options) |
|||
{ |
|||
items = Check.NotNull(items, nameof(items)); |
|||
options = Check.NotNull(options, nameof(options)); |
|||
|
|||
var itemArray = items.ToArray(); |
|||
var tasks = new Task[itemArray.Length]; |
|||
var creationTime = DateTimeOffset.UtcNow; |
|||
var absoluteExpiration = GetAbsoluteExpiration(creationTime, options); |
|||
|
|||
for (var i = 0; i < itemArray.Length; i++) |
|||
{ |
|||
tasks[i] = RedisDatabase.ScriptEvaluateAsync(SetScript, new RedisKey[] {Instance + itemArray[i].Key}, |
|||
new RedisValue[] |
|||
{ |
|||
absoluteExpiration?.Ticks ?? NotPresent, |
|||
options.SlidingExpiration?.Ticks ?? NotPresent, |
|||
GetExpirationInSeconds(creationTime, absoluteExpiration, options) ?? NotPresent, |
|||
itemArray[i].Value |
|||
}); |
|||
} |
|||
|
|||
return tasks; |
|||
} |
|||
|
|||
protected virtual void MapMetadata( |
|||
RedisValue[] results, |
|||
out DateTimeOffset? absoluteExpiration, |
|||
out TimeSpan? slidingExpiration) |
|||
{ |
|||
var parameters = new object[] {results, null, null}; |
|||
MapMetadataMethod.Invoke(this, parameters); |
|||
|
|||
absoluteExpiration = (DateTimeOffset?) parameters[1]; |
|||
slidingExpiration = (TimeSpan?) parameters[2]; |
|||
} |
|||
|
|||
protected virtual long? GetExpirationInSeconds( |
|||
DateTimeOffset creationTime, |
|||
DateTimeOffset? absoluteExpiration, |
|||
DistributedCacheEntryOptions options) |
|||
{ |
|||
return (long?) GetExpirationInSecondsMethod.Invoke(null, |
|||
new object[] {creationTime, absoluteExpiration, options}); |
|||
} |
|||
|
|||
protected virtual DateTimeOffset? GetAbsoluteExpiration( |
|||
DateTimeOffset creationTime, |
|||
DistributedCacheEntryOptions options) |
|||
{ |
|||
return (DateTimeOffset?) GetAbsoluteExpirationMethod.Invoke(null, new object[] {creationTime, options}); |
|||
} |
|||
|
|||
private IDatabase GetRedisDatabase() |
|||
{ |
|||
if (_redisDatabase == null) |
|||
{ |
|||
_redisDatabase = RedisDatabaseField.GetValue(this) as IDatabase; |
|||
} |
|||
|
|||
return _redisDatabase; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using StackExchange.Redis; |
|||
|
|||
namespace Volo.Abp.Caching.StackExchangeRedis |
|||
{ |
|||
public static class AbpRedisExtensions |
|||
{ |
|||
public static RedisValue[][] HashMemberGetMany( |
|||
this IDatabase cache, |
|||
string[] keys, |
|||
params string[] members) |
|||
{ |
|||
var tasks = new Task<RedisValue[]>[keys.Length]; |
|||
var fields = members.Select(member => (RedisValue) member).ToArray(); |
|||
var results = new RedisValue[keys.Length][]; |
|||
|
|||
for (var i = 0; i < keys.Length; i++) |
|||
{ |
|||
tasks[i] = cache.HashGetAsync((RedisKey) keys[i], fields); |
|||
} |
|||
|
|||
for (var i = 0; i < tasks.Length; i++) |
|||
{ |
|||
results[i] = cache.Wait(tasks[i]); |
|||
} |
|||
|
|||
return results; |
|||
} |
|||
|
|||
public static async Task<RedisValue[][]> HashMemberGetManyAsync( |
|||
this IDatabase cache, |
|||
string[] keys, |
|||
params string[] members) |
|||
{ |
|||
var tasks = new Task<RedisValue[]>[keys.Length]; |
|||
var fields = members.Select(member => (RedisValue) member).ToArray(); |
|||
|
|||
for (var i = 0; i < keys.Length; i++) |
|||
{ |
|||
tasks[i] = cache.HashGetAsync((RedisKey) keys[i], fields); |
|||
} |
|||
|
|||
return await Task.WhenAll(tasks); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Caching.Distributed; |
|||
|
|||
namespace Volo.Abp.Caching |
|||
{ |
|||
public interface ICacheSupportsMultipleItems |
|||
{ |
|||
byte[][] GetMany( |
|||
IEnumerable<string> keys |
|||
); |
|||
|
|||
Task<byte[][]> GetManyAsync( |
|||
IEnumerable<string> keys, |
|||
CancellationToken token = default |
|||
); |
|||
|
|||
void SetMany( |
|||
IEnumerable<KeyValuePair<string, byte[]>> items, |
|||
DistributedCacheEntryOptions options |
|||
); |
|||
|
|||
Task SetManyAsync( |
|||
IEnumerable<KeyValuePair<string, byte[]>> items, |
|||
DistributedCacheEntryOptions options, |
|||
CancellationToken token = default |
|||
); |
|||
} |
|||
} |
|||
@ -1,7 +0,0 @@ |
|||
{ |
|||
"profiles": { |
|||
"Volo.Abp.Cli": { |
|||
"commandName": "Project" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Runtime.InteropServices; |
|||
|
|||
namespace System.Runtime |
|||
{ |
|||
public interface IOSPlatformProvider |
|||
{ |
|||
OSPlatform GetCurrentOSPlatform(); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
using System.Runtime.InteropServices; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace System.Runtime |
|||
{ |
|||
public class OSPlatformProvider : IOSPlatformProvider, ITransientDependency |
|||
{ |
|||
public virtual OSPlatform GetCurrentOSPlatform() |
|||
{ |
|||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) |
|||
{ |
|||
return OSPlatform.OSX; //MAC
|
|||
} |
|||
|
|||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
|||
{ |
|||
return OSPlatform.Windows; |
|||
} |
|||
|
|||
return OSPlatform.Linux; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Diagnostics; |
|||
using System.Reflection; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Validation |
|||
{ |
|||
/// <summary>
|
|||
/// Used to determine <see cref="StringLengthAttribute.MaximumLength"/> and <see cref="StringLengthAttribute.MinimumLength"/>
|
|||
/// properties on the runtime.
|
|||
/// </summary>
|
|||
public class DynamicStringLengthAttribute : StringLengthAttribute |
|||
{ |
|||
private static readonly FieldInfo MaximumLengthField; |
|||
|
|||
static DynamicStringLengthAttribute() |
|||
{ |
|||
MaximumLengthField = typeof(StringLengthAttribute).GetField( |
|||
"<MaximumLength>k__BackingField", |
|||
BindingFlags.Instance | BindingFlags.NonPublic |
|||
); |
|||
Debug.Assert(MaximumLengthField != null, nameof(MaximumLengthField) + " != null"); |
|||
} |
|||
|
|||
/// <param name="sourceType">A type to get the values of the properties</param>
|
|||
/// <param name="maximumLengthPropertyName">The name of the public static property for the <see cref="StringLengthAttribute.MaximumLength"/></param>
|
|||
/// <param name="minimumLengthPropertyName">The name of the public static property for the <see cref="StringLengthAttribute.MinimumLength"/></param>
|
|||
public DynamicStringLengthAttribute( |
|||
[NotNull] Type sourceType, |
|||
[CanBeNull] string maximumLengthPropertyName, |
|||
[CanBeNull] string minimumLengthPropertyName = null) |
|||
: base(0) |
|||
{ |
|||
Check.NotNull(sourceType, nameof(sourceType)); |
|||
|
|||
if (maximumLengthPropertyName != null) |
|||
{ |
|||
var maximumLengthProperty = sourceType.GetProperty( |
|||
maximumLengthPropertyName, |
|||
BindingFlags.Static | BindingFlags.Public |
|||
); |
|||
Debug.Assert(maximumLengthProperty != null, nameof(maximumLengthProperty) + " != null"); |
|||
MaximumLengthField.SetValue(this, (int) maximumLengthProperty.GetValue(null)); |
|||
} |
|||
|
|||
if (minimumLengthPropertyName != null) |
|||
{ |
|||
var minimumLengthProperty = sourceType.GetProperty( |
|||
minimumLengthPropertyName, |
|||
BindingFlags.Static | BindingFlags.Public |
|||
); |
|||
Debug.Assert(minimumLengthProperty != null, nameof(minimumLengthProperty) + " != null"); |
|||
MinimumLength = (int) minimumLengthProperty.GetValue(null); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:52306/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.Http.Client.IdentityModel": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:52307/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:52306/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.Http.Client.IdentityModel": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:52307/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:52208/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.Http.Client": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:52209/" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System.Collections.Generic; |
|||
using MongoDB.Driver; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MongoDB |
|||
{ |
|||
public interface IMongoDbRepositoryFilterer<TEntity> where TEntity : class, IEntity |
|||
{ |
|||
void AddGlobalFilters(List<FilterDefinition<TEntity>> filters); |
|||
} |
|||
|
|||
public interface IMongoDbRepositoryFilterer<TEntity, TKey> : IMongoDbRepositoryFilterer<TEntity> where TEntity : class, IEntity<TKey> |
|||
{ |
|||
FilterDefinition<TEntity> CreateEntityFilter(TKey id, bool applyFilters = false); |
|||
|
|||
FilterDefinition<TEntity> CreateEntityFilter(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null); |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
using System.Collections.Generic; |
|||
using MongoDB.Driver; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
namespace Volo.Abp.Domain.Repositories.MongoDB |
|||
{ |
|||
public class MongoDbRepositoryFilterer<TEntity> : IMongoDbRepositoryFilterer<TEntity> |
|||
where TEntity : class, IEntity |
|||
{ |
|||
protected IDataFilter DataFilter { get; } |
|||
|
|||
protected ICurrentTenant CurrentTenant { get; } |
|||
|
|||
public MongoDbRepositoryFilterer(IDataFilter dataFilter, ICurrentTenant currentTenant) |
|||
{ |
|||
DataFilter = dataFilter; |
|||
CurrentTenant = currentTenant; |
|||
} |
|||
|
|||
public virtual void AddGlobalFilters(List<FilterDefinition<TEntity>> filters) |
|||
{ |
|||
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)) && DataFilter.IsEnabled<ISoftDelete>()) |
|||
{ |
|||
filters.Add(Builders<TEntity>.Filter.Eq(e => ((ISoftDelete) e).IsDeleted, false)); |
|||
} |
|||
|
|||
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity))) |
|||
{ |
|||
var tenantId = CurrentTenant.Id; |
|||
filters.Add(Builders<TEntity>.Filter.Eq(e => ((IMultiTenant) e).TenantId, tenantId)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class MongoDbRepositoryFilterer<TEntity, TKey> : MongoDbRepositoryFilterer<TEntity>, |
|||
IMongoDbRepositoryFilterer<TEntity, TKey> |
|||
where TEntity : class, IEntity<TKey> |
|||
{ |
|||
public MongoDbRepositoryFilterer(IDataFilter dataFilter, ICurrentTenant currentTenant) |
|||
: base(dataFilter, currentTenant) |
|||
{ |
|||
} |
|||
|
|||
public FilterDefinition<TEntity> CreateEntityFilter(TKey id, bool applyFilters = false) |
|||
{ |
|||
var filters = new List<FilterDefinition<TEntity>> |
|||
{ |
|||
Builders<TEntity>.Filter.Eq(e => e.Id, id) |
|||
}; |
|||
|
|||
if (applyFilters) |
|||
{ |
|||
AddGlobalFilters(filters); |
|||
} |
|||
|
|||
return Builders<TEntity>.Filter.And(filters); |
|||
} |
|||
|
|||
public FilterDefinition<TEntity> CreateEntityFilter(TEntity entity, bool withConcurrencyStamp = false, string concurrencyStamp = null) |
|||
{ |
|||
if (!withConcurrencyStamp || !(entity is IHasConcurrencyStamp entityWithConcurrencyStamp)) |
|||
{ |
|||
return Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id); |
|||
} |
|||
|
|||
if (concurrencyStamp == null) |
|||
{ |
|||
concurrencyStamp = entityWithConcurrencyStamp.ConcurrencyStamp; |
|||
} |
|||
|
|||
return Builders<TEntity>.Filter.And( |
|||
Builders<TEntity>.Filter.Eq(e => e.Id, entity.Id), |
|||
Builders<TEntity>.Filter.Eq(e => ((IHasConcurrencyStamp) e).ConcurrencyStamp, concurrencyStamp) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace Volo.Abp.Auditing.App.Entities |
|||
{ |
|||
[Audited] |
|||
public class AppEntityWithAuditedAndHasCustomAuditingProperties : AggregateRoot<Guid> |
|||
{ |
|||
protected AppEntityWithAuditedAndHasCustomAuditingProperties() |
|||
{ |
|||
} |
|||
|
|||
public AppEntityWithAuditedAndHasCustomAuditingProperties(Guid id) |
|||
: base(id) |
|||
{ |
|||
} |
|||
|
|||
public DateTime? CreationTime { get; set; } |
|||
public Guid? CreatorId { get; set; } |
|||
public DateTime? LastModificationTime { get; set; } |
|||
public Guid? LastModifierId { get; set; } |
|||
public bool IsDeleted { get; set; } |
|||
public DateTime? DeletionTime { get; set; } |
|||
public Guid? DeleterId { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
|
|||
namespace Volo.Abp.Auditing.App.Entities |
|||
{ |
|||
[Audited] |
|||
public class AppFullAuditedEntityWithAudited : FullAuditedAggregateRoot<Guid> |
|||
{ |
|||
protected AppFullAuditedEntityWithAudited() |
|||
{ |
|||
} |
|||
|
|||
public AppFullAuditedEntityWithAudited(Guid id, string name) |
|||
: base(id) |
|||
{ |
|||
Name = name; |
|||
} |
|||
|
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
using Shouldly; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.BlobStoring.Azure |
|||
{ |
|||
public class DefaultAzureBlobNamingNormalizerProvider_Tests : AbpBlobStoringAzureTestCommonBase |
|||
{ |
|||
private readonly IBlobNamingNormalizer _blobNamingNormalizer; |
|||
|
|||
public DefaultAzureBlobNamingNormalizerProvider_Tests() |
|||
{ |
|||
_blobNamingNormalizer = GetRequiredService<IBlobNamingNormalizer>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeContainerName_Lowercase() |
|||
{ |
|||
var filename = "ThisIsMyContainerName"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe("thisismycontainername"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeContainerName_Only_Letters_Numbers_Dash() |
|||
{ |
|||
var filename = ",./this-i,./s-my-c,./ont,./ai+*/.=!@#$n^&*er-name.+/"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe("this-is-my-container-name"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeContainerName_Dash() |
|||
{ |
|||
var filename = "-this--is----my-container----name-"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe("this-is-my-container-name"); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public void NormalizeContainerName_Min_Length() |
|||
{ |
|||
var filename = "a"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.Length.ShouldBeGreaterThanOrEqualTo(3); |
|||
} |
|||
|
|||
|
|||
[Fact] |
|||
public void NormalizeContainerName_Max_Length() |
|||
{ |
|||
var filename = "abpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabpabp"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.Length.ShouldBeLessThanOrEqualTo(63); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using System.Runtime; |
|||
using System.Runtime.InteropServices; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using NSubstitute; |
|||
using Shouldly; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.BlobStoring.FileSystem |
|||
{ |
|||
public class DefaultFileSystemBlobNamingNormalizerProvider_Tests : AbpBlobStoringFileSystemTestBase |
|||
{ |
|||
private readonly IBlobNamingNormalizer _blobNamingNormalizer; |
|||
|
|||
public DefaultFileSystemBlobNamingNormalizerProvider_Tests() |
|||
{ |
|||
_blobNamingNormalizer = GetRequiredService<IBlobNamingNormalizer>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
var _iosPlatformProvider = Substitute.For<IOSPlatformProvider>(); |
|||
_iosPlatformProvider.GetCurrentOSPlatform().Returns(OSPlatform.Windows); |
|||
services.AddSingleton(_iosPlatformProvider); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeContainerName() |
|||
{ |
|||
var filename = "thisismy:*?\"<>|foldername"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe("thisismyfoldername"); |
|||
} |
|||
|
|||
[Fact] |
|||
public void NormalizeBlobName() |
|||
{ |
|||
var filename = "thisismy:*?\"<>|filename"; |
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe("thisismyfilename"); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData("/")] |
|||
[InlineData("\\")] |
|||
public void NormalizeContainerName_With_Directory(string delimiter) |
|||
{ |
|||
var filename = $"thisis{delimiter}my:*?\"<>|{delimiter}foldername";
|
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe($"thisis{delimiter}my{delimiter}foldername"); |
|||
} |
|||
|
|||
[Theory] |
|||
[InlineData("/")] |
|||
[InlineData("\\")] |
|||
public void NormalizeBlobName_With_Directory(string delimiter) |
|||
{ |
|||
var filename = $"thisis{delimiter}my:*?\"<>|{delimiter}filename";
|
|||
filename = _blobNamingNormalizer.NormalizeContainerName(filename); |
|||
filename.ShouldBe($"thisis{delimiter}my{delimiter}filename"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\common.test.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
|||
<ProjectReference Include="..\..\src\Volo.Abp.Caching.StackExchangeRedis\Volo.Abp.Caching.StackExchangeRedis.csproj" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,12 @@ |
|||
using Volo.Abp.Testing; |
|||
|
|||
namespace Volo.Abp.Caching.StackExchangeRedis |
|||
{ |
|||
public abstract class AbpCachingStackExchangeRedisTestBase : AbpIntegratedTest<AbpCachingStackExchangeRedisTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.Caching.StackExchangeRedis |
|||
{ |
|||
[DependsOn( |
|||
typeof(AbpCachingStackExchangeRedisModule), |
|||
typeof(AbpTestBaseModule), |
|||
typeof(AbpAutofacModule) |
|||
)] |
|||
public class AbpCachingStackExchangeRedisTestModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
using Microsoft.Extensions.Caching.Distributed; |
|||
using Shouldly; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Caching.StackExchangeRedis |
|||
{ |
|||
public class AbpRedisCache_Tests : AbpCachingStackExchangeRedisTestBase |
|||
{ |
|||
private readonly IDistributedCache _distributedCache; |
|||
|
|||
public AbpRedisCache_Tests() |
|||
{ |
|||
_distributedCache = GetRequiredService<IDistributedCache>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Replace_RedisCache() |
|||
{ |
|||
(_distributedCache is AbpRedisCache).ShouldBeTrue(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:49583/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.Account.Web.IdentityServer": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:49584/" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
@page "/Account/LoggedOut" |
|||
@model Volo.Abp.Account.Web.Pages.Account.LoggedOutModel |
|||
@using Volo.Abp.Account.Localization |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Web.Pages.Account |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
|
|||
@section scripts { |
|||
<abp-script-bundle name="@typeof(LoggedOutModel).FullName"> |
|||
<abp-script src="/Pages/Account/LoggedOut.js"/> |
|||
</abp-script-bundle> |
|||
} |
|||
|
|||
@section styles { |
|||
<abp-style src="/Pages/Account/LoggedOut.css"/> |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-body> |
|||
<abp-card-title>@L["LoggedOutTitle"]</abp-card-title> |
|||
<abp-card-text>@L["LoggedOutText"]</abp-card-text> |
|||
@if (Model.PostLogoutRedirectUri != null) |
|||
{ |
|||
<a abp-button="Primary" id="redirectButton" href="@Model.PostLogoutRedirectUri">@L["ReturnToText", Model.ClientName]</a> |
|||
} |
|||
@if (Model.SignOutIframeUrl != null) |
|||
{ |
|||
<iframe class="signout logoutiframe" src="@Model.SignOutIframeUrl"></iframe> |
|||
} |
|||
</abp-card-body> |
|||
</abp-card> |
|||
@ -0,0 +1,30 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
|
|||
namespace Volo.Abp.Account.Web.Pages.Account |
|||
{ |
|||
public class LoggedOutModel : AccountPageModel |
|||
{ |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ClientName { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string SignOutIframeUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string PostLogoutRedirectUri { get; set; } |
|||
|
|||
public virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
return Task.FromResult<IActionResult>(Page()); |
|||
} |
|||
|
|||
public virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
return Task.FromResult<IActionResult>(Page()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
.logoutiframe { |
|||
display: none; |
|||
width:0; |
|||
height: 0; |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
document.addEventListener("DOMContentLoaded", function (event) { |
|||
setTimeout(function () { |
|||
window.location = document.getElementById("redirectButton").getAttribute("href"); |
|||
}, 3000) |
|||
}); |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:56009/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.Account.Web": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:56013/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:50000/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Blogging.Web": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:50014/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:50000/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Blogging.Web": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:50014/" |
|||
} |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:51023/", |
|||
"sslPort": 0 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.ClientSimulation.Web": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "http://localhost:51024/" |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue