Browse Source

Merge pull request #11192 from abpframework/auto-merge/rel-5-0/766

Merge branch dev with rel-5.0
pull/11197/head
maliming 5 years ago
committed by GitHub
parent
commit
ed34dc931c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      docs/en/Background-Workers-Hangfire.md
  2. 9
      docs/en/Modules/Cms-Kit/Index.md
  3. 30
      docs/zh-Hans/Background-Workers-Hangfire.md
  4. 9
      framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs
  5. 5
      framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs
  6. 9
      framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs
  7. 20
      framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs
  8. 48
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs
  9. 33
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ListResultDto.cs
  10. 9
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedAndSortedResultRequestDto.cs
  11. 30
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultDto.cs
  12. 12
      framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultRequestDto.cs
  13. 2
      templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs

30
docs/en/Background-Workers-Hangfire.md

@ -66,6 +66,33 @@ public class MyLogWorker : HangfireBackgroundWorkerBase
> You can directly implement the `IHangfireBackgroundWorker`, but `HangfireBackgroundWorkerBase` provides some useful properties like Logger. > You can directly implement the `IHangfireBackgroundWorker`, but `HangfireBackgroundWorkerBase` provides some useful properties like Logger.
### UnitOfWork
For use with `UnitOfWorkAttribute`, you need to define an interface for worker:
```csharp
public interface IMyLogWorker : IHangfireBackgroundWorker
{
}
[ExposeServices(typeof(IMyLogWorker))]
public class MyLogWorker : HangfireBackgroundWorkerBase, IMyLogWorker
{
public MyLogWorker()
{
RecurringJobId = nameof(MyLogWorker);
CronExpression = Cron.Daily();
}
[UnitOfWork]
public override Task DoWorkAsync()
{
Logger.LogInformation("Executed MyLogWorker..!");
return Task.CompletedTask;
}
}
```
## Register BackgroundWorkerManager ## Register BackgroundWorkerManager
After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class: After creating a background worker class, you should add it to the `IBackgroundWorkerManager`. The most common place is the `OnApplicationInitialization` method of your module class:
@ -78,6 +105,9 @@ public class MyModule : AbpModule
ApplicationInitializationContext context) ApplicationInitializationContext context)
{ {
context.AddBackgroundWorker<MyLogWorker>(); context.AddBackgroundWorker<MyLogWorker>();
//If the interface is defined
//context.AddBackgroundWorker<IMyLogWorker>();
} }
} }
```` ````

9
docs/en/Modules/Cms-Kit/Index.md

@ -19,15 +19,14 @@ Click to a feature to understand and learn how to use it.
All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, by the help of the [Global Features](../../Global-Features.md) system. All features are individually usable. If you disable a feature, it completely disappears from your application, even from the database tables, by the help of the [Global Features](../../Global-Features.md) system.
## Pre Requirements ## Pre Requirements
- This module depends on [BlobStoring](../../Blob-Storing.md) module for keeping media content.
> Make sure `BlobStoring` module is installed and at leats one provider is configured properly. For more information, check the [documentation](../../Blob-Storing.md).
CMS Kit uses [distributed cache](../../Caching.md) for responding faster. - CMS Kit uses [distributed cache](../../Caching.md) for responding faster.
> Using a distributed cache, such as [Redis](../../Redis-Cache.md), is highly recommended for data consistency in distributed/clustered deployments. > Using a distributed cache, such as [Redis](../../Redis-Cache.md), is highly recommended for data consistency in distributed/clustered deployments.
## How to Install ## How to Install
> This module is depends on [BlobStoring](../../Blob-Storing.md) module, please install `BlobStoring` module first and add a provider. For more information, check the [documentation](../../Blob-Storing.md).
[ABP CLI](../../CLI.md) allows installing a module to a solution using the `add-module` command. You can install the CMS Kit module in a command-line terminal with the following command: [ABP CLI](../../CLI.md) allows installing a module to a solution using the `add-module` command. You can install the CMS Kit module in a command-line terminal with the following command:
```bash ```bash
@ -77,4 +76,4 @@ All tables/collections use the `Cms` prefix by default. Set static properties on
This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string. This module uses `CmsKit` for the connection string name. If you don't define a connection string with this name, it fallbacks to the `Default` connection string.
See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details. See the [connection strings](https://docs.abp.io/en/abp/latest/Connection-Strings) documentation for details.

30
docs/zh-Hans/Background-Workers-Hangfire.md

@ -67,6 +67,33 @@ public class MyLogWorker : HangfireBackgroundWorkerBase
> 你可以直接实现 `IHangfireBackgroundWorker`, 但是 `HangfireBackgroundWorkerBase` 提供了一些有用的属性,例如 `Logger`. > 你可以直接实现 `IHangfireBackgroundWorker`, 但是 `HangfireBackgroundWorkerBase` 提供了一些有用的属性,例如 `Logger`.
### UnitOfWork
使用 `UnitOfWorkAttribute` 你需要为工作者定义一个接口:
```csharp
public interface IMyLogWorker : IHangfireBackgroundWorker
{
}
[ExposeServices(typeof(IMyLogWorker))]
public class MyLogWorker : HangfireBackgroundWorkerBase, IMyLogWorker
{
public MyLogWorker()
{
RecurringJobId = nameof(MyLogWorker);
CronExpression = Cron.Daily();
}
[UnitOfWork]
public override Task DoWorkAsync()
{
Logger.LogInformation("Executed MyLogWorker..!");
return Task.CompletedTask;
}
}
```
## 注册到后台工作者管理器 ## 注册到后台工作者管理器
创建一个后台工作者后, 你应该添加到 `IBackgroundWorkerManager`, 最常用的地方是在你模块类的 `OnApplicationInitialization` 方法中: 创建一个后台工作者后, 你应该添加到 `IBackgroundWorkerManager`, 最常用的地方是在你模块类的 `OnApplicationInitialization` 方法中:
@ -79,6 +106,9 @@ public class MyModule : AbpModule
ApplicationInitializationContext context) ApplicationInitializationContext context)
{ {
context.AddBackgroundWorker<MyLogWorker>(); context.AddBackgroundWorker<MyLogWorker>();
//如果定义了接口
//context.AddBackgroundWorker<IMyLogWorker>();
} }
} }
```` ````

9
framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireBackgroundWorkerManager.cs

@ -4,6 +4,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Hangfire; using Hangfire;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundWorkers.Hangfire; namespace Volo.Abp.BackgroundWorkers.Hangfire;
@ -25,14 +26,14 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle
{ {
if (worker is IHangfireBackgroundWorker hangfireBackgroundWorker) if (worker is IHangfireBackgroundWorker hangfireBackgroundWorker)
{ {
var unProxyWorker = ProxyHelper.UnProxy(hangfireBackgroundWorker);
if (hangfireBackgroundWorker.RecurringJobId.IsNullOrWhiteSpace()) if (hangfireBackgroundWorker.RecurringJobId.IsNullOrWhiteSpace())
{ {
RecurringJob.AddOrUpdate(() => hangfireBackgroundWorker.DoWorkAsync(), RecurringJob.AddOrUpdate(() => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(),hangfireBackgroundWorker.CronExpression);
hangfireBackgroundWorker.CronExpression);
} }
else else
{ {
RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId,() => hangfireBackgroundWorker.DoWorkAsync(), RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId,() => ((IHangfireBackgroundWorker)unProxyWorker).DoWorkAsync(),
hangfireBackgroundWorker.CronExpression); hangfireBackgroundWorker.CronExpression);
} }
} }
@ -64,7 +65,7 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle
return Task.CompletedTask; return Task.CompletedTask;
} }
var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(worker.GetType()); var adapterType = typeof(HangfirePeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker));
var workerAdapter = Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker; var workerAdapter = Activator.CreateInstance(adapterType) as IHangfireBackgroundWorker;
RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(), GetCron(period.Value)); RecurringJob.AddOrUpdate(() => workerAdapter.DoWorkAsync(), GetCron(period.Value));

5
framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerManager.cs

@ -1,8 +1,9 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Quartz; using Quartz;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundWorkers.Quartz; namespace Volo.Abp.BackgroundWorkers.Quartz;
@ -56,7 +57,7 @@ public class QuartzBackgroundWorkerManager : IBackgroundWorkerManager, ISingleto
} }
else else
{ {
var adapterType = typeof(QuartzPeriodicBackgroundWorkerAdapter<>).MakeGenericType(worker.GetType()); var adapterType = typeof(QuartzPeriodicBackgroundWorkerAdapter<>).MakeGenericType(ProxyHelper.GetUnProxiedType(worker));
var workerAdapter = Activator.CreateInstance(adapterType) as IQuartzBackgroundWorkerAdapter; var workerAdapter = Activator.CreateInstance(adapterType) as IQuartzBackgroundWorkerAdapter;

9
framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzPeriodicBackgroundWorkerAdapter.cs

@ -1,7 +1,8 @@
using System; using System;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Quartz; using Quartz;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundWorkers.Quartz; namespace Volo.Abp.BackgroundWorkers.Quartz;
@ -26,16 +27,16 @@ public class QuartzPeriodicBackgroundWorkerAdapter<TWorker> : QuartzBackgroundWo
public void BuildWorker(IBackgroundWorker worker) public void BuildWorker(IBackgroundWorker worker)
{ {
int? period; int? period;
var workerType = worker.GetType(); var workerType = ProxyHelper.GetUnProxiedType(worker);
if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase) if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase)
{ {
if (typeof(TWorker) != worker.GetType()) if (typeof(TWorker) != workerType)
{ {
throw new ArgumentException($"{nameof(worker)} type is different from the generic type"); throw new ArgumentException($"{nameof(worker)} type is different from the generic type");
} }
var timer = worker.GetType().GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); var timer = workerType.GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker);
if (worker is AsyncPeriodicBackgroundWorkerBase) if (worker is AsyncPeriodicBackgroundWorkerBase)
{ {

20
framework/src/Volo.Abp.Core/Volo/Abp/DynamicProxy/ProxyHelper.cs

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -9,7 +9,7 @@ public static class ProxyHelper
private const string ProxyNamespace = "Castle.Proxies"; private const string ProxyNamespace = "Castle.Proxies";
/// <summary> /// <summary>
/// Returns dynamic proxy target object if this is a proxied object, otherwise returns the given object. /// Returns dynamic proxy target object if this is a proxied object, otherwise returns the given object.
/// It supports Castle Dynamic Proxies. /// It supports Castle Dynamic Proxies.
/// </summary> /// </summary>
public static object UnProxy(object obj) public static object UnProxy(object obj)
@ -33,6 +33,20 @@ public static class ProxyHelper
public static Type GetUnProxiedType(object obj) public static Type GetUnProxiedType(object obj)
{ {
return UnProxy(obj).GetType(); if (obj.GetType().Namespace == ProxyNamespace)
{
var target = UnProxy(obj);
if (target != null)
{
if (target == obj)
{
return obj.GetType().GetTypeInfo().BaseType;
}
return target.GetType();
}
}
return obj.GetType();
} }
} }

48
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/LimitedResultRequestDto.cs

@ -49,3 +49,51 @@ public class LimitedResultRequestDto : ILimitedResultRequest, IValidatableObject
} }
} }
} }
/// <summary>
/// Simply implements <see cref="ILimitedResultRequest"/>.
/// </summary>
[Serializable]
public class ExtensibleLimitedResultRequestDto : ExtensibleEntityDto, ILimitedResultRequest, IValidatableObject
{
/// <summary>
/// Default value: 10.
/// </summary>
public static int DefaultMaxResultCount { get; set; } = 10;
/// <summary>
/// Maximum possible value of the <see cref="MaxResultCount"/>.
/// Default value: 1,000.
/// </summary>
public static int MaxMaxResultCount { get; set; } = 1000;
/// <summary>
/// Maximum result count should be returned.
/// This is generally used to limit result count on paging.
/// </summary>
[Range(1, int.MaxValue)]
public virtual int MaxResultCount { get; set; } = DefaultMaxResultCount;
public override IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
foreach(var result in base.Validate(validationContext))
{
yield return result;
}
if (MaxResultCount > MaxMaxResultCount)
{
var localizer = validationContext.GetRequiredService<IStringLocalizer<AbpDddApplicationContractsResource>>();
yield return new ValidationResult(
localizer[
"MaxResultCountExceededExceptionMessage",
nameof(MaxResultCount),
MaxMaxResultCount,
typeof(ExtensibleLimitedResultRequestDto).FullName,
nameof(MaxMaxResultCount)
],
new[] { nameof(MaxResultCount) });
}
}
}

33
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ListResultDto.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.Application.Dtos; namespace Volo.Abp.Application.Dtos;
@ -7,7 +8,8 @@ namespace Volo.Abp.Application.Dtos;
public class ListResultDto<T> : IListResult<T> public class ListResultDto<T> : IListResult<T>
{ {
/// <inheritdoc /> /// <inheritdoc />
public IReadOnlyList<T> Items { public IReadOnlyList<T> Items
{
get { return _items ?? (_items = new List<T>()); } get { return _items ?? (_items = new List<T>()); }
set { _items = value; } set { _items = value; }
} }
@ -30,3 +32,32 @@ public class ListResultDto<T> : IListResult<T>
Items = items; Items = items;
} }
} }
[Serializable]
public class ExtensibleListResultDto<T> : ExtensibleObject, IListResult<T>
{
/// <inheritdoc />
public IReadOnlyList<T> Items
{
get { return _items ?? (_items = new List<T>()); }
set { _items = value; }
}
private IReadOnlyList<T> _items;
/// <summary>
/// Creates a new <see cref="ListResultDto{T}"/> object.
/// </summary>
public ExtensibleListResultDto()
{
}
/// <summary>
/// Creates a new <see cref="ListResultDto{T}"/> object.
/// </summary>
/// <param name="items">List of items</param>
public ExtensibleListResultDto(IReadOnlyList<T> items)
{
Items = items;
}
}

9
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedAndSortedResultRequestDto.cs

@ -10,3 +10,12 @@ public class PagedAndSortedResultRequestDto : PagedResultRequestDto, IPagedAndSo
{ {
public virtual string Sorting { get; set; } public virtual string Sorting { get; set; }
} }
/// <summary>
/// Simply implements <see cref="IPagedAndSortedResultRequest"/>.
/// </summary>
[Serializable]
public class ExtensiblePagedAndSortedResultRequestDto : ExtensiblePagedResultRequestDto, IPagedAndSortedResultRequest
{
public virtual string Sorting { get; set; }
}

30
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultDto.cs

@ -32,3 +32,33 @@ public class PagedResultDto<T> : ListResultDto<T>, IPagedResult<T>
TotalCount = totalCount; TotalCount = totalCount;
} }
} }
/// <summary>
/// Implements <see cref="IPagedResult{T}"/>.
/// </summary>
/// <typeparam name="T">Type of the items in the <see cref="ListResultDto{T}.Items"/> list</typeparam>
[Serializable]
public class ExtensiblePagedResultDto<T> : ExtensibleListResultDto<T>, IPagedResult<T>
{
/// <inheritdoc />
public long TotalCount { get; set; } //TODO: Can be a long value..?
/// <summary>
/// Creates a new <see cref="PagedResultDto{T}"/> object.
/// </summary>
public ExtensiblePagedResultDto()
{
}
/// <summary>
/// Creates a new <see cref="PagedResultDto{T}"/> object.
/// </summary>
/// <param name="totalCount">Total count of Items</param>
/// <param name="items">List of items in current page</param>
public ExtensiblePagedResultDto(long totalCount, IReadOnlyList<T> items)
: base(items)
{
TotalCount = totalCount;
}
}

12
framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/PagedResultRequestDto.cs

@ -1,4 +1,4 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace Volo.Abp.Application.Dtos; namespace Volo.Abp.Application.Dtos;
@ -12,3 +12,13 @@ public class PagedResultRequestDto : LimitedResultRequestDto, IPagedResultReques
[Range(0, int.MaxValue)] [Range(0, int.MaxValue)]
public virtual int SkipCount { get; set; } public virtual int SkipCount { get; set; }
} }
/// <summary>
/// Simply implements <see cref="IPagedResultRequest"/>.
/// </summary>
[Serializable]
public class ExtensiblePagedResultRequestDto : ExtensibleLimitedResultRequestDto, IPagedResultRequest
{
[Range(0, int.MaxValue)]
public virtual int SkipCount { get; set; }
}

2
templates/app/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebTestModule.cs

@ -27,7 +27,7 @@ public class MyProjectNameWebTestModule : AbpModule
{ {
context.Services.PreConfigure<IMvcBuilder>(builder => context.Services.PreConfigure<IMvcBuilder>(builder =>
{ {
builder.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(MyProjectNameWebModule).Assembly)); builder.PartManager.ApplicationParts.Add(new CompiledRazorAssemblyPart(typeof(MyProjectNameWebModule).Assembly));
}); });
} }

Loading…
Cancel
Save