mirror of https://github.com/abpframework/abp.git
443 changed files with 10999 additions and 4979 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,13 +1,17 @@ |
|||||
@using Localization.Resources.AbpUi |
@using Localization.Resources.AbpUi |
||||
@using Microsoft.Extensions.Localization |
@using Microsoft.Extensions.Localization |
||||
|
|
||||
@inject IStringLocalizer<AbpUiResource> L |
@inject IStringLocalizer<AbpUiResource> L |
||||
|
|
||||
<form method="post" class="page-search-form"> |
<form method="post" class="page-search-form"> |
||||
<div class="input-group"> |
<div class="input-group"> |
||||
<input class="form-control page-search-filter-text" placeholder="@L["Search"].Value"> |
<input class="form-control page-search-filter-text" placeholder="@L["Search"].Value" /> |
||||
<div class="input-group-append"> |
<div class="input-group-append"> |
||||
<abp-button button-type="Primary" type="submit"> |
<abp-button button-type="Primary" type="submit"> |
||||
<i class="fa fa-search" aria-hidden="true" style="margin-left: 10%; margin-top:50%;" ></i> |
<i class="fa fa-search" aria-hidden="true"></i> |
||||
</abp-button> |
</abp-button> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
</form> |
</form> |
||||
|
|
||||
|
|
||||
|
|||||
@ -0,0 +1,4 @@ |
|||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
||||
|
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
||||
|
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
||||
|
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
@ -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/" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue