Browse Source

Merge branch 'dev' into net6

pull/9700/head
maliming 5 years ago
parent
commit
b64da714b8
  1. 9
      common.props
  2. 140
      docs/en/API/Swagger-Integration.md
  3. 23
      docs/en/Background-Jobs-Hangfire.md
  4. 3
      docs/en/Swagger.md
  5. 7
      docs/en/Validation.md
  6. 4
      docs/en/docs-nav.json
  7. 7
      docs/zh-Hans/Validation.md
  8. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
  9. 5
      framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs
  10. 1
      framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj
  11. 46
      framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireAuthorizationFilter.cs
  12. 2
      framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireModule.cs
  13. 14
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  14. 1
      framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj
  15. 4
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationObjectValidationContributor.cs
  16. 6
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs
  17. 8
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidationContributor.cs
  18. 7
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs
  19. 17
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs
  20. 9
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs
  21. 6
      framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs
  22. 27
      framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs
  23. 3
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs
  24. 11
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs
  25. 16
      framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs
  26. 8
      modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs
  27. 9
      modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs
  28. 10
      modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs

9
common.props

@ -19,4 +19,13 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Content Remove="*.abppkg.json"/>
<None Include="*.abppkg.json">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

140
docs/en/API/Swagger-Integration.md

@ -0,0 +1,140 @@
# Swagger Integration
[Swagger (OpenAPI)](https://swagger.io/) is a language-agnostic specification for describing REST APIs. It allows both computers and humans to understand the capabilities of a REST API without direct access to the source code. Its main goals are to:
- Minimize the amount of work needed to connect decoupled services.
- Reduce the amount of time needed to accurately document a service.
ABP Framework offers a prebuilt module for full Swagger integration with small configurations.
## Installation
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
If installation is needed, it is suggested to use the [ABP CLI](CLI.md) to install this package.
### Using the ABP CLI
Open a command line window in the folder of the `Web` or `HttpApi.Host` project (.csproj file) and type the following command:
```bash
abp add-package Volo.Abp.Swashbuckle
```
### Manual Installation
If you want to manually install;
1. Add the [Volo.Abp.Swashbuckle](https://www.nuget.org/packages/Volo.Abp.Swashbuckle) NuGet package to your `Web` or `HttpApi.Host` project:
`Install-Package Volo.Abp.Swashbuckle`
2. Add the `AbpSwashbuckleModule` to the dependency list of your module:
```csharp
[DependsOn(
//...other dependencies
typeof(AbpSwashbuckleModule) // <-- Add module dependency like that
)]
public class YourModule : AbpModule
{
}
```
## Configuration
First, we need to use `AddAbpSwaggerGen` extension to configure Swagger in `ConfigureServices` method of our module.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = contex.Services;
//... other configarations.
services.AddAbpSwaggerGen(
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
}
);
}
```
Then we can use Swagger UI by calling `UseAbpSwaggerUI` method in the `OnApplicationInitialization` method of our module.
```csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
//... other configarations.
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test API");
});
//... other configarations.
}
```
## Using Swagger with OAUTH
For non MVC/Tiered applications, we need to configure Swagger with OAUTH to handle authorization.
> ABP Framework uses IdentityServer by default. To get more information about IDS, check this [documentation](Modules/IdentityServer.md).
To do that, we need to use `AddAbpSwaggerGenWithOAuth` extension to configure Swagger with OAuth issuer and scopes in `ConfigureServices` method of our module.
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = contex.Services;
//... other configarations.
services.AddAbpSwaggerGenWithOAuth(
"https://localhost:44341", // authority issuer
new Dictionary<string, string> //
{ // scopes
{"Test", "Test API"} //
}, //
options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
options.CustomSchemaIds(type => type.FullName);
}
);
}
```
Then we can use Swagger UI by calling `UseAbpSwaggerUI` method in the `OnApplicationInitialization` method of our module.
> Do not forget to set `OAuthClientId` and `OAuthClientSecret`.
```csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
//... other configarations.
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test API");
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
options.OAuthClientId("Test_Swagger"); // clientId
options.OAuthClientSecret("1q2w3e*"); // clientSecret
});
//... other configarations.
}
```

23
docs/en/Background-Jobs-Hangfire.md

@ -79,3 +79,26 @@ After you have installed these NuGet packages, you need to configure your projec
}
````
### Dashboard Authorization
Hangfire Dashboard provides information about your background jobs, including method names and serialized arguments as well as gives you an opportunity to manage them by performing different actions – retry, delete, trigger, etc. So it is important to restrict access to the Dashboard.
To make it secure by default, only local requests are allowed, however you can change this by following the [official documentation](http://docs.hangfire.io/en/latest/configuration/using-dashboard.html) of Hangfire.
You can integrate the Hangfire dashboard to [ABP authorization system](Authorization.md) using the **AbpHangfireAuthorizationFilter**
class. This class is defined in the `Volo.Abp.Hangfire` package. The following example, checks if the current user is logged in to the application:
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() }
});
If you want to require an additional permission, you can pass it into the constructor as below:
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter("MyHangFireDashboardPermissionName") }
});
**Important**: `UseHangfireDashboard` should be called after the authentication middleware in your `Startup` class (probably at the last line). Otherwise,
authorization will always fail!

3
docs/en/Swagger.md

@ -1,3 +0,0 @@
# Swagger UI Integration
TODO

7
docs/en/Validation.md

@ -149,8 +149,8 @@ Once ABP determines a validation error, it throws an exception of type `AbpValid
In addition to the automatic validation, you may want to manually validate an object. In this case, [inject](Dependency-Injection.md) and use the `IObjectValidator` service:
* `Validate` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
* `GetErrors` doesn't throw an exception, but only returns the validation errors.
* `ValidateAsync` method validates the given object based on the validation rules and throws an `AbpValidationException` if it is not in a valid state.
* `GetErrorsAsync` doesn't throw an exception, but only returns the validation errors.
`IObjectValidator` is implemented by the `ObjectValidator` by default. `ObjectValidator` is extensible; you can implement `IObjectValidationContributor` interface to contribute a custom logic. Example:
@ -158,13 +158,14 @@ In addition to the automatic validation, you may want to manually validate an ob
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
public void AddErrors(ObjectValidationContext context)
public Task AddErrorsAsync(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
return Task.CompletedTask;
}
}
````

4
docs/en/docs-nav.json

@ -578,6 +578,10 @@
"path": "API/Application-Configuration.md"
}
]
},
{
"text": "Swagger Integration",
"path": "API/Swagger-Integration.md"
}
]
},

7
docs/zh-Hans/Validation.md

@ -130,8 +130,8 @@ namespace Acme.BookStore
除了自动验证你可能需要手动验证对象,这种情况下[注入](Dependency-Injection.md)并使用 `IObjectValidator` 服务:
* `Validate` 方法根据验证​​规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
* `GetErrors` 不会抛出异常,只返回验证错误.
* `ValidateAsync` 方法根据验证​​规则验证给定对象,如果对象没有被验证通过会抛出 `AbpValidationException` 异常.
* `GetErrorsAsync` 不会抛出异常,只返回验证错误.
`IObjectValidator` 默认由 `ObjectValidator` 实现. `ObjectValidator`是可扩展的; 可以实现`IObjectValidationContributor`接口提供自定义逻辑.
示例 :
@ -140,13 +140,14 @@ namespace Acme.BookStore
public class MyObjectValidationContributor
: IObjectValidationContributor, ITransientDependency
{
public void AddErrors(ObjectValidationContext context)
public Task AddErrorsAsync(ObjectValidationContext context)
{
//Get the validating object
var obj = context.ValidatingObject;
//Add the validation errors if available
context.Errors.Add(...);
return Task.CompletedTask;
}
}
````

5
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -576,11 +576,12 @@ namespace Volo.Abp.Cli.ProjectModification
return;
}
var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj"));
var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj"))
?? projectFiles.FirstOrDefault(p => p.EndsWith(".EntityFrameworkCore.csproj")) ;
if (dbMigrationsProject == null)
{
Logger.LogDebug("Solution doesn't have a \".DbMigrations\" project.");
Logger.LogDebug("Solution doesn't have a Migrations project.");
if (!skipDbMigrations)
{

5
framework/src/Volo.Abp.FluentValidation/Volo/Abp/FluentValidation/FluentObjectValidationContributor.cs

@ -2,6 +2,7 @@ using FluentValidation;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Validation;
@ -17,7 +18,7 @@ namespace Volo.Abp.FluentValidation
_serviceProvider = serviceProvider;
}
public void AddErrors(ObjectValidationContext context)
public virtual async Task AddErrorsAsync(ObjectValidationContext context)
{
var serviceType = typeof(IValidator<>).MakeGenericType(context.ValidatingObject.GetType());
var validator = _serviceProvider.GetService(serviceType) as IValidator;
@ -26,7 +27,7 @@ namespace Volo.Abp.FluentValidation
return;
}
var result = validator.Validate((IValidationContext) Activator.CreateInstance(
var result = await validator.ValidateAsync((IValidationContext) Activator.CreateInstance(
typeof(ValidationContext<>).MakeGenericType(context.ValidatingObject.GetType()),
context.ValidatingObject));

1
framework/src/Volo.Abp.HangFire/Volo.Abp.HangFire.csproj

@ -19,6 +19,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Authorization.Abstractions\Volo.Abp.Authorization.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.Core\Volo.Abp.Core.csproj" />
</ItemGroup>

46
framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireAuthorizationFilter.cs

@ -0,0 +1,46 @@
using System;
using System.Threading.Tasks;
using Hangfire.Dashboard;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Users;
namespace Volo.Abp.Hangfire
{
public class AbpHangfireAuthorizationFilter : IDashboardAsyncAuthorizationFilter
{
private readonly string _requiredPermissionName;
public AbpHangfireAuthorizationFilter(string requiredPermissionName = null)
{
_requiredPermissionName = requiredPermissionName;
}
public async Task<bool> AuthorizeAsync(DashboardContext context)
{
if (!IsLoggedIn(context))
{
return false;
}
if (_requiredPermissionName.IsNullOrEmpty())
{
return true;
}
return await IsPermissionGrantedAsync(context, _requiredPermissionName);
}
private static bool IsLoggedIn(DashboardContext context)
{
var currentUser = context.GetHttpContext().RequestServices.GetRequiredService<ICurrentUser>();
return currentUser.IsAuthenticated;
}
private static async Task<bool> IsPermissionGrantedAsync(DashboardContext context, string requiredPermissionName)
{
var permissionChecker = context.GetHttpContext().RequestServices.GetRequiredService<IPermissionChecker>();
return await permissionChecker.IsGrantedAsync(requiredPermissionName);
}
}
}

2
framework/src/Volo.Abp.HangFire/Volo/Abp/Hangfire/AbpHangfireModule.cs

@ -1,10 +1,12 @@
using Hangfire;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Authorization;
using Volo.Abp.Modularity;
namespace Volo.Abp.Hangfire
{
[DependsOn(typeof(AbpAuthorizationAbstractionsModule))]
public class AbpHangfireModule : AbpModule
{
private BackgroundJobServer _backgroundJobServer;

14
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -174,7 +174,7 @@ namespace Volo.Abp.Http.Client.DynamicProxying
var response = await client.SendAsync(
requestMessage,
HttpCompletionOption.ResponseHeadersRead /*this will buffer only the headers, the content will be used as a stream*/,
GetCancellationToken()
GetCancellationToken(invocation)
);
if (!response.IsSuccessStatusCode)
@ -306,8 +306,18 @@ namespace Volo.Abp.Http.Client.DynamicProxying
return input;
}
protected virtual CancellationToken GetCancellationToken()
protected virtual CancellationToken GetCancellationToken(IAbpMethodInvocation invocation)
{
var cancellationTokenArg = invocation.Arguments.LastOrDefault(x => x is CancellationToken);
if (cancellationTokenArg != null)
{
var cancellationToken = (CancellationToken) cancellationTokenArg;
if (cancellationToken != default)
{
return cancellationToken;
}
}
return CancellationTokenProvider.Token;
}
}

1
framework/src/Volo.Abp.Sms.Aliyun/Volo.Abp.Sms.Aliyun.csproj

@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AlibabaCloud.OpenApiUtil" Version="1.0.10" />
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="1.0.2"/>
</ItemGroup>

4
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/DataAnnotationObjectValidationContributor.cs

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
@ -26,9 +27,10 @@ namespace Volo.Abp.Validation
Options = options.Value;
}
public void AddErrors(ObjectValidationContext context)
public Task AddErrorsAsync(ObjectValidationContext context)
{
ValidateObjectRecursively(context.Errors, context.ValidatingObject, currentDepth: 1);
return Task.CompletedTask;
}
protected virtual void ValidateObjectRecursively(List<ValidationResult> errors, object validatingObject, int currentDepth)

6
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IMethodInvocationValidator.cs

@ -1,7 +1,9 @@
namespace Volo.Abp.Validation
using System.Threading.Tasks;
namespace Volo.Abp.Validation
{
public interface IMethodInvocationValidator
{
void Validate(MethodInvocationValidationContext context);
Task ValidateAsync(MethodInvocationValidationContext context);
}
}

8
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidationContributor.cs

@ -1,7 +1,9 @@
namespace Volo.Abp.Validation
using System.Threading.Tasks;
namespace Volo.Abp.Validation
{
public interface IObjectValidationContributor
{
void AddErrors(ObjectValidationContext context);
Task AddErrorsAsync(ObjectValidationContext context);
}
}
}

7
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/IObjectValidator.cs

@ -1,20 +1,21 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
namespace Volo.Abp.Validation
{
public interface IObjectValidator
{
void Validate(
Task ValidateAsync(
object validatingObject,
string name = null,
bool allowNull = false
);
List<ValidationResult> GetErrors(
Task<List<ValidationResult>> GetErrorsAsync(
object validatingObject,
string name = null,
bool allowNull = false
);
}
}
}

17
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/MethodInvocationValidator.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Reflection;
@ -16,7 +17,7 @@ namespace Volo.Abp.Validation
_objectValidator = objectValidator;
}
public virtual void Validate(MethodInvocationValidationContext context)
public virtual async Task ValidateAsync(MethodInvocationValidationContext context)
{
Check.NotNull(context, nameof(context));
@ -46,7 +47,7 @@ namespace Volo.Abp.Validation
ThrowValidationError(context);
}
AddMethodParameterValidationErrors(context);
await AddMethodParameterValidationErrorsAsync(context);
if (context.Errors.Any())
{
@ -60,7 +61,7 @@ namespace Volo.Abp.Validation
{
return false;
}
if (ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(context.Method) != null)
{
return true;
@ -82,22 +83,22 @@ namespace Volo.Abp.Validation
);
}
protected virtual void AddMethodParameterValidationErrors(MethodInvocationValidationContext context)
protected virtual async Task AddMethodParameterValidationErrorsAsync(MethodInvocationValidationContext context)
{
for (var i = 0; i < context.Parameters.Length; i++)
{
AddMethodParameterValidationErrors(context, context.Parameters[i], context.ParameterValues[i]);
await AddMethodParameterValidationErrorsAsync(context, context.Parameters[i], context.ParameterValues[i]);
}
}
protected virtual void AddMethodParameterValidationErrors(IAbpValidationResult context, ParameterInfo parameterInfo, object parameterValue)
protected virtual async Task AddMethodParameterValidationErrorsAsync(IAbpValidationResult context, ParameterInfo parameterInfo, object parameterValue)
{
var allowNulls = parameterInfo.IsOptional ||
parameterInfo.IsOut ||
TypeHelper.IsPrimitiveExtended(parameterInfo.ParameterType, includeEnums: true);
context.Errors.AddRange(
_objectValidator.GetErrors(
await _objectValidator.GetErrorsAsync(
parameterValue,
parameterInfo.Name,
allowNulls
@ -105,4 +106,4 @@ namespace Volo.Abp.Validation
);
}
}
}
}

9
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ObjectValidator.cs

@ -2,6 +2,7 @@ using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
@ -18,9 +19,9 @@ namespace Volo.Abp.Validation
Options = options.Value;
}
public virtual void Validate(object validatingObject, string name = null, bool allowNull = false)
public virtual async Task ValidateAsync(object validatingObject, string name = null, bool allowNull = false)
{
var errors = GetErrors(validatingObject, name, allowNull);
var errors = await GetErrorsAsync(validatingObject, name, allowNull);
if (errors.Any())
{
@ -31,7 +32,7 @@ namespace Volo.Abp.Validation
}
}
public virtual List<ValidationResult> GetErrors(object validatingObject, string name = null, bool allowNull = false)
public virtual async Task<List<ValidationResult>> GetErrorsAsync(object validatingObject, string name = null, bool allowNull = false)
{
if (validatingObject == null)
{
@ -58,7 +59,7 @@ namespace Volo.Abp.Validation
{
var contributor = (IObjectValidationContributor)
scope.ServiceProvider.GetRequiredService(contributorType);
contributor.AddErrors(context);
await contributor.AddErrorsAsync(context);
}
}

6
framework/src/Volo.Abp.Validation/Volo/Abp/Validation/ValidationInterceptor.cs

@ -15,13 +15,13 @@ namespace Volo.Abp.Validation
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
Validate(invocation);
await ValidateAsync(invocation);
await invocation.ProceedAsync();
}
protected virtual void Validate(IAbpMethodInvocation invocation)
protected virtual async Task ValidateAsync(IAbpMethodInvocation invocation)
{
_methodInvocationValidator.Validate(
await _methodInvocationValidator.ValidateAsync(
new MethodInvocationValidationContext(
invocation.TargetObject,
invocation.Method,

27
framework/test/Volo.Abp.FluentValidation.Tests/Volo/Abp/FluentValidation/ApplicationService_FluentValidation_Tests.cs

@ -39,7 +39,8 @@ namespace Volo.Abp.FluentValidation
},
MyMethodInput3 = new MyMethodInput3
{
MyStringValue3 = "ccc"
MyStringValue3 = "ccc",
MyBoolValue3 = true
}
});
@ -62,12 +63,13 @@ namespace Volo.Abp.FluentValidation
},
MyMethodInput3 = new MyMethodInput3
{
MyStringValue3 = "c"
MyStringValue3 = "c",
MyBoolValue3 = false
}
}
)
);
exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyStringValue"));
exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput2.MyStringValue2"));
exception.ValidationErrors.ShouldContain(x => x.MemberNames.Contains("MyMethodInput3.MyStringValue3"));
@ -100,7 +102,7 @@ namespace Volo.Abp.FluentValidation
output.ShouldBe("444");
}
[DependsOn(typeof(AbpAutofacModule))]
[DependsOn(typeof(AbpFluentValidationModule))]
public class TestModule : AbpModule
@ -162,6 +164,8 @@ namespace Volo.Abp.FluentValidation
{
public string MyStringValue3 { get; set; }
public bool MyBoolValue3 { get; set; }
}
public class MyMethodInput4
@ -175,7 +179,8 @@ namespace Volo.Abp.FluentValidation
{
RuleFor(x => x.MyStringValue).Equal("aaa");
RuleFor(x => x.MyMethodInput2.MyStringValue2).Equal("bbb");
RuleFor(customer => customer.MyMethodInput3).SetValidator(new MyMethodInput3Validator());
RuleFor(x => x.MyMethodInput3).SetValidator(new MyMethodInput3Validator());
RuleFor(x => x.MyMethodInput3).SetValidator(new MyMethodInput3AsyncValidator());
}
}
@ -194,5 +199,15 @@ namespace Volo.Abp.FluentValidation
RuleFor(x => x.MyStringValue3).Equal("ccc");
}
}
public class MyMethodInput3AsyncValidator : MethodInputBaseValidator
{
public MyMethodInput3AsyncValidator()
{
RuleFor(x => x.MyStringValue3).Equal("ccc");
RuleFor(x => x.MyBoolValue3).MustAsync((myBookValue3, cancellation) => Task.FromResult(myBookValue3));
}
}
}
}
}

3
framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/IRegularTestController.cs

@ -1,4 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Volo.Abp.Http.DynamicProxying
@ -36,5 +37,7 @@ namespace Volo.Abp.Http.DynamicProxying
Task<string> PatchValueWithHeaderAndQueryStringAsync(string headerValue, string qsValue);
Task<int> DeleteByIdAsync(int id);
Task<string> AbortRequestAsync(CancellationToken cancellationToken = default);
}
}

11
framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestController.cs

@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Application.Services;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.UI;
namespace Volo.Abp.Http.DynamicProxying
{
@ -129,6 +128,14 @@ namespace Volo.Abp.Http.DynamicProxying
{
return Task.FromResult(id + 1);
}
[HttpGet]
[Route("abort-request")]
public async Task<string> AbortRequestAsync(CancellationToken cancellationToken = default)
{
await Task.Delay(100, cancellationToken);
return "AbortRequestAsync";
}
}
public class Car

16
framework/test/Volo.Abp.Http.Client.Tests/Volo/Abp/Http/DynamicProxying/RegularTestControllerClientProxy_Tests.cs

@ -1,10 +1,10 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Shouldly;
using Volo.Abp.Http.Client;
using Volo.Abp.Http.Localization;
using Volo.Abp.Localization;
using Xunit;
@ -159,5 +159,17 @@ namespace Volo.Abp.Http.DynamicProxying
(await _controller.DeleteByIdAsync(42)).ShouldBe(43);
}
[Fact]
public async Task AbortRequestAsync()
{
var cts = new CancellationTokenSource();
cts.CancelAfter(10);
var result = await _controller.AbortRequestAsync(default);
result.ShouldBe("AbortRequestAsync");
var exception = await Assert.ThrowsAsync<HttpRequestException>(async () => await _controller.AbortRequestAsync(cts.Token));
exception.InnerException.InnerException.Message.ShouldBe("The client aborted the request.");
}
}
}

8
modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/IDocumentRepository.cs

@ -25,6 +25,12 @@ namespace Volo.Docs.Documents
string version,
CancellationToken cancellationToken = default);
Task<List<Document>> GetListAsync(
Guid? projectId,
string version,
string name,
CancellationToken cancellationToken = default);
Task<List<DocumentWithoutContent>> GetAllAsync(
Guid? projectId,
string name,
@ -67,4 +73,4 @@ namespace Volo.Docs.Documents
Task<Document> GetAsync(Guid id, CancellationToken cancellationToken = default);
}
}
}

9
modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/Documents/EFCoreDocumentRepository.cs

@ -38,6 +38,15 @@ namespace Volo.Docs.Documents
return await (await GetDbSetAsync()).Where(d => d.ProjectId == projectId).ToListAsync(cancellationToken: cancellationToken);
}
public async Task<List<Document>> GetListAsync(Guid? projectId, string version, string name, CancellationToken cancellationToken = default)
{
return await (await GetDbSetAsync())
.WhereIf(version != null, x => x.Version == version)
.WhereIf(name != null, x => x.Name == name)
.WhereIf(projectId.HasValue, x => x.ProjectId == projectId)
.ToListAsync(cancellationToken: cancellationToken);
}
public async Task<List<DocumentWithoutContent>> GetAllAsync(
Guid? projectId,
string name,

10
modules/docs/src/Volo.Docs.MongoDB/Volo/Docs/Documents/MongoDocumentRepository.cs

@ -57,6 +57,16 @@ namespace Volo.Docs.Documents
x.Version == version, cancellationToken: cancellationToken);
}
public async Task<List<Document>> GetListAsync(Guid? projectId, string version, string name, CancellationToken cancellationToken = default)
{
return await (await GetMongoQueryableAsync(cancellationToken))
.WhereIf(version != null, x => x.Version == version)
.WhereIf(name != null, x => x.Name == name)
.WhereIf(projectId.HasValue, x => x.ProjectId == projectId)
.As<IMongoQueryable<Document>>()
.ToListAsync(cancellationToken);
}
public async Task<List<DocumentWithoutContent>> GetAllAsync(
Guid? projectId,
string name,

Loading…
Cancel
Save