From 8544f954a74657d95eb89541b05b0182d233c676 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 1 Dec 2020 15:31:09 +0800 Subject: [PATCH 1/9] Discard the task result in Timer_Elapsed. Resolve #6385 --- .../AsyncPeriodicBackgroundWorkerBase.cs | 18 ++++++++++-------- .../Volo/Abp/Caching/DistributedCache.cs | 2 +- .../src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs | 12 +++++------- .../Abp/RabbitMQ/RabbitMqMessageConsumer.cs | 10 +++++----- .../Volo/Abp/Threading/AbpTimer.cs | 4 ++-- .../Aws/AbpBlobStoringAwsTestModule.cs | 4 ++-- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs index ed48ba69ee..b766ca531a 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs @@ -35,22 +35,24 @@ namespace Volo.Abp.BackgroundWorkers } private void Timer_Elapsed(object sender, System.EventArgs e) + { + // Discard the result + _ = DoWorkAsync(); + } + + private async Task DoWorkAsync() { using (var scope = ServiceScopeFactory.CreateScope()) { try { - AsyncHelper.RunSync( - () => DoWorkAsync(new PeriodicBackgroundWorkerContext(scope.ServiceProvider)) - ); + await DoWorkAsync(new PeriodicBackgroundWorkerContext(scope.ServiceProvider)); } catch (Exception ex) { - AsyncHelper.RunSync( - () => scope.ServiceProvider - .GetRequiredService() - .NotifyAsync(new ExceptionNotificationContext(ex)) - ); + await scope.ServiceProvider + .GetRequiredService() + .NotifyAsync(new ExceptionNotificationContext(ex)); Logger.LogException(ex); } diff --git a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs index 3a46c3b18e..d62411628e 100644 --- a/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs +++ b/framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs @@ -1029,7 +1029,7 @@ namespace Volo.Abp.Caching protected virtual void HandleException(Exception ex) { - AsyncHelper.RunSync(() => HandleExceptionAsync(ex)); + _ = HandleExceptionAsync(ex); } protected virtual async Task HandleExceptionAsync(Exception ex) diff --git a/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs index c78d5f93f3..886520e95c 100644 --- a/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs +++ b/framework/src/Volo.Abp.Cli/Volo/Abp/Cli/Program.cs @@ -3,13 +3,13 @@ using Microsoft.Extensions.DependencyInjection; using Serilog; using Serilog.Events; using System.IO; -using Volo.Abp.Threading; +using System.Threading.Tasks; namespace Volo.Abp.Cli { public class Program { - private static void Main(string[] args) + private static async Task Main(string[] args) { Console.OutputEncoding = System.Text.Encoding.UTF8; @@ -37,11 +37,9 @@ namespace Volo.Abp.Cli { application.Initialize(); - AsyncHelper.RunSync( - () => application.ServiceProvider - .GetRequiredService() - .RunAsync(args) - ); + await application.ServiceProvider + .GetRequiredService() + .RunAsync(args); application.Shutdown(); } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs index 135156f7a8..728fbd9077 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs @@ -38,7 +38,7 @@ namespace Volo.Abp.RabbitMQ public RabbitMqMessageConsumer( IConnectionPool connectionPool, - AbpTimer timer, + AbpTimer timer, IExceptionNotifier exceptionNotifier) { ConnectionPool = connectionPool; @@ -119,7 +119,7 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex, LogLevel.Warning); - AsyncHelper.RunSync(() => ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning)); + _ = ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } } @@ -186,7 +186,7 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex, LogLevel.Warning); - AsyncHelper.RunSync(() => ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning)); + _ = ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } } @@ -204,7 +204,7 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex); - await ExceptionNotifier.NotifyAsync(ex); + _ = ExceptionNotifier.NotifyAsync(ex); } } @@ -222,7 +222,7 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex, LogLevel.Warning); - AsyncHelper.RunSync(() => ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning)); + _ = ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } } diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs index 5c5041cdf6..f3439d383d 100644 --- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs @@ -101,7 +101,7 @@ namespace Volo.Abp.Threading catch(Exception ex) { Logger.LogException(ex); - AsyncHelper.RunSync(() => ExceptionNotifier.NotifyAsync(ex)); + _ = ExceptionNotifier.NotifyAsync(ex); } finally { @@ -118,4 +118,4 @@ namespace Volo.Abp.Threading } } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs index d176a864e7..71a1cd8504 100644 --- a/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs +++ b/framework/test/Volo.Abp.BlobStoring.Aws.Tests/Volo/Abp/BlobStoring/Aws/AbpBlobStoringAwsTestModule.cs @@ -69,7 +69,7 @@ namespace Volo.Abp.BlobStoring.Aws private async Task DeleteBucketAsync(ApplicationShutdownContext context) { - var amazonS3Client = await context.ServiceProvider.GetService() + var amazonS3Client = await context.ServiceProvider.GetRequiredService() .GetAmazonS3Client(_configuration); if (await AmazonS3Util.DoesS3BucketExistV2Async(amazonS3Client, _randomContainerName)) @@ -89,4 +89,4 @@ namespace Volo.Abp.BlobStoring.Aws } } } -} \ No newline at end of file +} From 9407a4b041693d8798827e18bcf88863d7013e90 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 1 Dec 2020 15:37:31 +0800 Subject: [PATCH 2/9] Update PeriodicBackgroundWorkerBase's Timer_Elapsed method. --- .../Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs index e29dbfec6e..1b2237099d 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs @@ -43,12 +43,11 @@ namespace Volo.Abp.BackgroundWorkers { try { - DoWork(new PeriodicBackgroundWorkerContext(scope.ServiceProvider)); } catch (Exception ex) { - scope.ServiceProvider + _ = scope.ServiceProvider .GetRequiredService() .NotifyAsync(new ExceptionNotificationContext(ex)); From db59f2773e22e3e4448e64e1b956754d553c6300 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 3 Dec 2020 14:45:24 +0800 Subject: [PATCH 3/9] Add AbpAsyncTimer. --- .../Abp/BackgroundJobs/BackgroundJobWorker.cs | 4 +- .../Quartz/QuartzBackgroundWorkerAdapter.cs | 2 +- .../AsyncPeriodicBackgroundWorkerBase.cs | 11 +- .../PeriodicBackgroundWorkerBase.cs | 5 +- .../Abp/RabbitMQ/RabbitMqMessageConsumer.cs | 55 +++++--- .../Volo/Abp/Threading/AbpAsyncTimer.cs | 127 ++++++++++++++++++ .../Volo/Abp/Threading/AbpTimer.cs | 2 +- 7 files changed, 171 insertions(+), 35 deletions(-) create mode 100644 framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpAsyncTimer.cs diff --git a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs index 62e79010cc..2635294323 100644 --- a/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs +++ b/framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorker.cs @@ -17,7 +17,7 @@ namespace Volo.Abp.BackgroundJobs protected AbpBackgroundJobWorkerOptions WorkerOptions { get; } public BackgroundJobWorker( - AbpTimer timer, + AbpAsyncTimer timer, IOptions jobOptions, IOptions workerOptions, IServiceScopeFactory serviceScopeFactory) @@ -113,4 +113,4 @@ namespace Volo.Abp.BackgroundJobs return nextTryDate; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs index e6a65a2865..970beea3f0 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers.Quartz/Volo/Abp/BackgroundWorkers/Quartz/QuartzBackgroundWorkerAdapter.cs @@ -34,7 +34,7 @@ namespace Volo.Abp.BackgroundWorkers.Quartz throw new ArgumentException($"{nameof(worker)} type is different from the generic type"); } - var timer = (AbpTimer) worker.GetType().GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); + var timer = (AbpAsyncTimer) worker.GetType().GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker); period = timer?.Period; } else diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs index b766ca531a..094c6eb7eb 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AsyncPeriodicBackgroundWorkerBase.cs @@ -11,15 +11,15 @@ namespace Volo.Abp.BackgroundWorkers public abstract class AsyncPeriodicBackgroundWorkerBase : BackgroundWorkerBase { protected IServiceScopeFactory ServiceScopeFactory { get; } - protected AbpTimer Timer { get; } + protected AbpAsyncTimer Timer { get; } protected AsyncPeriodicBackgroundWorkerBase( - AbpTimer timer, + AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory) { ServiceScopeFactory = serviceScopeFactory; Timer = timer; - Timer.Elapsed += Timer_Elapsed; + Timer.Elapsed = Timer_Elapsed; } public async override Task StartAsync(CancellationToken cancellationToken = default) @@ -34,10 +34,9 @@ namespace Volo.Abp.BackgroundWorkers await base.StopAsync(cancellationToken); } - private void Timer_Elapsed(object sender, System.EventArgs e) + private async Task Timer_Elapsed(AbpAsyncTimer timer) { - // Discard the result - _ = DoWorkAsync(); + await DoWorkAsync(); } private async Task DoWorkAsync() diff --git a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs index 1b2237099d..6ac757fef5 100644 --- a/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs +++ b/framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/PeriodicBackgroundWorkerBase.cs @@ -47,9 +47,8 @@ namespace Volo.Abp.BackgroundWorkers } catch (Exception ex) { - _ = scope.ServiceProvider - .GetRequiredService() - .NotifyAsync(new ExceptionNotificationContext(ex)); + var exceptionNotifier = scope.ServiceProvider.GetRequiredService(); + AsyncHelper.RunSync(() => exceptionNotifier.NotifyAsync(new ExceptionNotificationContext(ex))); Logger.LogException(ex); } diff --git a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs index 728fbd9077..fb1b0c7fe2 100644 --- a/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs +++ b/framework/src/Volo.Abp.RabbitMQ/Volo/Abp/RabbitMQ/RabbitMqMessageConsumer.cs @@ -20,7 +20,7 @@ namespace Volo.Abp.RabbitMQ protected IExceptionNotifier ExceptionNotifier { get; } - protected AbpTimer Timer { get; } + protected AbpAsyncTimer Timer { get; } protected ExchangeDeclareConfiguration Exchange { get; private set; } @@ -38,7 +38,7 @@ namespace Volo.Abp.RabbitMQ public RabbitMqMessageConsumer( IConnectionPool connectionPool, - AbpTimer timer, + AbpAsyncTimer timer, IExceptionNotifier exceptionNotifier) { ConnectionPool = connectionPool; @@ -50,7 +50,7 @@ namespace Volo.Abp.RabbitMQ Callbacks = new ConcurrentBag>(); Timer.Period = 5000; //5 sec. - Timer.Elapsed += Timer_Elapsed; + Timer.Elapsed = Timer_Elapsed; Timer.RunOnStart = true; } @@ -77,7 +77,7 @@ namespace Volo.Abp.RabbitMQ await TrySendQueueBindCommandsAsync(); } - protected virtual void TrySendQueueBindCommands() + protected virtual async Task TrySendQueueBindCommandsAsync() { try { @@ -119,40 +119,33 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex, LogLevel.Warning); - _ = ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); + await ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } } - protected virtual Task TrySendQueueBindCommandsAsync() - { - TrySendQueueBindCommands(); - return Task.CompletedTask; - } - public virtual void OnMessageReceived(Func callback) { Callbacks.Add(callback); } - protected virtual void Timer_Elapsed(object sender, EventArgs e) + protected virtual async Task Timer_Elapsed(AbpAsyncTimer timer) { if (Channel == null || Channel.IsOpen == false) { - TryCreateChannel(); - TrySendQueueBindCommands(); + await TryCreateChannelAsync(); + await TrySendQueueBindCommandsAsync(); } } - protected virtual void TryCreateChannel() + protected virtual async Task TryCreateChannelAsync() { - DisposeChannel(); + await DisposeChannelAsync(); try { var channel = ConnectionPool .Get(ConnectionName) .CreateModel(); - channel.ExchangeDeclare( exchange: Exchange.ExchangeName, type: Exchange.Type, @@ -172,7 +165,7 @@ namespace Volo.Abp.RabbitMQ var consumer = new EventingBasicConsumer(channel); consumer.Received += async (model, basicDeliverEventArgs) => { - await HandleIncomingMessage(channel, basicDeliverEventArgs); + await HandleIncomingMessageAsync(channel, basicDeliverEventArgs); }; channel.BasicConsume( @@ -186,11 +179,11 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex, LogLevel.Warning); - _ = ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); + await ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } } - protected virtual async Task HandleIncomingMessage(IModel channel, BasicDeliverEventArgs basicDeliverEventArgs) + protected virtual async Task HandleIncomingMessageAsync(IModel channel, BasicDeliverEventArgs basicDeliverEventArgs) { try { @@ -204,7 +197,25 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex); - _ = ExceptionNotifier.NotifyAsync(ex); + await ExceptionNotifier.NotifyAsync(ex); + } + } + + protected virtual async Task DisposeChannelAsync() + { + if (Channel == null) + { + return; + } + + try + { + Channel.Dispose(); + } + catch (Exception ex) + { + Logger.LogException(ex, LogLevel.Warning); + await ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); } } @@ -222,7 +233,7 @@ namespace Volo.Abp.RabbitMQ catch (Exception ex) { Logger.LogException(ex, LogLevel.Warning); - _ = ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning); + AsyncHelper.RunSync(() => ExceptionNotifier.NotifyAsync(ex, logLevel: LogLevel.Warning)); } } diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpAsyncTimer.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpAsyncTimer.cs new file mode 100644 index 0000000000..8ce369ef66 --- /dev/null +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpAsyncTimer.cs @@ -0,0 +1,127 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ExceptionHandling; + +namespace Volo.Abp.Threading +{ + /// + /// A robust timer implementation that ensures no overlapping occurs. It waits exactly specified between ticks. + /// + public class AbpAsyncTimer : ITransientDependency + { + /// + /// This func is raised periodically according to Period of Timer. + /// + public Func Elapsed = _ => Task.CompletedTask; + + /// + /// Task period of timer (as milliseconds). + /// + public int Period { get; set; } + + /// + /// Indicates whether timer raises Elapsed event on Start method of Timer for once. + /// Default: False. + /// + public bool RunOnStart { get; set; } + + public ILogger Logger { get; set; } + + public IExceptionNotifier ExceptionNotifier { get; set; } + + private readonly Timer _taskTimer; + private volatile bool _performingTasks; + private volatile bool _isRunning; + + public AbpAsyncTimer() + { + ExceptionNotifier = NullExceptionNotifier.Instance; + Logger = NullLogger.Instance; + + _taskTimer = new Timer( + TimerCallBack, + null, + Timeout.Infinite, + Timeout.Infinite + ); + } + + public void Start(CancellationToken cancellationToken = default) + { + if (Period <= 0) + { + throw new AbpException("Period should be set before starting the timer!"); + } + + lock (_taskTimer) + { + _taskTimer.Change(RunOnStart ? 0 : Period, Timeout.Infinite); + _isRunning = true; + } + } + + public void Stop(CancellationToken cancellationToken = default) + { + lock (_taskTimer) + { + _taskTimer.Change(Timeout.Infinite, Timeout.Infinite); + while (_performingTasks) + { + Monitor.Wait(_taskTimer); + } + + _isRunning = false; + } + } + + /// + /// This method is called by _taskTimer. + /// + /// Not used argument + private void TimerCallBack(object state) + { + lock (_taskTimer) + { + if (!_isRunning || _performingTasks) + { + return; + } + + _taskTimer.Change(Timeout.Infinite, Timeout.Infinite); + _performingTasks = true; + } + + _ = Timer_Elapsed(); + } + + private async Task Timer_Elapsed() + { + try + { + await Elapsed(this); + } + catch(Exception ex) + { + Logger.LogException(ex); + await ExceptionNotifier.NotifyAsync(ex); + } + finally + { + lock (_taskTimer) + { + _performingTasks = false; + if (_isRunning) + { + _taskTimer.Change(Period, Timeout.Infinite); + } + + Monitor.Pulse(_taskTimer); + } + } + } + } +} diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs index f3439d383d..e7e6efd5de 100644 --- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/AbpTimer.cs @@ -101,7 +101,7 @@ namespace Volo.Abp.Threading catch(Exception ex) { Logger.LogException(ex); - _ = ExceptionNotifier.NotifyAsync(ex); + AsyncHelper.RunSync(() => ExceptionNotifier.NotifyAsync(ex)); } finally { From fca9647d94f466fa0f2c55c76e2e875213acde06 Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 3 Dec 2020 14:58:17 +0800 Subject: [PATCH 4/9] Use AbpAsyncTimer in TokenCleanupBackgroundWorker. --- .../IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs index a7ad09d191..c424f9513c 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/Tokens/TokenCleanupBackgroundWorker.cs @@ -11,11 +11,11 @@ namespace Volo.Abp.IdentityServer.Tokens protected TokenCleanupOptions Options { get; } public TokenCleanupBackgroundWorker( - AbpTimer timer, + AbpAsyncTimer timer, IServiceScopeFactory serviceScopeFactory, IOptions options) : base( - timer, + timer, serviceScopeFactory) { Options = options.Value; @@ -27,8 +27,7 @@ namespace Volo.Abp.IdentityServer.Tokens await workerContext .ServiceProvider .GetRequiredService() - .CleanAsync() - ; + .CleanAsync(); } } } From bd54d221b1adf3fcb14b55d1381ec098e3b6fc20 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 4 Dec 2020 15:56:44 +0800 Subject: [PATCH 5/9] Add responseCallback to datatables.createAjax function. Resolve #6383 --- .../datatables/datatables-extensions.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js index 2bbd1aa7a3..b0c4873b59 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/datatables/datatables-extensions.js @@ -325,7 +325,14 @@ * AJAX extension for datatables * *************************************************************************/ (function () { - datatables.createAjax = function (serverMethod, inputAction) { + datatables.createAjax = function (serverMethod, inputAction, responseCallback) { + responseCallback = responseCallback || function(result) { + return { + recordsTotal: result.totalCount, + recordsFiltered: result.totalCount, + data: result.items + }; + } return function (requestData, callback, settings) { var input = inputAction ? inputAction(requestData, settings) : {}; @@ -359,11 +366,7 @@ if (callback) { serverMethod(input).then(function (result) { - callback({ - recordsTotal: result.totalCount, - recordsFiltered: result.totalCount, - data: result.items - }); + callback(responseCallback(result)); }); } }; From d7985119d0680aa6f32ebf6eb894f18c212eec6a Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 7 Dec 2020 23:11:39 +0800 Subject: [PATCH 6/9] Update command allow to specify version --- .../Volo/Abp/Cli/Commands/UpdateCommand.cs | 22 +++-- .../Volo/Abp/Cli/NuGet/NuGetService.cs | 71 +++++++------- .../ProjectModification/NpmPackagesUpdater.cs | 57 ++++++++--- .../VoloNugetPackagesVersionUpdater.cs | 94 +++++++++++++------ 4 files changed, 161 insertions(+), 83 deletions(-) diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs index 5fd30115e2..3173744bd0 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/UpdateCommand.cs @@ -34,24 +34,25 @@ namespace Volo.Abp.Cli.Commands var directory = commandLineArgs.Options.GetOrNull(Options.SolutionPath.Short, Options.SolutionPath.Long) ?? Directory.GetCurrentDirectory(); + var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long); if (updateNuget || !updateNpm) { - await UpdateNugetPackages(commandLineArgs, directory); + await UpdateNugetPackages(commandLineArgs, directory, version); } if (updateNpm || !updateNuget) { - await UpdateNpmPackages(directory); + await UpdateNpmPackages(directory, version); } } - private async Task UpdateNpmPackages(string directory) + private async Task UpdateNpmPackages(string directory, string version) { - await _npmPackagesUpdater.Update(directory); + await _npmPackagesUpdater.Update(directory, version: version); } - private async Task UpdateNugetPackages(CommandLineArgs commandLineArgs, string directory) + private async Task UpdateNugetPackages(CommandLineArgs commandLineArgs, string directory, string version) { var solution = commandLineArgs.Options.GetOrNull(Options.SolutionName.Short, Options.SolutionName.Long); @@ -66,7 +67,7 @@ namespace Volo.Abp.Cli.Commands { var solutionName = Path.GetFileName(solution).RemovePostFix(".sln"); - await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, checkAll: checkAll); + await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, checkAll: checkAll, version: version); Logger.LogInformation($"Volo packages are updated in {solutionName} solution."); return; @@ -78,7 +79,7 @@ namespace Volo.Abp.Cli.Commands { var projectName = Path.GetFileName(project).RemovePostFix(".csproj"); - await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, checkAll: checkAll); + await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, checkAll: checkAll, version: version); Logger.LogInformation($"Volo packages are updated in {projectName} project."); return; @@ -107,6 +108,7 @@ namespace Volo.Abp.Cli.Commands sb.AppendLine("-sp|--solution-path (Specify the solution path)"); sb.AppendLine("-sn|--solution-name (Specify the solution name)"); sb.AppendLine("--check-all (Check the new version of each package separately)"); + sb.AppendLine("-v|--version (default: latest version)"); sb.AppendLine(""); sb.AppendLine("Some examples:"); sb.AppendLine(""); @@ -148,6 +150,12 @@ namespace Volo.Abp.Cli.Commands { public const string Long = "check-all"; } + + public static class Version + { + public const string Short = "v"; + public const string Long = "version"; + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs index 1ecfc9e34d..a7243dbccd 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/NuGet/NuGetService.cs @@ -40,13 +40,43 @@ namespace Volo.Abp.Cli.NuGet } public async Task GetLatestVersionOrNullAsync(string packageId, bool includeNightly = false, bool includeReleaseCandidates = false) + { + var versionList = await GetPackageVersionListAsync(packageId, includeNightly, includeReleaseCandidates); + + List versions; + + if (!includeNightly && !includeReleaseCandidates) + { + versions = versionList + .Select(SemanticVersion.Parse) + .OrderByDescending(v=> v, new VersionComparer()).ToList(); + + versions = versions.Where(x => !x.IsPrerelease).ToList(); + } + else if (!includeNightly && includeReleaseCandidates) + { + versions = versionList + .Where(v=> !v.Contains("-preview")) + .Select(SemanticVersion.Parse) + .OrderByDescending(v=> v, new VersionComparer()).ToList(); + } + else + { + versions = versionList + .Select(SemanticVersion.Parse) + .OrderByDescending(v=> v, new VersionComparer()).ToList(); + } + + return versions.Any() ? versions.Max() : null; + + } + + public async Task> GetPackageVersionListAsync(string packageId, bool includeNightly = false, + bool includeReleaseCandidates = false) { if (AuthService.IsLoggedIn()) { - if (_proPackageList == null) - { - _proPackageList = await GetProPackageListAsync(); - } + _proPackageList ??= await GetProPackageListAsync(); } string url; @@ -75,37 +105,8 @@ namespace Volo.Abp.Cli.NuGet var responseContent = await responseMessage.Content.ReadAsStringAsync(); - List versions; - - if (!includeNightly && !includeReleaseCandidates) - { - versions = JsonSerializer - .Deserialize(responseContent) - .Versions - .Select(SemanticVersion.Parse) - .OrderByDescending(v=> v, new VersionComparer()).ToList(); - - versions = versions.Where(x => !x.IsPrerelease).ToList(); - } - else if (!includeNightly && includeReleaseCandidates) - { - versions = JsonSerializer - .Deserialize(responseContent) - .Versions - .Where(v=> !v.Contains("-preview")) - .Select(SemanticVersion.Parse) - .OrderByDescending(v=> v, new VersionComparer()).ToList(); - } - else - { - versions = JsonSerializer - .Deserialize(responseContent) - .Versions - .Select(SemanticVersion.Parse) - .OrderByDescending(v=> v, new VersionComparer()).ToList(); - } - - return versions.Any() ? versions.Max() : null; + return JsonSerializer + .Deserialize(responseContent).Versions; } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs index c71e9591c0..f2bbe873d8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmPackagesUpdater.cs @@ -43,7 +43,7 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public async Task Update(string rootDirectory, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false) + public async Task Update(string rootDirectory, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, string version = null) { var fileList = _packageJsonFileFinder.Find(rootDirectory); @@ -58,7 +58,7 @@ namespace Volo.Abp.Cli.ProjectModification async Task UpdateAsync(string file) { - var updated = await UpdatePackagesInFile(file, includePreviews,includeReleaseCandidates, switchToStable); + var updated = await UpdatePackagesInFile(file, includePreviews,includeReleaseCandidates, switchToStable, version); packagesUpdated.TryAdd(file, updated); } @@ -181,7 +181,8 @@ namespace Volo.Abp.Cli.ProjectModification string filePath, bool includePreviews = false, bool includeReleaseCandidates = false, - bool switchToStable = false) + bool switchToStable = false, + string specifiedVersion = null) { var packagesUpdated = false; var fileContent = File.ReadAllText(filePath); @@ -195,7 +196,7 @@ namespace Volo.Abp.Cli.ProjectModification foreach (var abpPackage in abpPackages) { - var updated = await TryUpdatingPackage(filePath, abpPackage, includePreviews, includeReleaseCandidates, switchToStable); + var updated = await TryUpdatingPackage(filePath, abpPackage, includePreviews, includeReleaseCandidates, switchToStable, specifiedVersion); if (updated) { @@ -215,27 +216,45 @@ namespace Volo.Abp.Cli.ProjectModification JProperty package, bool includePreviews = false, bool includeReleaseCandidates = false, - bool switchToStable = false) + bool switchToStable = false, + string specifiedVersion = null) { var currentVersion = (string) package.Value; var version = ""; - if ((includePreviews || (!switchToStable && currentVersion.Contains("-preview"))) && !includeReleaseCandidates) + if (!specifiedVersion.IsNullOrWhiteSpace()) { - version = "preview"; + if (!SpecifiedVersionExists(specifiedVersion, package)) + { + return false; + } + + if (SemanticVersion.Parse(specifiedVersion) <= SemanticVersion.Parse(currentVersion.RemovePreFix("~", "^"))) + { + return false; + } + version = specifiedVersion.EnsureStartsWith('^'); } else { - if (!switchToStable && IsPrerelease(currentVersion)) + if ((includePreviews || (!switchToStable && currentVersion.Contains("-preview"))) && !includeReleaseCandidates) { - version = await GetLatestVersion(package, true); + version = "preview"; } else { - version = await GetLatestVersion(package, includeReleaseCandidates); + if (!switchToStable && IsPrerelease(currentVersion)) + { + version = await GetLatestVersion(package, true); + } + else + { + version = await GetLatestVersion(package, includeReleaseCandidates); + } } } + if (string.IsNullOrEmpty(version) || version == currentVersion) { return false; @@ -267,9 +286,7 @@ namespace Volo.Abp.Cli.ProjectModification return _fileVersionStorage[package.Name]; } - var versionListAsJson = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} versions"); - var versionList = JsonConvert.DeserializeObject(versionListAsJson) - .OrderByDescending(SemanticVersion.Parse, new VersionComparer()).ToList(); + var versionList = GetPackageVersionList(package); var newVersion = includeReleaseCandidates ? versionList.First() @@ -327,5 +344,19 @@ namespace Volo.Abp.Cli.ProjectModification Logger.LogInformation($"Running npm install on {fileDirectory}"); CmdHelper.RunCmd($"cd {fileDirectory} && npm install"); } + + protected virtual List GetPackageVersionList(JProperty package) + { + var versionListAsJson = CmdHelper.RunCmdAndGetOutput($"npm show {package.Name} versions"); + return JsonConvert.DeserializeObject(versionListAsJson) + .OrderByDescending(SemanticVersion.Parse, new VersionComparer()).ToList(); + } + + protected virtual bool SpecifiedVersionExists(string version, JProperty package) + { + var versionList = GetPackageVersionList(package); + + return versionList.Any(v => v.Equals(version, StringComparison.OrdinalIgnoreCase)); + } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs index 275bf23c76..c499dd0ee0 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/VoloNugetPackagesVersionUpdater.cs @@ -25,11 +25,11 @@ namespace Volo.Abp.Cli.ProjectModification Logger = NullLogger.Instance; } - public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false) + public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false, string version = null) { var projectPaths = ProjectFinder.GetProjectFiles(solutionPath); - if (checkAll) + if (checkAll && version.IsNullOrWhiteSpace()) { Task.WaitAll(projectPaths.Select(projectPath => UpdateInternalAsync(projectPath, includePreviews, includeReleaseCandidates, switchToStable)).ToArray()); } @@ -48,7 +48,8 @@ namespace Volo.Abp.Cli.ProjectModification switchToStable, latestVersionFromNuget, latestReleaseCandidateVersionFromNuget, - latestVersionFromMyGet); + latestVersionFromMyGet, + version); File.WriteAllText(filePath, updatedContent); } @@ -57,9 +58,9 @@ namespace Volo.Abp.Cli.ProjectModification } } - public async Task UpdateProjectAsync(string projectPath, bool includeNightlyPreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false) + public async Task UpdateProjectAsync(string projectPath, bool includeNightlyPreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, bool checkAll = false, string version = null) { - if (checkAll) + if (checkAll && version.IsNullOrWhiteSpace()) { await UpdateInternalAsync(projectPath, includeNightlyPreviews, includeReleaseCandidates, switchToStable); } @@ -77,7 +78,8 @@ namespace Volo.Abp.Cli.ProjectModification switchToStable, latestVersionFromNuget, latestReleaseCandidateVersionFromNuget, - latestVersionFromMyGet); + latestVersionFromMyGet, + version); File.WriteAllText(projectPath, updatedContent); } @@ -91,13 +93,26 @@ namespace Volo.Abp.Cli.ProjectModification File.WriteAllText(projectPath, updatedContent); } + protected virtual async Task SpecifiedVersionExists(string version, string packageId) + { + var versionList = await _nuGetService.GetPackageVersionListAsync(packageId); + + if (versionList.All(v => !v.Equals(version, StringComparison.OrdinalIgnoreCase))) + { + versionList = await _nuGetService.GetPackageVersionListAsync(packageId, true); + } + + return versionList.Any(v => v.Equals(version, StringComparison.OrdinalIgnoreCase)); + } + private async Task UpdateVoloPackagesAsync(string content, bool includeNightlyPreviews = false, bool includeReleaseCandidates = false, bool switchToStable = false, SemanticVersion latestNugetVersion = null, SemanticVersion latestNugetReleaseCandidateVersion = null, - string latestMyGetVersion = null) + string latestMyGetVersion = null, + string specifiedVersion = null) { string packageId = null; @@ -129,40 +144,63 @@ namespace Volo.Abp.Cli.ProjectModification Logger.LogDebug("Checking package: \"{0}\" - Current version: {1}", packageId, currentSemanticVersion); - if ((includeNightlyPreviews || (currentVersion.Contains("-preview") && !switchToStable)) && !includeReleaseCandidates) + if (!specifiedVersion.IsNullOrWhiteSpace()) { - var latestVersion = latestMyGetVersion ?? await GetLatestVersionFromMyGet(packageId); - - if (currentVersion != latestVersion) + if (await SpecifiedVersionExists(specifiedVersion, packageId)) { - Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentVersion, latestVersion); - versionAttribute.Value = latestVersion; + var specifiedSemanticVersion = SemanticVersion.Parse(specifiedVersion); + if (specifiedSemanticVersion > currentSemanticVersion) + { + Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentVersion, specifiedVersion); + versionAttribute.Value = specifiedVersion; + } + else + { + Logger.LogWarning("Unable to update package \"{0}\" version v{1} to v{2}.", packageId, currentVersion, specifiedVersion); + } } else { - Logger.LogDebug("Package: \"{0}-v{1}\" is up to date.", packageId, currentVersion); + Logger.LogWarning("Package \"{0}\" specified version v{1} does not exist.", packageId, specifiedVersion); } } else { - SemanticVersion latestVersion; - if (currentSemanticVersion.IsPrerelease && !switchToStable) - { - latestVersion = latestNugetReleaseCandidateVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: true); - } - else - { - latestVersion = latestNugetVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates); - } - - if (latestVersion != null && (currentSemanticVersion < latestVersion || (currentSemanticVersion.IsPrerelease && switchToStable))) + if ((includeNightlyPreviews || (currentVersion.Contains("-preview") && !switchToStable)) && !includeReleaseCandidates) { - Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentSemanticVersion.ToString(), latestVersion.ToString()); - versionAttribute.Value = latestVersion.ToString(); + var latestVersion = latestMyGetVersion ?? await GetLatestVersionFromMyGet(packageId); + + if (currentVersion != latestVersion) + { + Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentVersion, latestVersion); + versionAttribute.Value = latestVersion; + } + else + { + Logger.LogDebug("Package: \"{0}-v{1}\" is up to date.", packageId, currentVersion); + } } else { - Logger.LogInformation("Package: \"{0}-v{1}\" is up to date.", packageId, currentSemanticVersion); + SemanticVersion latestVersion; + if (currentSemanticVersion.IsPrerelease && !switchToStable) + { + latestVersion = latestNugetReleaseCandidateVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: true); + } + else + { + latestVersion = latestNugetVersion ?? await _nuGetService.GetLatestVersionOrNullAsync(packageId, includeReleaseCandidates: includeReleaseCandidates); + } + + if (latestVersion != null && (currentSemanticVersion < latestVersion || (currentSemanticVersion.IsPrerelease && switchToStable))) + { + Logger.LogInformation("Updating package \"{0}\" from v{1} to v{2}.", packageId, currentSemanticVersion.ToString(), latestVersion.ToString()); + versionAttribute.Value = latestVersion.ToString(); + } + else + { + Logger.LogInformation("Package: \"{0}-v{1}\" is up to date.", packageId, currentSemanticVersion); + } } } } From e5729e24f792f7acab7496460d7b134ed332c6f6 Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Mon, 7 Dec 2020 23:15:43 +0800 Subject: [PATCH 7/9] Update CLI.md --- docs/en/CLI.md | 1 + docs/zh-Hans/CLI.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/en/CLI.md b/docs/en/CLI.md index d51dd91b5d..c5eb38bbbe 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -129,6 +129,7 @@ abp update [options] * `--solution-path` or `-sp`: Specify the solution path. Use the current directory by default * `--solution-name` or `-sn`: Specify the solution name. Search `*.sln` files in the directory by default. * `--check-all`: Check the new version of each package separately. Default is `false`. +* `--version` or `-v`: Specifies the version to use for update. If not specified, latest version is used. ### add-package diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md index 3390ce99b3..4c63dcd818 100644 --- a/docs/zh-Hans/CLI.md +++ b/docs/zh-Hans/CLI.md @@ -126,6 +126,7 @@ abp update [options] * `--solution-path` 或 `-sp`: 指定解决方案路径/目录. 默认使用当前目录 * `--solution-name` 或 `-sn`: 指定解决方案名称. 默认在目录中搜索`*.sln`文件. * `--check-all`: 分别检查每个包的新版本. 默认是 `false`. +* `--version` or `-v`: 指定用于升级的版本. 如果没有指定,则使用最新版本. ### add-package From 78b1650c8bbdc1879ac409ddbbf9f5689145d1cc Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 8 Dec 2020 09:51:01 +0800 Subject: [PATCH 8/9] Update Data-Tables.md --- docs/en/UI/AspNetCore/Data-Tables.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Data-Tables.md b/docs/en/UI/AspNetCore/Data-Tables.md index a9dbf1eecf..b97d49d562 100644 --- a/docs/en/UI/AspNetCore/Data-Tables.md +++ b/docs/en/UI/AspNetCore/Data-Tables.md @@ -105,6 +105,32 @@ The `abp.libs.datatables.createAjax` method (used in the example above) adapts r This works automatically, so most of the times you don't need to know how it works. See the [DTO document](../../Data-Transfer-Objects.md) if you want to learn more about `IPagedAndSortedResultRequest`, `IPagedResult` and other standard interfaces and base DTO classes those are used in client to server communication. +The `createAjax` also supports you to customize request parameters and handle the responses. + +**Example:** + +````csharp +var inputAction = function () { + return { + id: $('#Id').val(), + name: $('#Name').val(), + }; +}; + +var responseCallback = function(result) { + + // your custom code. + + return { + recordsTotal: result.totalCount, + recordsFiltered: result.totalCount, + data: result.items + }; +}; + +ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList, inputAction, responseCallback) +```` + ### Row Actions `rowAction` is an option defined by the ABP Framework to the column definitions to show a drop down button to take actions for a row in the table. @@ -260,4 +286,4 @@ Assuming that the possible values for a column data is `f` and `m`, the `gender` ## Other Data Grids -You can use any library you like. For example, [see this article](https://community.abp.io/articles/using-devextreme-components-with-the-abp-framework-zb8z7yqv) to learn how to use DevExtreme Data Grid in your applications. \ No newline at end of file +You can use any library you like. For example, [see this article](https://community.abp.io/articles/using-devextreme-components-with-the-abp-framework-zb8z7yqv) to learn how to use DevExtreme Data Grid in your applications. From d1f0b6682d6f66baab8ce9ae3a49b3df6d2891ba Mon Sep 17 00:00:00 2001 From: Yunus Emre Kalkan Date: Tue, 8 Dec 2020 12:10:28 +0300 Subject: [PATCH 9/9] Docs module: Ensure document contributors are ordered by commmit count resolves https://github.com/volosoft/volo/issues/4222 --- ...201208084431_Added_CommitCount.Designer.cs | 987 ++++++++++++++++++ .../20201208084431_Added_CommitCount.cs | 24 + .../VoloDocsDbContextModelSnapshot.cs | 5 +- .../Docs/Documents/DocumentContributorDto.cs | 2 + .../Volo/Docs/Documents/Document.cs | 4 +- .../Docs/Documents/DocumentContributor.cs | 5 +- .../Docs/GitHub/Documents/DocumentAuthor.cs | 13 + .../GitHub/Documents/GithubDocumentSource.cs | 31 +- .../Pages/Documents/Project/Index.cshtml | 2 +- 9 files changed, 1061 insertions(+), 12 deletions(-) create mode 100644 modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.Designer.cs create mode 100644 modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.cs create mode 100644 modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/DocumentAuthor.cs diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.Designer.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.Designer.cs new file mode 100644 index 0000000000..ff28c9f865 --- /dev/null +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.Designer.cs @@ -0,0 +1,987 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Volo.Abp.EntityFrameworkCore; +using VoloDocs.EntityFrameworkCore; + +namespace VoloDocs.EntityFrameworkCore.Migrations +{ + [DbContext(typeof(VoloDocsDbContext))] + [Migration("20201208084431_Added_CommitCount")] + partial class Added_CommitCount + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .UseIdentityColumns() + .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.0"); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Description") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsStatic") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Regex") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("RegexDescription") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Required") + .HasColumnType("bit"); + + b.Property("ValueType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("AbpClaimTypes"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("SourceTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("SourceUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetTenantId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SourceUserId", "SourceTenantId", "TargetUserId", "TargetTenantId") + .IsUnique() + .HasFilter("[SourceTenantId] IS NOT NULL AND [TargetTenantId] IS NOT NULL"); + + b.ToTable("AbpLinkUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDefault") + .HasColumnType("bit") + .HasColumnName("IsDefault"); + + b.Property("IsPublic") + .HasColumnType("bit") + .HasColumnName("IsPublic"); + + b.Property("IsStatic") + .HasColumnType("bit") + .HasColumnName("IsStatic"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName"); + + b.ToTable("AbpRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AbpRoleClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Action") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("ApplicationName") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("BrowserInfo") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("ClientId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ClientIpAddress") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CorrelationId") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Identity") + .HasMaxLength(96) + .HasColumnType("nvarchar(96)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TenantName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("TenantId", "Action"); + + b.HasIndex("TenantId", "ApplicationName"); + + b.HasIndex("TenantId", "Identity"); + + b.HasIndex("TenantId", "UserId"); + + b.ToTable("AbpSecurityLogs"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("AccessFailedCount"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("Email"); + + b.Property("EmailConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("EmailConfirmed"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("IsExternal") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsExternal"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("LockoutEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("LockoutEnabled"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("Name") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Name"); + + b.Property("NormalizedEmail") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedEmail"); + + b.Property("NormalizedUserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("NormalizedUserName"); + + b.Property("PasswordHash") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("PasswordHash"); + + b.Property("PhoneNumber") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)") + .HasColumnName("PhoneNumber"); + + b.Property("PhoneNumberConfirmed") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("PhoneNumberConfirmed"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("SecurityStamp"); + + b.Property("Surname") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)") + .HasColumnName("Surname"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("TwoFactorEnabled") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("TwoFactorEnabled"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)") + .HasColumnName("UserName"); + + b.HasKey("Id"); + + b.HasIndex("Email"); + + b.HasIndex("NormalizedEmail"); + + b.HasIndex("NormalizedUserName"); + + b.HasIndex("UserName"); + + b.ToTable("AbpUsers"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("ClaimType") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ClaimValue") + .HasMaxLength(1024) + .HasColumnType("nvarchar(1024)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AbpUserClaims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderDisplayName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(196) + .HasColumnType("nvarchar(196)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "LoginProvider"); + + b.HasIndex("LoginProvider", "ProviderKey"); + + b.ToTable("AbpUserLogins"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "UserId"); + + b.HasIndex("UserId", "OrganizationUnitId"); + + b.ToTable("AbpUserOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId", "UserId"); + + b.ToTable("AbpUserRoles"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Name") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AbpUserTokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(95) + .HasColumnType("nvarchar(95)") + .HasColumnName("Code"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("DeleterId") + .HasColumnType("uniqueidentifier") + .HasColumnName("DeleterId"); + + b.Property("DeletionTime") + .HasColumnType("datetime2") + .HasColumnName("DeletionTime"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)") + .HasColumnName("DisplayName"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false) + .HasColumnName("IsDeleted"); + + b.Property("LastModificationTime") + .HasColumnType("datetime2") + .HasColumnName("LastModificationTime"); + + b.Property("LastModifierId") + .HasColumnType("uniqueidentifier") + .HasColumnName("LastModifierId"); + + b.Property("ParentId") + .HasColumnType("uniqueidentifier"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Code"); + + b.HasIndex("ParentId"); + + b.ToTable("AbpOrganizationUnits"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.Property("OrganizationUnitId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("CreatorId") + .HasColumnType("uniqueidentifier") + .HasColumnName("CreatorId"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("OrganizationUnitId", "RoleId"); + + b.HasIndex("RoleId", "OrganizationUnitId"); + + b.ToTable("AbpOrganizationUnitRoles"); + }); + + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("TenantId") + .HasColumnType("uniqueidentifier") + .HasColumnName("TenantId"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpPermissionGrants"); + }); + + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ProviderKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("ProviderName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.HasKey("Id"); + + b.HasIndex("Name", "ProviderName", "ProviderKey"); + + b.ToTable("AbpSettings"); + }); + + modelBuilder.Entity("Volo.Docs.Documents.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("Content") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("CreationTime") + .HasColumnType("datetime2"); + + b.Property("EditLink") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Format") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LanguageCode") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LastCachedTime") + .HasColumnType("datetime2"); + + b.Property("LastSignificantUpdateTime") + .HasColumnType("datetime2"); + + b.Property("LastUpdatedTime") + .HasColumnType("datetime2"); + + b.Property("LocalDirectory") + .HasMaxLength(512) + .HasColumnType("nvarchar(512)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("RawRootUrl") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("RootUrl") + .HasMaxLength(2048) + .HasColumnType("nvarchar(2048)"); + + b.Property("Version") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.ToTable("DocsDocuments"); + }); + + modelBuilder.Entity("Volo.Docs.Documents.DocumentContributor", b => + { + b.Property("DocumentId") + .HasColumnType("uniqueidentifier"); + + b.Property("Username") + .HasColumnType("nvarchar(450)"); + + b.Property("AvatarUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("CommitCount") + .HasColumnType("int"); + + b.Property("UserProfileUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("DocumentId", "Username"); + + b.ToTable("DocsDocumentContributors"); + }); + + modelBuilder.Entity("Volo.Docs.Projects.Project", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("DefaultDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("DocumentStoreType") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Format") + .HasColumnType("nvarchar(max)"); + + b.Property("LatestVersionBranchName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("MainWebsiteUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("MinimumVersion") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("NavigationDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParametersDocumentName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ShortName") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.ToTable("DocsProjects"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRoleClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany("Claims") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserClaim", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Claims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserLogin", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Logins") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserOrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("OrganizationUnits") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserRole", b => + { + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUserToken", b => + { + b.HasOne("Volo.Abp.Identity.IdentityUser", null) + .WithMany("Tokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany() + .HasForeignKey("ParentId"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnitRole", b => + { + b.HasOne("Volo.Abp.Identity.OrganizationUnit", null) + .WithMany("Roles") + .HasForeignKey("OrganizationUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Volo.Abp.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Docs.Documents.DocumentContributor", b => + { + b.HasOne("Volo.Docs.Documents.Document", null) + .WithMany("Contributors") + .HasForeignKey("DocumentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => + { + b.Navigation("Claims"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => + { + b.Navigation("Claims"); + + b.Navigation("Logins"); + + b.Navigation("OrganizationUnits"); + + b.Navigation("Roles"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => + { + b.Navigation("Roles"); + }); + + modelBuilder.Entity("Volo.Docs.Documents.Document", b => + { + b.Navigation("Contributors"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.cs new file mode 100644 index 0000000000..1ed082ff34 --- /dev/null +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/20201208084431_Added_CommitCount.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace VoloDocs.EntityFrameworkCore.Migrations +{ + public partial class Added_CommitCount : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CommitCount", + table: "DocsDocumentContributors", + type: "int", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CommitCount", + table: "DocsDocumentContributors"); + } + } +} diff --git a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs index 204023bf3c..112509c609 100644 --- a/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs +++ b/modules/docs/app/VoloDocs.EntityFrameworkCore/Migrations/VoloDocsDbContextModelSnapshot.cs @@ -19,7 +19,7 @@ namespace VoloDocs.EntityFrameworkCore.Migrations .UseIdentityColumns() .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("ProductVersion", "5.0.0-rc.2.20475.6"); + .HasAnnotation("ProductVersion", "5.0.0"); modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { @@ -782,6 +782,9 @@ namespace VoloDocs.EntityFrameworkCore.Migrations b.Property("AvatarUrl") .HasColumnType("nvarchar(max)"); + b.Property("CommitCount") + .HasColumnType("int"); + b.Property("UserProfileUrl") .HasColumnType("nvarchar(max)"); diff --git a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentContributorDto.cs b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentContributorDto.cs index 337faf3db1..fcd049d7c9 100644 --- a/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentContributorDto.cs +++ b/modules/docs/src/Volo.Docs.Application.Contracts/Volo/Docs/Documents/DocumentContributorDto.cs @@ -10,5 +10,7 @@ namespace Volo.Docs.Documents public string UserProfileUrl { get; set; } public string AvatarUrl { get; set; } + + public int CommitCount { get; set; } } } diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs index c2ec85f33b..967b5939f2 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/Document.cs @@ -87,9 +87,9 @@ namespace Volo.Docs.Documents Contributors = new List(); } - public virtual void AddContributor(string username, string userProfileUrl, string avatarUrl) + public virtual void AddContributor(string username, string userProfileUrl, string avatarUrl, int commitCount = 1) { - Contributors.AddIfNotContains(new DocumentContributor(Id, username, userProfileUrl, avatarUrl)); + Contributors.AddIfNotContains(new DocumentContributor(Id, username, userProfileUrl, avatarUrl, commitCount)); } public virtual void RemoveAllContributors() diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/DocumentContributor.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/DocumentContributor.cs index 1351b0a4ca..876686b5ff 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/DocumentContributor.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/Documents/DocumentContributor.cs @@ -9,6 +9,8 @@ namespace Volo.Docs.Documents public string Username { get; set; } + public int CommitCount { get; set; } + public string UserProfileUrl { get; set; } public string AvatarUrl { get; set; } @@ -23,12 +25,13 @@ namespace Volo.Docs.Documents return DocumentId == documentId && Username == username; } - public DocumentContributor(Guid documentId, string username, string userProfileUrl, string avatarUrl) + public DocumentContributor(Guid documentId, string username, string userProfileUrl, string avatarUrl, int commitCount = 1) { DocumentId = documentId; Username = username; UserProfileUrl = userProfileUrl; AvatarUrl = avatarUrl; + CommitCount = commitCount; } public override object[] GetKeys() diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/DocumentAuthor.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/DocumentAuthor.cs new file mode 100644 index 0000000000..f1fef91713 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/DocumentAuthor.cs @@ -0,0 +1,13 @@ +namespace Volo.Docs.GitHub.Documents +{ + public class DocumentAuthor + { + public string Login { get; set; } + + public string HtmlUrl { get; set; } + + public string AvatarUrl { get; set; } + + public int CommitCount { get; set; } + } +} diff --git a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs index ef8ea15e76..dfc79f7547 100644 --- a/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs +++ b/modules/docs/src/Volo.Docs.Domain/Volo/Docs/GitHub/Documents/GithubDocumentSource.cs @@ -84,9 +84,11 @@ namespace Volo.Docs.GitHub.Documents } var authors = GetAuthors(commits); + + document.RemoveAllContributors(); foreach (var author in authors) { - document.AddContributor(author.Login, author.HtmlUrl, author.AvatarUrl); + document.AddContributor(author.Login, author.HtmlUrl, author.AvatarUrl, author.CommitCount); } return document; @@ -114,20 +116,35 @@ namespace Volo.Docs.GitHub.Documents : null; } - private static List GetAuthors(IReadOnlyList commits) + private static List GetAuthors(IReadOnlyList commits) { if (commits == null || !commits.Any()) { - return new List(); + return new List(); } - return commits + var authorsOrderedAndGrouped = commits .Where(x => x.Author != null) .Select(x => x.Author) .GroupBy(x => x.Id) - .OrderByDescending(x => x.Count()) - .Select(x => x.FirstOrDefault()) - .ToList(); + .OrderByDescending(x => x.Count()); + + var documentAuthors = new List(); + + foreach (var authorGroup in authorsOrderedAndGrouped) + { + var author = authorGroup.FirstOrDefault(); + var documentAuthor = new DocumentAuthor + { + CommitCount = authorGroup.Count(), + AvatarUrl = author.AvatarUrl, + HtmlUrl = author.HtmlUrl, + Login = author.Login + }; + documentAuthors.Add(documentAuthor); + } + + return documentAuthors; } private static DateTime GetLastCommitDate(IReadOnlyList commits) diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index a7897eddfe..1cdfe7ca2e 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -217,7 +217,7 @@ @(L["Contributors"].Value) - @foreach (var contributor in Model.Document.Contributors) + @foreach (var contributor in Model.Document.Contributors.OrderByDescending(c=> c.CommitCount).ToList()) {