Merge branch 'dev' into MailKit-integration

pull/1463/head
Halil İbrahim Kalkan 6 years ago committed by GitHub
commit 98f95809ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -29,6 +29,14 @@ Pokud chcete přeložit celou [dokumentaci](https://abp.io/documents/) (včetně
* Pro referenci použijte ["en" složku](https://github.com/abpframework/abp/tree/master/docs/en) a její názvy souborů a strom složek. Při překladu této dokumentace zachovejte prosím tyto názvy stejné.
* Zašlete pull request (PR) po překladu jakéhokoliv dokumentu klidně i po jednom. Nečekejte až budete mít překlad všech dokumentů.
Existuje několik základních dokumentů, které je třeba přeložit než bude jazyk uveřejněn na [stránkách ABP dokumentace](https://docs.abp.io)
* Začínáme dokumenty
* Tutoriály
* CLI
Nový jazyk je publikován jakmile budou minimálně tyto překlady dokončeny.
### Lokalizace zdrojů
ABP framework má flexibilní [lokalizační systém](../Localization.md). Můžete tak vytvořit lokalizované uživatelské prostředí pro svou vlastní aplikaci.

@ -0,0 +1,186 @@
# Začínáme s ASP.NET Core MVC aplikací
Tento tutoriál vysvětluje jak začít s ABP z ničeho s minimem závislostí. Obvykle chcete začít se **[startovací šablonou](https://abp.io/Templates)**.
## Tvorba nového projektu
1. Vytvořte novou prázdnou AspNet Core Web aplikaci ve Visual Studio:
![](images/create-new-aspnet-core-application.png)
2. Zvolte prázdnou šablonu
![](images/select-empty-web-application.png)
Můžete zvolit i jinou šablonu, ale pro demonstraci je lepší čístý projekt.
## Instalace Volo.Abp.AspNetCore.Mvc balíku
Volo.Abp.AspNetCore.Mvc je AspNet Core MVC integrační balík pro ABP. Takže ho nainstalujeme do projektu:
````
Install-Package Volo.Abp.AspNetCore.Mvc
````
## Tvorba prvního ABP modulu
ABP je modulární framework a proto vyžaduje **spouštěcí (kořenový) modul** což je třída dědící z ``AbpModule``:
````C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.AspNetCore.Modularity;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace BasicAspNetCoreApplication
{
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
public class AppModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvcWithDefaultRoute();
}
}
}
````
``AppModule`` je dobrý název pro spouštěcí modul aplikace.
ABP balíky definují modulové třídy a modul může mít závislost na jiný modul. V kódu výše, náš ``AppModule`` má závislost na ``AbpAspNetCoreMvcModule`` (definován v balíku Volo.Abp.AspNetCore.Mvc). Je běžné přidat ``DependsOn`` atribute po instalaci nového ABP NuGet balíku.
Místo třídy Startup, konfigurujeme ASP.NET Core pipeline v této modulové třídě.
## Třída Startup
V dalším kroku upravíme Startup třídu k integraci ABP modulového systému:
````C#
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddApplication<AppModule>();
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
{
app.InitializeApplication();
}
}
}
````
Změnili jsme metodu ``ConfigureServices`` aby vracela ``IServiceProvider`` místo ``void``. Tato změna nám dovoluje nahradit AspNet Core vkládání závislostí za jiný framework (více v sekci Autofac integrace níže). ``services.AddApplication<AppModule>()`` přidává všechny služby definované ve všech modulech počínaje ``AppModule``.
Volání ``app.InitializeApplication()`` v metodě ``Configure`` inicializuje a spustí aplikaci.
## Ahoj světe!
Aplikace výše zatím nic nedělá. Pojďme proto vytvořit MVC controller, který už něco dělá:
````C#
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc;
namespace BasicAspNetCoreApplication.Controllers
{
public class HomeController : AbpController
{
public IActionResult Index()
{
return Content("Hello World!");
}
}
}
````
Jakmile spustíte aplikaci, uvidíte na stránce zprávu "Hello World!".
Odvození ``HomeController`` od ``AbpController`` místo standardní třídy ``Controller``. Toto není vyžadováno, ale třída ``AbpController`` má užitečné základní vlastnosti a metody, které usnadňují vývoj.
## Použití Autofac jako frameworku pro vkládání závislostí
Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) skvělý pro základní požadavky, Autofac poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku.
Nahrazení AspNet Core DI systému za Autofac a integrace s ABP je snadná.
1. Nainstalujeme [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) balík
````
Install-Package Volo.Abp.Autofac
````
2. Přidáme ``AbpAutofacModule`` závislost
````C#
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
[DependsOn(typeof(AbpAutofacModule))] // Přidá závislost na AbpAutofacModule
public class AppModule : AbpModule
{
...
}
````
3. Změníme řádek ``services.AddApplication<AppModule>();`` v třídě ``Startup`` následovně:
````C#
services.AddApplication<AppModule>(options =>
{
options.UseAutofac(); // Integrace s Autofac
});
````
4. Upravíme `Program.cs` aby nepoužíval metodu `WebHost.CreateDefaultBuilder()` jelikož ta používá výchozí DI kontejner:
````csharp
public class Program
{
public static void Main(string[] args)
{
/*
https://github.com/aspnet/AspNetCore/issues/4206#issuecomment-445612167
CurrentDirectoryHelpers exists in: \framework\src\Volo.Abp.AspNetCore.Mvc\Microsoft\AspNetCore\InProcess\CurrentDirectoryHelpers.cs
Will remove CurrentDirectoryHelpers.cs when upgrade to ASP.NET Core 3.0.
*/
CurrentDirectoryHelpers.SetCurrentDirectory();
BuildWebHostInternal(args).Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIIS()
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
````
## Zdrojový kód
Získejte zdrojový kód vzorového projektu vytvořeného v tomto tutoriálů [z tohoto odkazu](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication).

@ -0,0 +1,102 @@
## Začínáme s ASP.NET Core MVC šablonou
Tento tutoriál vysvětluje, jak vytvořit novou ASP.NET Core MVC webovou aplikaci pomocí úvodní šablony, jak ji nakonfigurovat a spustit.
### Tvorba nového projektu
Tento tutoriál používá k tvorbě nového projektu **ABP CLI**. Podívejte se na stránku [Začínáme](https://abp.io/get-started) pro více možností.
Pokud ještě nemáte ABP CLI nainstalováno, učiňte tak pomocí okna příkazového řádku:
````bash
dotnet tool install -g Volo.Abp.Cli
````
K tvorbě vašeho projektu použijte příkaz `abp new` v prázdné složce:
````bash
abp new Acme.BookStore
````
> Můžete použít různé úrovně jmenných prostorů; např. BookStore, Acme.BookStore nebo Acme.Retail.BookStore.
Příkaz `new` vytvoří **vrstvenou MVC aplikaci** s **Entity Framework Core** jako databázovým poskytovatelem. Jsou zde však i jiné možnosti. Podívejte se na [CLI dokumnentaci](CLI.md) pro všechny další možností.
#### Požadavky
Vytvořené řešení vyžaduje;
* [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/)
* [.NET Core 2.2+](https://www.microsoft.com/net/download/dotnet-core/)
### Struktura řešení
Otevřete řešení ve **Visual Studio**:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v3.png)
Řešení má vrstvenou strukturu (založenou na [Domain Driven Design](Domain-Driven-Design.md)) a obsahuje projekty jednotkovových a integračních testů předkonfigurované pro práci s **EF Core** & **SQLite in-memory** databází.
> Podívejte se na [dokument šablony MVC aplikace](Startup-Templates/Mvc.md) k detailnímu pochopení struktury řešení.
### Connection string databáze
Zkontrolujte **connection string** v souboru `appsettings.json` v projektu `.Web`:
````json
{
"ConnectionStrings": {
"Default": "Server=localhost;Database=BookStore;Trusted_Connection=True"
}
}
````
Řešení je nakonfigurováno k používání **Entity Framework Core** s **MS SQL Server**. EF Core podporuje [různé](https://docs.microsoft.com/en-us/ef/core/providers/) databázové poskytovatele, takže můžete použít i jiné DBMS. V případě potřeby změňte connection string.
### Tvorba databáze & aplikace databázových migrací
K vytvoření databáze máte dvě možnosti.
#### Použití DbMigrator aplikace
Řešení obsahuje konzolovou aplikaci (v tomto příkladu nazvanou `Acme.BookStore.DbMigrator`), která může vytvářet databáze, aplikovat migrace a vkládat seed data. Je užitečná jak pro vývojové, tak pro produkční prostředí.
> Projekt `.DbMigrator` má vlastní `appsettings.json`. Takže pokud jste změnili connection string uvedený výše, musíte změnit také tento.
Klikněte pravým na projekt `.DbMigrator` a vyberte **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Zmáčkněte F5 (nebo Ctrl+F5) ke spuštění aplikace. Výstup bude vypadat následovně:
![set-as-startup-project](images/db-migrator-app.png)
#### Použití EF Core Update-Database příkazu
Ef Core má `Update-Database` příkaz, který v případě potřeby vytvoří databázi a aplikuje čekající migrace. Klikněte pravým na projekt `.Web` a vyberte **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Otevřete **Package Manager Console**, vyberte projekt `.EntityFrameworkCore.DbMigrations` jako **Default Project** and spusťte příkaz `Update-Database`:
![pcm-update-database](images/pcm-update-database-v2.png)
Dojde k vytvoření nové databáze na základě nakonfigurovaného connection stringu.
> Použití nástroje `.Migrator` je doporučený způsob, jelikož zároveň vloží seed data nutné k správnému běhu webové aplikace.
### Spuštění aplikace
Ujistěte se že je projekt `.Web` nastaven jako startovací projekt. Spusťte aplikaci což následně otevře **úvodní** stránku ve vašem prohlížeči:
![bookstore-homepage](images/bookstore-homepage.png)
Klikněte na tlačítko **Přihlásit**, vložte `admin` jako uživatelské jméno a `1q2w3E*` jako heslo k přihlášení do aplikace.
Startovací šabloná obsahuje **identity management** a **tenant management** moduly. Jakmile se přihlásite, budete mít přístup do nabídky Administrace, kde můžete spravovat **tenanty**, **role**, **uživatele** a jejich **oprávnění**. Správa uživatelů vypadá takto:
![bookstore-user-management](images/bookstore-user-management-v2.png)
### Co dále?
* [Tutoriál vývoje aplikace](Tutorials/AspNetCore-Mvc/Part-I.md)

@ -0,0 +1,181 @@
# Začínáme s konzolovou aplikací
Tento tutoriál vysvětluje jak začít s ABP z ničeho s minimem závislostí. Obvykle chcete začít se **[startovací šablonou](https://abp.io/Templates)**.
## Tvorba nového projektu
Vytvořte regulérní .NET Core konzolovou aplikaci z Visual Studio:
![](images/create-new-net-core-console-application.png)
## Instalace Volo.Abp balíku
Volo.Abp.Core je základní NuGet balík k tvorbě aplikací založených na ABP. Takže ho nainstalujeme do projektu:
````
Install-Package Volo.Abp.Core
````
## Tvorba prvního ABP modulu
ABP je modulární framework a proto vyžaduje **spouštěcí (kořenový) modul** což je třída dědící z ``AbpModule``:
````C#
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace AbpConsoleDemo
{
public class AppModule : AbpModule
{
}
}
````
``AppModule`` je dobrý název pro spouštěcí modul aplikace.
## Inicializace aplikace
Dalším krokem je bootstrap aplikace pomocí spouštěcího modulu vytvořeného výše:
````C#
using System;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>())
{
application.Initialize();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
````
``AbpApplicationFactory`` se používá k vytvoření aplikace a načtení všech modulů, s využitím ``AppModule`` jako spouštěcím modulem. ``Initialize()`` metoda spouští aplikaci.
## Ahoj světe!
Aplikace výše zatím nic nedělá. Pojďme proto vytvořit službu která už něco dělá:
````C#
using System;
using Volo.Abp.DependencyInjection;
namespace AbpConsoleDemo
{
public class HelloWorldService : ITransientDependency
{
public void SayHello()
{
Console.WriteLine("Hello World!");
}
}
}
````
``ITransientDependency`` je speciální rozhraní ABP, které automaticky registruje službu jako přechodnou (více v [dokumentu vkládání závislostí](Dependency-Injection.md)).
Nyní můžeme vyřešit ``HelloWorldService`` a vypsat naše ahoj. Změníme Program.cs podle vyobrazení níže:
````C#
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>())
{
application.Initialize();
// Vyřeší službu a použije ji
var helloWorldService =
application.ServiceProvider.GetService<HelloWorldService>();
helloWorldService.SayHello();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
````
I když je to dostačující pro tento jednoduchý príklad kódu, je vždy lepší v případě přímého řešení závislostí z ``IServiceProvider`` vytvořit rámce (více v [dokumentu vkládání závislostí](Dependency-Injection.md)).
## Využití Autofac jako frameworku pro vkládání závislostí
Ačkoliv je AspNet Core systém pro vkládání závíslostí (DI) skvělý pro základní požadavky, Autofac poskytuje pokročilé funkce jako injekce vlastností nebo záchyt metod, které jsou v ABP užity k provádění pokročilých funkcí frameworku.
Nahrazení AspNet Core DI systému za Autofac a integrace s ABP je snadná.
1. Nainstalujeme [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) balík
```
Install-Package Volo.Abp.Autofac
```
1. Přidáme ``AbpAutofacModule`` závislost
```c#
[DependsOn(typeof(AbpAutofacModule))] // Přidá závislost na AbpAutofacModule
public class AppModule : AbpModule
{
}
```
1. Změníme soubor ``Program.cs`` podle vyobrazení níže:
```c#
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
namespace AbpConsoleDemo
{
class Program
{
static void Main(string[] args)
{
using (var application = AbpApplicationFactory.Create<AppModule>(options =>
{
options.UseAutofac(); // Autofac integrace
}))
{
application.Initialize();
// Vyřeší službu a použije ji
var helloWorldService =
application.ServiceProvider.GetService<HelloWorldService>();
helloWorldService.SayHello();
Console.WriteLine("Press ENTER to stop application...");
Console.ReadLine();
}
}
}
}
```
Stačí volat metodu `options.UseAutofac()` v možnostech `AbpApplicationFactory.Create`.
## Zdrojový kód
Získejte zdrojový kód vzorového projektu vytvořeného v tomto tutoriálů [z tohoto odkazu](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication).

@ -9,6 +9,11 @@
"DisplayName" : "简体中文",
"Code" : "zh-Hans",
"IsDefault": false
}
},
{
"DisplayName" : "Čeština",
"Code" : "cs",
"IsDefault": false
}
]
}

@ -204,7 +204,7 @@ namespace Acme.BookStore
* This DTO class is used to get book information from the user interface while creating or updating a book.
* It defines data annotation attributes (like `[Required]`) to define validations for the properties. DTOs are [automatically validated](../../Validation.md) by the ABP framework.
Like done for the `BookDto` above, create a mapping from the `CreateUpdateBookDto` object to the `Book` entity:
Next, add a mapping in `BookStoreApplicationAutoMapperProfile` from the `CreateUpdateBookDto` object to the `Book` entity:
````csharp
CreateMap<CreateUpdateBookDto, Book>();

@ -1,13 +0,0 @@
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
public static class CachedApplicationConfigurationClientExtensions
{
public static ApplicationConfigurationDto Get(this ICachedApplicationConfigurationClient client)
{
return AsyncHelper.RunSync(client.GetAsync);
}
}
}

@ -4,6 +4,7 @@ using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Localization;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.Client
{
@ -54,8 +55,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Client
private Dictionary<string, string> GetResourceOrNull()
{
var resource = _applicationConfigurationClient
.Get()
var applicationConfigurationDto = AsyncHelper.RunSync(
() => _applicationConfigurationClient.GetAsync()
);
var resource = applicationConfigurationDto
.Localization.Values
.GetOrDefault(_resource.ResourceName);

@ -0,0 +1,6 @@
(function ($) {
$('#GlobalRefreshButton').on('click',
function () {
$(document).trigger('RefreshWidgets', $('#DashboardGlobalFiltersForm').serializeFormToObject());
});
})(jQuery);

@ -18,14 +18,17 @@
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\AspNetCore\Mvc\UI\Dashboards\Components\**\*.cshtml" />
<Content Remove="Volo\Abp\AspNetCore\Mvc\UI\Dashboards\Components\**\*.cshtml" />
<EmbeddedResource Include="Pages\Components\Dashboard\*.js" />
<Content Remove="Pages\Components\Dashboard\*.js" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\AspNetCore\Mvc\UI\Dashboards\_ViewImports.cshtml" />
<Content Remove="Volo\Abp\AspNetCore\Mvc\UI\Dashboards\_ViewImports.cshtml" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\AspNetCore\Mvc\UI\Dashboards\_ViewImports.cshtml" />
<Content Include="Volo\Abp\AspNetCore\Mvc\UI\Dashboards\Components\Dashboard\Default.cshtml" />
</ItemGroup>
<ItemGroup>

@ -4,5 +4,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
{
public class AbpBasicDashboardScriptContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.Add("/Pages/Components/Dashboard/Default.js");
}
}
}

@ -10,18 +10,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
{
private readonly DashboardOptions _dashboardOptions;
private readonly WidgetOptions _widgetOptions;
private readonly GlobalFilterOptions _globalFilterOptions;
public DashboardViewComponent(IOptions<DashboardOptions> dashboardOptions, IOptions<WidgetOptions> widgetOptions)
public DashboardViewComponent(IOptions<DashboardOptions> dashboardOptions, IOptions<WidgetOptions> widgetOptions, IOptions<GlobalFilterOptions> globalFilterOptions)
{
_dashboardOptions = dashboardOptions.Value;
_widgetOptions = widgetOptions.Value;
_globalFilterOptions = globalFilterOptions.Value;
}
public IViewComponentResult Invoke(string dashboardName)
{
var dashboard = _dashboardOptions.Dashboards.Single(d => d.Name.Equals(dashboardName));
var model = new DashboardViewModel(dashboard, _widgetOptions.Widgets);
var model = new DashboardViewModel(dashboard, _widgetOptions.Widgets, _globalFilterOptions.GlobalFilters);
return View("~/Volo/Abp/AspNetCore/Mvc/UI/Dashboards/Components/Dashboard/Default.cshtml", model);
}

@ -13,10 +13,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
public List<WidgetDefinition> Widgets { get; set; }
public DashboardViewModel(DashboardDefinition dashboard, List<WidgetDefinition> widgets)
public List<GlobalFilterDefinition> GlobalFilters { get; set; }
public DashboardViewModel(DashboardDefinition dashboard, List<WidgetDefinition> widgets, List<GlobalFilterDefinition> globalFilters)
{
Dashboard = dashboard;
Widgets = widgets;
GlobalFilters = globalFilters;
}
public WidgetDefinition GetWidget(string name)
@ -24,6 +27,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard
return Widgets.Single(d => d.Name.Equals(name));
}
public GlobalFilterDefinition GetGlobalFilter(string name)
{
return GlobalFilters.Single(d => d.Name.Equals(name));
}
public async Task<bool> CheckPermissionsAsync(IAuthorizationService authorizationService, WidgetDefinition widget)
{
foreach (var permission in widget.RequiredPermissions)

@ -1,13 +1,41 @@
@using Microsoft.AspNetCore.Authorization
@using Localization.Resources.AbpUi
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Dashboards
@using Volo.Abp.AspNetCore.Mvc.UI.Widgets
@inject IAuthorizationService AuthorizationService
@inject IWidgetRenderer WidgetRenderer
@inject IStringLocalizerFactory localizer
@inject IGlobalFilterRenderer GlobalFilteRenderer
@inject IHtmlLocalizer<AbpUiResource> L
@model Volo.Abp.AspNetCore.Mvc.UI.Dashboards.Components.Dashboard.DashboardViewModel
@{
}
<abp-row class="mb-4 align-items-center justify-content-between">
@if (Model.Dashboard.AvailableGlobalFilters.Any())
{
<abp-column size="_10">
<form id="DashboardGlobalFiltersForm">
<abp-row>
@foreach (var globalFilterConfiguration in Model.Dashboard.AvailableGlobalFilters)
{
var globalFilter = Model.GetGlobalFilter(globalFilterConfiguration.GlobalFilterName);
@await GlobalFilteRenderer.RenderAsync(Component, globalFilter.Name)
}
</abp-row>
</form>
</abp-column>
<abp-column size="_2">
<div class="float-right">
<abp-button button-type="Success" text="@L["Refresh"].Value" icon="refresh" id="GlobalRefreshButton" />
</div>
</abp-column>
}
</abp-row>
<abp-row>
@foreach (var widgetConfiguration in Model.Dashboard.AvailableWidgets)
{

@ -19,7 +19,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
public List<DashboardWidgetConfiguration> AvailableWidgets { get; }
/// <summary>
/// Display name of the widget.
/// A list of Global Filters available for this dashboard.
/// </summary>
public List<DashboardGlobalFilterConfiguration> AvailableGlobalFilters { get; }
/// <summary>
/// Display name of the dashboard.
/// </summary>
[NotNull]
public ILocalizableString DisplayName
@ -37,6 +42,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
DisplayName = displayName ?? new FixedLocalizableString(name);
AvailableWidgets = new List<DashboardWidgetConfiguration>();
AvailableGlobalFilters = new List<DashboardGlobalFilterConfiguration>();
}
public DashboardDefinition WithWidget(string widgetName, WidgetLocation location = null, WidgetDimensions dimensions = null)
@ -45,5 +51,12 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
return this;
}
public DashboardDefinition WithGlobalFilter(string globalFilterName)
{
AvailableGlobalFilters.Add( new DashboardGlobalFilterConfiguration(globalFilterName));
return this;
}
}
}

@ -0,0 +1,15 @@
using JetBrains.Annotations;
namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
{
public class DashboardGlobalFilterConfiguration
{
[NotNull]
public string GlobalFilterName { get; }
public DashboardGlobalFilterConfiguration([NotNull] string globalFilterName)
{
GlobalFilterName = Check.NotNullOrWhiteSpace(globalFilterName, nameof(globalFilterName));
}
}
}

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
{
public class GlobalFilterDefinition
{
/// <summary>
/// Unique name of the Global Filter.
/// </summary>
[NotNull]
public string Name { get; }
/// <summary>
/// Display name of the Global Filter.
/// </summary>
[NotNull]
public ILocalizableString DisplayName
{
get => _displayName;
set => _displayName = Check.NotNull(value, nameof(value));
}
private ILocalizableString _displayName;
[NotNull]
public Type ViewComponentType { get; }
public GlobalFilterDefinition(
[NotNull] string name,
[CanBeNull] ILocalizableString displayName,
[NotNull] Type viewComponentType)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
DisplayName = displayName ?? new FixedLocalizableString(name);
ViewComponentType = Check.NotNull(viewComponentType, nameof(viewComponentType));
}
}
}

@ -0,0 +1,14 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
{
public class GlobalFilterOptions
{
public List<GlobalFilterDefinition> GlobalFilters { get; }
public GlobalFilterOptions()
{
GlobalFilters = new List<GlobalFilterDefinition>();
}
}
}

@ -0,0 +1,25 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
{
public class GlobalFilterRenderer : IGlobalFilterRenderer
{
private readonly GlobalFilterOptions _globalFilterOptions;
public GlobalFilterRenderer(IOptions<GlobalFilterOptions> widgetOptions)
{
_globalFilterOptions = widgetOptions.Value;
}
public async Task<IHtmlContent> RenderAsync(IViewComponentHelper componentHelper, string globalFilterName, object args = null)
{
var globalFilter = _globalFilterOptions.GlobalFilters.Single(w => w.Name.Equals(globalFilterName));
return await componentHelper.InvokeAsync(globalFilter.ViewComponentType, args ?? new object());
}
}
}

@ -0,0 +1,12 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.UI.Dashboards
{
public interface IGlobalFilterRenderer : ITransientDependency
{
Task<IHtmlContent> RenderAsync(IViewComponentHelper componentHelper, string globalFilterName, object args = null);
}
}

@ -10,22 +10,23 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars
{
public class BasicThemeMainTopToolbarContributor : IToolbarContributor
{
public Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
public async Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
{
if (context.Toolbar.Name != StandardToolbars.Main)
{
return Task.CompletedTask;
return;
}
if (!(context.Theme is BasicTheme))
{
return Task.CompletedTask;
return;
}
var languageProvider = context.ServiceProvider.GetService<ILanguageProvider>();
//TODO: This duplicates GetLanguages() usage. Can we eleminate this?
if (languageProvider.GetLanguages().Count > 1)
var languages = await languageProvider.GetLanguagesAsync();
if (languages.Count > 1)
{
context.Toolbar.Items.Add(new ToolbarItem(typeof(LanguageSwitchViewComponent)));
}
@ -34,8 +35,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars
{
context.Toolbar.Items.Add(new ToolbarItem(typeof(UserMenuViewComponent)));
}
return Task.CompletedTask;
}
}
}

@ -56,10 +56,10 @@ namespace Microsoft.AspNetCore.Builder
using (var scope = app.ApplicationServices.CreateScope())
{
var languageProvider = scope.ServiceProvider.GetRequiredService<ILanguageProvider>();
languages = languageProvider.GetLanguages();
languages = AsyncHelper.RunSync(() => languageProvider.GetLanguagesAsync());
var settingProvider = scope.ServiceProvider.GetRequiredService<ISettingProvider>();
defaultLanguage = settingProvider.GetOrNull(LocalizationSettingNames.DefaultLanguage);
defaultLanguage = AsyncHelper.RunSync(() => settingProvider.GetOrNullAsync(LocalizationSettingNames.DefaultLanguage));
}
var options = !languages.Any()

@ -1,25 +1,12 @@
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Authorization;
using Volo.Abp.Threading;
namespace Microsoft.AspNetCore.Authorization
{
// TODO: Complete all Sync extension methods!
public static class AbpAuthorizationServiceExtensions
{
public static AuthorizationResult Authorize(this IAuthorizationService authorizationService, ClaimsPrincipal user, object resource, string policyName)
{
return AsyncHelper.RunSync(() => authorizationService.AuthorizeAsync(user, resource, policyName));
}
public static AuthorizationResult Authorize(this IAuthorizationService authorizationService, ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
return AsyncHelper.RunSync(() => authorizationService.AuthorizeAsync(user, resource, requirements));
}
public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService authorizationService, string policyName)
{
return AuthorizeAsync(
@ -29,15 +16,6 @@ namespace Microsoft.AspNetCore.Authorization
);
}
public static AuthorizationResult Authorize(this IAuthorizationService authorizationService, string policyName)
{
return Authorize(
authorizationService,
authorizationService.AsAbpAuthorizationService().CurrentPrincipal,
policyName
);
}
public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement)
{
return authorizationService.AuthorizeAsync(
@ -81,25 +59,11 @@ namespace Microsoft.AspNetCore.Authorization
);
}
public static AuthorizationResult Authorize(this IAuthorizationService authorizationService, object resource, string policyName)
{
return authorizationService.Authorize(
authorizationService.AsAbpAuthorizationService().CurrentPrincipal,
resource,
policyName
);
}
public static async Task<bool> IsGrantedAsync(this IAuthorizationService authorizationService, string policyName)
{
return (await authorizationService.AuthorizeAsync(policyName)).Succeeded;
}
public static bool IsGranted(this IAuthorizationService authorizationService, string policyName)
{
return authorizationService.Authorize(policyName).Succeeded;
}
public static async Task<bool> IsGrantedAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement)
{
return (await authorizationService.AuthorizeAsync(resource, requirement)).Succeeded;
@ -133,11 +97,6 @@ namespace Microsoft.AspNetCore.Authorization
}
}
public static void Check(this IAuthorizationService authorizationService, string policyName)
{
AsyncHelper.RunSync(() => authorizationService.CheckAsync(policyName));
}
public static async Task CheckAsync(this IAuthorizationService authorizationService, object resource, IAuthorizationRequirement requirement)
{
if (!await authorizationService.IsGrantedAsync(resource, requirement))

@ -39,9 +39,9 @@ namespace Volo.Abp.Authorization
await invocation.ProceedAsync();
}
protected virtual Task AuthorizeAsync(IAbpMethodInvocation invocation)
protected virtual async Task AuthorizeAsync(IAbpMethodInvocation invocation)
{
return _methodInvocationAuthorizationService.CheckAsync(
await _methodInvocationAuthorizationService.CheckAsync(
new MethodInvocationAuthorizationContext(
invocation.Method
)

@ -1,6 +1,4 @@
using System;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading;
using Volo.Abp.DynamicProxy;
namespace Volo.Abp.BackgroundJobs
{
@ -9,19 +7,6 @@ namespace Volo.Abp.BackgroundJobs
/// </summary>
public static class BackgroundJobManagerExtensions
{
/// <summary>
/// Enqueues a job to be executed.
/// </summary>
/// <typeparam name="TArgs">Type of the arguments of job.</typeparam>
/// <param name="backgroundJobManager">Background job manager reference</param>
/// <param name="args">Job arguments.</param>
/// <param name="priority">Job priority.</param>
/// <param name="delay">Job delay (wait duration before first try).</param>
public static string Enqueue<TArgs>(this IBackgroundJobManager backgroundJobManager, TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null)
{
return AsyncHelper.RunSync(() => backgroundJobManager.EnqueueAsync<TArgs>(args, priority, delay));
}
/// <summary>
/// Checks if background job system has a real implementation.
/// It returns false if the current implementation is <see cref="NullBackgroundJobManager"/>.

@ -29,16 +29,20 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ
private static void StartJobQueueManager(ApplicationInitializationContext context)
{
context.ServiceProvider
.GetRequiredService<IJobQueueManager>()
.Start();
AsyncHelper.RunSync(
() => context.ServiceProvider
.GetRequiredService<IJobQueueManager>()
.StartAsync()
);
}
private static void StopJobQueueManager(ApplicationShutdownContext context)
{
context.ServiceProvider
.GetRequiredService<IJobQueueManager>()
.Stop();
AsyncHelper.RunSync(
() => context.ServiceProvider
.GetRequiredService<IJobQueueManager>()
.StopAsync()
);
}
}
}

@ -61,7 +61,7 @@ namespace Volo.Abp.BackgroundJobs.RabbitMQ
.GetRequiredService(typeof(IJobQueue<>)
.MakeGenericType(typeof(TArgs)));
jobQueue.Start();
AsyncHelper.RunSync(() => jobQueue.StartAsync());
return jobQueue;
});

@ -36,9 +36,7 @@ namespace Volo.Abp.BackgroundJobs
{
var store = scope.ServiceProvider.GetRequiredService<IBackgroundJobStore>();
var waitingJobs = AsyncHelper.RunSync(
() => store.GetWaitingJobsAsync(WorkerOptions.MaxJobFetchCount)
);
var waitingJobs = store.GetWaitingJobs(WorkerOptions.MaxJobFetchCount);
if (!waitingJobs.Any())
{
@ -64,7 +62,7 @@ namespace Volo.Abp.BackgroundJobs
{
jobExecuter.Execute(context);
AsyncHelper.RunSync(() => store.DeleteAsync(jobInfo.Id));
store.Delete(jobInfo.Id);
}
catch (BackgroundJobExecutionException)
{
@ -96,7 +94,7 @@ namespace Volo.Abp.BackgroundJobs
{
try
{
store.UpdateAsync(jobInfo);
store.Update(jobInfo);
}
catch (Exception updateEx)
{
@ -107,9 +105,8 @@ namespace Volo.Abp.BackgroundJobs
protected virtual DateTime? CalculateNextTryTime(BackgroundJobInfo jobInfo, IClock clock)
{
var nextWaitDuration = WorkerOptions.DefaultFirstWaitDuration * (Math.Pow(WorkerOptions.DefaultWaitFactor, jobInfo.TryCount - 1));
var nextTryDate = jobInfo.LastTryTime.HasValue
? jobInfo.LastTryTime.Value.AddSeconds(nextWaitDuration)
: clock.Now.AddSeconds(nextWaitDuration);
var nextTryDate = jobInfo.LastTryTime?.AddSeconds(nextWaitDuration) ??
clock.Now.AddSeconds(nextWaitDuration);
if (nextTryDate.Subtract(jobInfo.CreationTime).TotalSeconds > WorkerOptions.DefaultTimeout)
{

@ -9,6 +9,13 @@ namespace Volo.Abp.BackgroundJobs
/// </summary>
public interface IBackgroundJobStore
{
/// <summary>
/// Gets a BackgroundJobInfo based on the given jobId.
/// </summary>
/// <param name="jobId">The Job Unique Identifier.</param>
/// <returns>The BackgroundJobInfo object.</returns>
BackgroundJobInfo Find(Guid jobId);
/// <summary>
/// Gets a BackgroundJobInfo based on the given jobId.
/// </summary>
@ -16,12 +23,27 @@ namespace Volo.Abp.BackgroundJobs
/// <returns>The BackgroundJobInfo object.</returns>
Task<BackgroundJobInfo> FindAsync(Guid jobId);
/// <summary>
/// Inserts a background job.
/// </summary>
/// <param name="jobInfo">Job information.</param>
void Insert(BackgroundJobInfo jobInfo);
/// <summary>
/// Inserts a background job.
/// </summary>
/// <param name="jobInfo">Job information.</param>
Task InsertAsync(BackgroundJobInfo jobInfo);
/// <summary>
/// Gets waiting jobs. It should get jobs based on these:
/// Conditions: !IsAbandoned And NextTryTime &lt;= Clock.Now.
/// Order by: Priority DESC, TryCount ASC, NextTryTime ASC.
/// Maximum result: <paramref name="maxResultCount"/>.
/// </summary>
/// <param name="maxResultCount">Maximum result count.</param>
List<BackgroundJobInfo> GetWaitingJobs(int maxResultCount);
/// <summary>
/// Gets waiting jobs. It should get jobs based on these:
/// Conditions: !IsAbandoned And NextTryTime &lt;= Clock.Now.
@ -31,12 +53,24 @@ namespace Volo.Abp.BackgroundJobs
/// <param name="maxResultCount">Maximum result count.</param>
Task<List<BackgroundJobInfo>> GetWaitingJobsAsync(int maxResultCount);
/// <summary>
/// Deletes a job.
/// </summary>
/// <param name="jobId">The Job Unique Identifier.</param>
void Delete(Guid jobId);
/// <summary>
/// Deletes a job.
/// </summary>
/// <param name="jobId">The Job Unique Identifier.</param>
Task DeleteAsync(Guid jobId);
/// <summary>
/// Updates a job.
/// </summary>
/// <param name="jobInfo">Job information.</param>
void Update(BackgroundJobInfo jobInfo);
/// <summary>
/// Updates a job.
/// </summary>

@ -23,11 +23,21 @@ namespace Volo.Abp.BackgroundJobs
_jobs = new ConcurrentDictionary<Guid, BackgroundJobInfo>();
}
public BackgroundJobInfo Find(Guid jobId)
{
return _jobs.GetOrDefault(jobId);
}
public virtual Task<BackgroundJobInfo> FindAsync(Guid jobId)
{
return Task.FromResult(_jobs.GetOrDefault(jobId));
}
public void Insert(BackgroundJobInfo jobInfo)
{
_jobs[jobInfo.Id] = jobInfo;
}
public virtual Task InsertAsync(BackgroundJobInfo jobInfo)
{
_jobs[jobInfo.Id] = jobInfo;
@ -35,6 +45,17 @@ namespace Volo.Abp.BackgroundJobs
return Task.FromResult(0);
}
public List<BackgroundJobInfo> GetWaitingJobs(int maxResultCount)
{
return _jobs.Values
.Where(t => !t.IsAbandoned && t.NextTryTime <= Clock.Now)
.OrderByDescending(t => t.Priority)
.ThenBy(t => t.TryCount)
.ThenBy(t => t.NextTryTime)
.Take(maxResultCount)
.ToList();
}
public virtual Task<List<BackgroundJobInfo>> GetWaitingJobsAsync(int maxResultCount)
{
var waitingJobs = _jobs.Values
@ -48,6 +69,11 @@ namespace Volo.Abp.BackgroundJobs
return Task.FromResult(waitingJobs);
}
public void Delete(Guid jobId)
{
_jobs.TryRemove(jobId, out _);
}
public virtual Task DeleteAsync(Guid jobId)
{
_jobs.TryRemove(jobId, out _);
@ -55,6 +81,14 @@ namespace Volo.Abp.BackgroundJobs
return Task.FromResult(0);
}
public void Update(BackgroundJobInfo jobInfo)
{
if (jobInfo.IsAbandoned)
{
DeleteAsync(jobInfo.Id);
}
}
public virtual Task UpdateAsync(BackgroundJobInfo jobInfo)
{
if (jobInfo.IsAbandoned)

@ -15,9 +15,11 @@ namespace Volo.Abp.BackgroundWorkers
var options = context.ServiceProvider.GetRequiredService<IOptions<BackgroundWorkerOptions>>().Value;
if (options.IsEnabled)
{
context.ServiceProvider
.GetRequiredService<IBackgroundWorkerManager>()
.Start();
AsyncHelper.RunSync(
() => context.ServiceProvider
.GetRequiredService<IBackgroundWorkerManager>()
.StartAsync()
);
}
}
@ -26,9 +28,11 @@ namespace Volo.Abp.BackgroundWorkers
var options = context.ServiceProvider.GetRequiredService<IOptions<BackgroundWorkerOptions>>().Value;
if (options.IsEnabled)
{
context.ServiceProvider
.GetRequiredService<IBackgroundWorkerManager>()
.Stop();
AsyncHelper.RunSync(
() => context.ServiceProvider
.GetRequiredService<IBackgroundWorkerManager>()
.StopAsync()
);
}
}
}

@ -32,7 +32,9 @@ namespace Volo.Abp.BackgroundWorkers
if (IsRunning)
{
worker.Start();
AsyncHelper.RunSync(
() => worker.StartAsync()
);
}
}

@ -26,12 +26,12 @@ namespace Volo.Abp.BackgroundWorkers
public override async Task StartAsync(CancellationToken cancellationToken = default)
{
await base.StartAsync(cancellationToken);
await Timer.StartAsync(cancellationToken);
Timer.Start(cancellationToken);
}
public override async Task StopAsync(CancellationToken cancellationToken = default)
{
await Timer.StopAsync(cancellationToken);
Timer.Stop(cancellationToken);
await base.StopAsync(cancellationToken);
}

@ -27,7 +27,11 @@ namespace Volo.Abp.Cli.Commands
{
if (commandLineArgs.Target == null)
{
throw new CliUsageException("Module name is missing!" + Environment.NewLine + Environment.NewLine + await GetUsageInfo());
throw new CliUsageException(
"Module name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
var skipDbMigrations = Convert.ToBoolean(
@ -40,7 +44,7 @@ namespace Volo.Abp.Cli.Commands
);
}
public Task<string> GetUsageInfo()
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -61,14 +65,14 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine(" abp add-module Volo.Blogging -s Acme.BookStore --skip-db-migrations false Adds the module to the given solution but doesn't create a database migration.");
sb.AppendLine("");
return Task.FromResult(sb.ToString());
return sb.ToString();
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("Adds a multi-package module to a solution by finding all packages of the module, " +
"finding related projects in the solution and adding each package to the" +
" corresponding project in the solution.");
return "Adds a multi-package module to a solution by finding all packages of the module, " +
"finding related projects in the solution and adding each package to the" +
" corresponding project in the solution.";
}
protected virtual string GetSolutionFile(CommandLineArgs commandLineArgs)

@ -27,7 +27,11 @@ namespace Volo.Abp.Cli.Commands
{
if (commandLineArgs.Target == null)
{
throw new CliUsageException("Package name is missing!" + Environment.NewLine + Environment.NewLine + await GetUsageInfo());
throw new CliUsageException(
"Package name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
await ProjectNugetPackageAdder.AddAsync(
@ -36,7 +40,7 @@ namespace Volo.Abp.Cli.Commands
);
}
public Task<string> GetUsageInfo()
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -55,14 +59,14 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine(" abp add-package Volo.Abp.FluentValidation -p Acme.BookStore.Application Adds the package to the given project.");
sb.AppendLine("");
return Task.FromResult(sb.ToString());
return sb.ToString();
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("Adds a new ABP package to a project by adding related nuget package" +
" as a dependency to the project and adding [DependsOn(...)] attribute to" +
" the module class in the project.");
return "Adds a new ABP package to a project by adding related nuget package" +
" as a dependency to the project and adding [DependsOn(...)] attribute to" +
" the module class in the project.";
}
protected virtual string GetProjectFile(CommandLineArgs commandLineArgs)

@ -28,7 +28,7 @@ namespace Volo.Abp.Cli.Commands
{
if (string.IsNullOrWhiteSpace(commandLineArgs.Target))
{
Logger.LogInformation(await GetUsageInfo());
Logger.LogInformation(GetUsageInfo());
return;
}
@ -37,11 +37,11 @@ namespace Volo.Abp.Cli.Commands
using (var scope = ServiceScopeFactory.CreateScope())
{
var command = (IConsoleCommand) scope.ServiceProvider.GetRequiredService(commandType);
Logger.LogInformation(await command.GetUsageInfo());
Logger.LogInformation(command.GetUsageInfo());
}
}
public async Task<string> GetUsageInfo()
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -58,8 +58,8 @@ namespace Volo.Abp.Cli.Commands
using (var scope = ServiceScopeFactory.CreateScope())
{
shortDescription = await ((IConsoleCommand)scope.ServiceProvider.GetRequiredService(command.Value))
.GetShortDescriptionAsync();
shortDescription = ((IConsoleCommand) scope.ServiceProvider
.GetRequiredService(command.Value)).GetShortDescription();
}
sb.Append(" >");
@ -74,9 +74,9 @@ namespace Volo.Abp.Cli.Commands
return sb.ToString();
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("");
return string.Empty;
}
}
}

@ -7,8 +7,8 @@ namespace Volo.Abp.Cli.Commands
{
Task ExecuteAsync(CommandLineArgs commandLineArgs);
Task<string> GetUsageInfo();
string GetUsageInfo();
Task<string> GetShortDescriptionAsync();
string GetShortDescription();
}
}

@ -26,14 +26,22 @@ namespace Volo.Abp.Cli.Commands
{
if (commandLineArgs.Target.IsNullOrEmpty())
{
throw new CliUsageException("Username name is missing!" + Environment.NewLine + Environment.NewLine + await GetUsageInfo());
throw new CliUsageException(
"Username name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
Console.Write("Password: ");
var password = ConsoleHelper.ReadSecret();
if (password.IsNullOrWhiteSpace())
{
throw new CliUsageException("Password name is missing!" + Environment.NewLine + Environment.NewLine + await GetUsageInfo());
throw new CliUsageException(
"Password name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
await AuthService.LoginAsync(commandLineArgs.Target, password);
@ -41,7 +49,7 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation($"Successfully logged in as '{commandLineArgs.Target}'");
}
public Task<string> GetUsageInfo()
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -52,12 +60,12 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine("Example:");
sb.AppendLine(" abp login john");
return Task.FromResult(sb.ToString());
return sb.ToString();
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("");
return string.Empty;
}
}
}

@ -24,14 +24,14 @@ namespace Volo.Abp.Cli.Commands
return AuthService.LogoutAsync();
}
public Task<string> GetUsageInfo()
public string GetUsageInfo()
{
return Task.FromResult("");
return string.Empty;
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("");
return string.Empty;
}
}
}

@ -30,7 +30,11 @@ namespace Volo.Abp.Cli.Commands
{
if (commandLineArgs.Target == null)
{
throw new CliUsageException("Project name is missing!" + Environment.NewLine + Environment.NewLine + await GetUsageInfo());
throw new CliUsageException(
"Project name is missing!" +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
Logger.LogInformation("Creating a new project...");
@ -98,7 +102,7 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation($"The output folder is: '{outputFolder}'");
}
public Task<string> GetUsageInfo()
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -124,12 +128,12 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine("");
sb.AppendLine("See the documentation for more info.");
return Task.FromResult(sb.ToString());
return sb.ToString();
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("Generates a new solution based on the ABP startup templates.");
return "Generates a new solution based on the ABP startup templates.";
}
protected virtual DatabaseProvider GetDatabaseProviderOrNull(CommandLineArgs commandLineArgs)

@ -43,7 +43,7 @@ namespace Volo.Abp.Cli.Commands
public async Task ExecuteAsync(CommandLineArgs commandLineArgs)
{
UpdateNugetPackages(commandLineArgs);
await UpdateNugetPackages(commandLineArgs);
UpdateNpmPackages();
var options = commandLineArgs.Options
@ -61,7 +61,7 @@ namespace Volo.Abp.Cli.Commands
_npmPackagesUpdater.Update(Directory.GetCurrentDirectory());
}
private void UpdateNugetPackages(CommandLineArgs commandLineArgs)
private async Task UpdateNugetPackages(CommandLineArgs commandLineArgs)
{
var includePreviews =
commandLineArgs.Options.GetOrNull(Options.IncludePreviews.Short, Options.IncludePreviews.Long) != null;
@ -72,7 +72,7 @@ namespace Volo.Abp.Cli.Commands
{
var solutionName = Path.GetFileName(solution).RemovePostFix(".sln");
_nugetPackagesVersionUpdater.UpdateSolution(solution, includePreviews);
await _nugetPackagesVersionUpdater.UpdateSolutionAsync(solution, includePreviews);
Logger.LogInformation($"Volo packages are updated in {solutionName} solution.");
return;
@ -84,17 +84,20 @@ namespace Volo.Abp.Cli.Commands
{
var projectName = Path.GetFileName(project).RemovePostFix(".csproj");
_nugetPackagesVersionUpdater.UpdateProject(project, includePreviews);
await _nugetPackagesVersionUpdater.UpdateProjectAsync(project, includePreviews);
Logger.LogInformation($"Volo packages are updated in {projectName} project.");
return;
}
throw new CliUsageException("No solution or project found in this directory." + Environment.NewLine +
Environment.NewLine + AsyncHelper.RunSync(GetUsageInfo));
throw new CliUsageException(
"No solution or project found in this directory." +
Environment.NewLine + Environment.NewLine +
GetUsageInfo()
);
}
public Task<string> GetUsageInfo()
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -111,13 +114,13 @@ namespace Volo.Abp.Cli.Commands
sb.AppendLine("");
sb.AppendLine("See the documentation for more info.");
return Task.FromResult(sb.ToString());
return sb.ToString();
}
public Task<string> GetShortDescriptionAsync()
public string GetShortDescription()
{
return Task.FromResult("Automatically updates all ABP related NuGet packages and NPM packages in a" +
" solution or project to the latest versions");
return "Automatically updates all ABP related NuGet packages and NPM packages in a" +
" solution or project to the latest versions";
}
public static class Options

@ -1,9 +1,9 @@
using NuGet.Versioning;
using System.IO;
using System.Threading.Tasks;
using System.Xml;
using Volo.Abp.Cli.NuGet;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.Cli.ProjectModification
{
@ -16,29 +16,29 @@ namespace Volo.Abp.Cli.ProjectModification
_nuGetService = nuGetService;
}
public void UpdateSolution(string solutionPath, bool includePreviews)
public async Task UpdateSolutionAsync(string solutionPath, bool includePreviews)
{
var projectPaths = ProjectFinder.GetProjectFiles(solutionPath);
foreach (var filePath in projectPaths)
{
UpdateInternal(filePath, includePreviews);
await UpdateInternalAsync(filePath, includePreviews);
}
}
public void UpdateProject(string projectPath, bool includePreviews)
public async Task UpdateProjectAsync(string projectPath, bool includePreviews)
{
UpdateInternal(projectPath, includePreviews);
await UpdateInternalAsync(projectPath, includePreviews);
}
protected virtual void UpdateInternal(string projectPath, bool includePreviews)
protected virtual async Task UpdateInternalAsync(string projectPath, bool includePreviews)
{
var fileContent = File.ReadAllText(projectPath);
File.WriteAllText(projectPath, UpdateVoloPackages(fileContent, includePreviews));
File.WriteAllText(projectPath, await UpdateVoloPackagesAsync(fileContent, includePreviews));
}
private string UpdateVoloPackages(string content, bool includePreviews)
private async Task<string> UpdateVoloPackagesAsync(string content, bool includePreviews)
{
var doc = new XmlDocument() { PreserveWhitespace = true };
doc.LoadXml(content);
@ -49,7 +49,7 @@ namespace Volo.Abp.Cli.ProjectModification
var packageId = package.Attributes["Include"].Value;
var packageVersion = SemanticVersion.Parse(versionAttribute.Value);
var latestVersion = AsyncHelper.RunSync(() => _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews));
var latestVersion = await _nuGetService.GetLatestVersionOrNullAsync(packageId, includePreviews);
if (latestVersion != null && packageVersion < latestVersion)
{

@ -124,20 +124,5 @@ namespace Volo.Abp.Application.Services
await AuthorizationService.CheckAsync(policyName);
}
/// <summary>
/// Checks for given <paramref name="policyName"/>.
/// Throws <see cref="AbpAuthorizationException"/> if given policy has not been granted.
/// </summary>
/// <param name="policyName">The policy name. This method does nothing if given <paramref name="policyName"/> is null or empty.</param>
protected virtual void CheckPolicy([CanBeNull] string policyName)
{
if (string.IsNullOrEmpty(policyName))
{
return;
}
AuthorizationService.Check(policyName);
}
}
}

@ -1,168 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Application.Services
{
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected AsyncCrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected AsyncCrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
: AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected AsyncCrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
{
}
}
public abstract class AsyncCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: AsyncCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected AsyncCrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
{
}
protected override TEntityDto MapToGetListOutputDto(TEntity entity)
{
return MapToGetOutputDto(entity);
}
}
public abstract class AsyncCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CrudAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>,
IAsyncCrudAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }
protected AsyncCrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
{
AsyncQueryableExecuter = DefaultAsyncQueryableExecuter.Instance;
}
public virtual async Task<TGetOutputDto> GetAsync(TKey id)
{
await CheckGetPolicyAsync();
var entity = await GetEntityByIdAsync(id);
return MapToGetOutputDto(entity);
}
public virtual async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{
await CheckGetListPolicyAsync();
var query = CreateFilteredQuery(input);
var totalCount = await AsyncQueryableExecuter.CountAsync(query);
query = ApplySorting(query, input);
query = ApplyPaging(query, input);
var entities = await AsyncQueryableExecuter.ToListAsync(query);
return new PagedResultDto<TGetListOutputDto>(
totalCount,
entities.Select(MapToGetListOutputDto).ToList()
);
}
public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input)
{
await CheckCreatePolicyAsync();
var entity = MapToEntity(input);
TryToSetTenantId(entity);
await Repository.InsertAsync(entity, autoSave: true);
return MapToGetOutputDto(entity);
}
public virtual async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
{
await CheckUpdatePolicyAsync();
var entity = await GetEntityByIdAsync(id);
//TODO: Check if input has id different than given id and normalize if it's default value, throw ex otherwise
MapToEntity(input, entity);
await Repository.UpdateAsync(entity, autoSave: true);
return MapToGetOutputDto(entity);
}
public virtual async Task DeleteAsync(TKey id)
{
await CheckDeletePolicyAsync();
await Repository.DeleteAsync(id);
}
protected virtual Task<TEntity> GetEntityByIdAsync(TKey id)
{
return Repository.GetAsync(id);
}
protected virtual async Task CheckGetPolicyAsync()
{
await CheckPolicyAsync(GetPolicyName);
}
protected virtual async Task CheckGetListPolicyAsync()
{
await CheckPolicyAsync(GetListPolicyName);
}
protected virtual async Task CheckCreatePolicyAsync()
{
await CheckPolicyAsync(CreatePolicyName);
}
protected virtual async Task CheckUpdatePolicyAsync()
{
await CheckPolicyAsync(UpdatePolicyName);
}
protected virtual async Task CheckDeletePolicyAsync()
{
await CheckPolicyAsync(DeletePolicyName);
}
}
}

@ -1,8 +1,13 @@
using System.Linq;
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.Application.Services
{
@ -34,7 +39,6 @@ namespace Volo.Abp.Application.Services
: CrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
where TCreateInput : IEntityDto<TKey>
{
protected CrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
@ -44,9 +48,9 @@ namespace Volo.Abp.Application.Services
}
public abstract class CrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
: CrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TEntityDto : IEntityDto<TKey>
{
protected CrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
@ -61,38 +65,52 @@ namespace Volo.Abp.Application.Services
}
public abstract class CrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: CrudAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>,
: ApplicationService,
ICrudAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }
protected IRepository<TEntity, TKey> Repository { get; }
protected virtual string GetPolicyName { get; set; }
protected virtual string GetListPolicyName { get; set; }
protected virtual string CreatePolicyName { get; set; }
protected virtual string UpdatePolicyName { get; set; }
protected virtual string DeletePolicyName { get; set; }
protected CrudAppService(IRepository<TEntity, TKey> repository)
: base(repository)
{
Repository = repository;
AsyncQueryableExecuter = DefaultAsyncQueryableExecuter.Instance;
}
public virtual TGetOutputDto Get(TKey id)
public virtual async Task<TGetOutputDto> GetAsync(TKey id)
{
CheckGetPolicy();
await CheckGetPolicyAsync();
var entity = GetEntityById(id);
var entity = await GetEntityByIdAsync(id);
return MapToGetOutputDto(entity);
}
public virtual PagedResultDto<TGetListOutputDto> GetList(TGetListInput input)
public virtual async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{
CheckGetListPolicy();
await CheckGetListPolicyAsync();
var query = CreateFilteredQuery(input);
var totalCount = query.Count();
var totalCount = await AsyncQueryableExecuter.CountAsync(query);
query = ApplySorting(query, input);
query = ApplyPaging(query, input);
var entities = query.ToList();
var entities = await AsyncQueryableExecuter.ToListAsync(query);
return new PagedResultDto<TGetListOutputDto>(
totalCount,
@ -100,65 +118,218 @@ namespace Volo.Abp.Application.Services
);
}
public virtual TGetOutputDto Create(TCreateInput input)
public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input)
{
CheckCreatePolicy();
await CheckCreatePolicyAsync();
var entity = MapToEntity(input);
TryToSetTenantId(entity);
Repository.Insert(entity, autoSave: true);
await Repository.InsertAsync(entity, autoSave: true);
return MapToGetOutputDto(entity);
}
public virtual TGetOutputDto Update(TKey id, TUpdateInput input)
public virtual async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
{
CheckUpdatePolicy();
await CheckUpdatePolicyAsync();
var entity = GetEntityById(id);
var entity = await GetEntityByIdAsync(id);
//TODO: Check if input has id different than given id and normalize if it's default value, throw ex otherwise
MapToEntity(input, entity);
Repository.Update(entity, autoSave: true);
await Repository.UpdateAsync(entity, autoSave: true);
return MapToGetOutputDto(entity);
}
public virtual void Delete(TKey id)
public virtual async Task DeleteAsync(TKey id)
{
CheckDeletePolicy();
await CheckDeletePolicyAsync();
Repository.Delete(id);
await Repository.DeleteAsync(id);
}
protected virtual TEntity GetEntityById(TKey id)
protected virtual Task<TEntity> GetEntityByIdAsync(TKey id)
{
return Repository.Get(id);
return Repository.GetAsync(id);
}
protected virtual void CheckGetPolicy()
protected virtual async Task CheckGetPolicyAsync()
{
CheckPolicy(GetPolicyName);
await CheckPolicyAsync(GetPolicyName);
}
protected virtual void CheckGetListPolicy()
protected virtual async Task CheckGetListPolicyAsync()
{
CheckPolicy(GetListPolicyName);
await CheckPolicyAsync(GetListPolicyName);
}
protected virtual void CheckCreatePolicy()
protected virtual async Task CheckCreatePolicyAsync()
{
CheckPolicy(CreatePolicyName);
await CheckPolicyAsync(CreatePolicyName);
}
protected virtual async Task CheckUpdatePolicyAsync()
{
await CheckPolicyAsync(UpdatePolicyName);
}
protected virtual async Task CheckDeletePolicyAsync()
{
await CheckPolicyAsync(DeletePolicyName);
}
/// <summary>
/// Should apply sorting if needed.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> ApplySorting(IQueryable<TEntity> query, TGetListInput input)
{
//Try to sort query if available
var sortInput = input as ISortedResultRequest;
if (sortInput != null)
{
if (!sortInput.Sorting.IsNullOrWhiteSpace())
{
return query.OrderBy(sortInput.Sorting);
}
}
//IQueryable.Task requires sorting, so we should sort if Take will be used.
if (input is ILimitedResultRequest)
{
return query.OrderByDescending(e => e.Id);
}
//No sorting
return query;
}
/// <summary>
/// Should apply paging if needed.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> ApplyPaging(IQueryable<TEntity> query, TGetListInput input)
{
//Try to use paging if available
var pagedInput = input as IPagedResultRequest;
if (pagedInput != null)
{
return query.PageBy(pagedInput);
}
//Try to limit query result if available
var limitedInput = input as ILimitedResultRequest;
if (limitedInput != null)
{
return query.Take(limitedInput.MaxResultCount);
}
//No paging
return query;
}
/// <summary>
/// This method should create <see cref="IQueryable{TEntity}"/> based on given input.
/// It should filter query if needed, but should not do sorting or paging.
/// Sorting should be done in <see cref="ApplySorting"/> and paging should be done in <see cref="ApplyPaging"/>
/// methods.
/// </summary>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> CreateFilteredQuery(TGetListInput input)
{
return Repository;
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetOutputDto"/>.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TGetOutputDto MapToGetOutputDto(TEntity entity)
{
return ObjectMapper.Map<TEntity, TGetOutputDto>(entity);
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetListOutputDto"/>.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TGetListOutputDto MapToGetListOutputDto(TEntity entity)
{
return ObjectMapper.Map<TEntity, TGetListOutputDto>(entity);
}
/// <summary>
/// Maps <see cref="TCreateInput"/> to <see cref="TEntity"/> to create a new entity.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TEntity MapToEntity(TCreateInput createInput)
{
var entity = ObjectMapper.Map<TCreateInput, TEntity>(createInput);
SetIdForGuids(entity);
return entity;
}
/// <summary>
/// Sets Id value for the entity if <see cref="TKey"/> is <see cref="Guid"/>.
/// It's used while creating a new entity.
/// </summary>
protected virtual void SetIdForGuids(TEntity entity)
{
var entityWithGuidId = entity as IEntity<Guid>;
if (entityWithGuidId == null || entityWithGuidId.Id != Guid.Empty)
{
return;
}
entityWithGuidId.Id = GuidGenerator.Create();
}
/// <summary>
/// Maps <see cref="TUpdateInput"/> to <see cref="TEntity"/> to update the entity.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual void MapToEntity(TUpdateInput updateInput, TEntity entity)
{
if (updateInput is IEntityDto<TKey> entityDto)
{
entityDto.Id = entity.Id;
}
ObjectMapper.Map(updateInput, entity);
}
protected virtual void CheckUpdatePolicy()
protected virtual void TryToSetTenantId(TEntity entity)
{
CheckPolicy(UpdatePolicyName);
if (entity is IMultiTenant && HasTenantIdProperty(entity))
{
var tenantId = CurrentTenant.Id;
if (!tenantId.HasValue)
{
return;
}
var propertyInfo = entity.GetType().GetProperty(nameof(IMultiTenant.TenantId));
if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
{
propertyInfo.SetValue(entity, tenantId, null);
}
}
}
protected virtual void CheckDeletePolicy()
protected virtual bool HasTenantIdProperty(TEntity entity)
{
CheckPolicy(DeletePolicyName);
return entity.GetType().GetProperty(nameof(IMultiTenant.TenantId)) != null;
}
}
}

@ -1,191 +0,0 @@
using System;
using System.Linq;
using System.Linq.Dynamic.Core;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.Application.Services
{
/// <summary>
/// This is a common base class for CrudAppService and AsyncCrudAppService classes.
/// Inherit either from CrudAppService or AsyncCrudAppService, not from this class.
/// </summary>
public abstract class CrudAppServiceBase<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput> :
ApplicationService
where TEntity : class, IEntity<TKey>
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
protected IRepository<TEntity, TKey> Repository { get; }
protected virtual string GetPolicyName { get; set; }
protected virtual string GetListPolicyName { get; set; }
protected virtual string CreatePolicyName { get; set; }
protected virtual string UpdatePolicyName { get; set; }
protected virtual string DeletePolicyName { get; set; }
protected CrudAppServiceBase(IRepository<TEntity, TKey> repository)
{
Repository = repository;
}
/// <summary>
/// Should apply sorting if needed.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> ApplySorting(IQueryable<TEntity> query, TGetListInput input)
{
//Try to sort query if available
var sortInput = input as ISortedResultRequest;
if (sortInput != null)
{
if (!sortInput.Sorting.IsNullOrWhiteSpace())
{
return query.OrderBy(sortInput.Sorting);
}
}
//IQueryable.Task requires sorting, so we should sort if Take will be used.
if (input is ILimitedResultRequest)
{
return query.OrderByDescending(e => e.Id);
}
//No sorting
return query;
}
/// <summary>
/// Should apply paging if needed.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> ApplyPaging(IQueryable<TEntity> query, TGetListInput input)
{
//Try to use paging if available
var pagedInput = input as IPagedResultRequest;
if (pagedInput != null)
{
return query.PageBy(pagedInput);
}
//Try to limit query result if available
var limitedInput = input as ILimitedResultRequest;
if (limitedInput != null)
{
return query.Take(limitedInput.MaxResultCount);
}
//No paging
return query;
}
/// <summary>
/// This method should create <see cref="IQueryable{TEntity}"/> based on given input.
/// It should filter query if needed, but should not do sorting or paging.
/// Sorting should be done in <see cref="ApplySorting"/> and paging should be done in <see cref="ApplyPaging"/>
/// methods.
/// </summary>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> CreateFilteredQuery(TGetListInput input)
{
return Repository;
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetOutputDto"/>.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TGetOutputDto MapToGetOutputDto(TEntity entity)
{
return ObjectMapper.Map<TEntity, TGetOutputDto>(entity);
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetListOutputDto"/>.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TGetListOutputDto MapToGetListOutputDto(TEntity entity)
{
return ObjectMapper.Map<TEntity, TGetListOutputDto>(entity);
}
/// <summary>
/// Maps <see cref="TCreateInput"/> to <see cref="TEntity"/> to create a new entity.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TEntity MapToEntity(TCreateInput createInput)
{
var entity = ObjectMapper.Map<TCreateInput, TEntity>(createInput);
SetIdForGuids(entity);
return entity;
}
/// <summary>
/// Sets Id value for the entity if <see cref="TKey"/> is <see cref="Guid"/>.
/// It's used while creating a new entity.
/// </summary>
protected virtual void SetIdForGuids(TEntity entity)
{
var entityWithGuidId = entity as IEntity<Guid>;
if (entityWithGuidId == null || entityWithGuidId.Id != Guid.Empty)
{
return;
}
entityWithGuidId.Id = GuidGenerator.Create();
}
/// <summary>
/// Maps <see cref="TUpdateInput"/> to <see cref="TEntity"/> to update the entity.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual void MapToEntity(TUpdateInput updateInput, TEntity entity)
{
if (updateInput is IEntityDto<TKey> entityDto)
{
entityDto.Id = entity.Id;
}
ObjectMapper.Map(updateInput, entity);
}
protected virtual void TryToSetTenantId(TEntity entity)
{
if (entity is IMultiTenant && HasTenantIdProperty(entity))
{
var tenantId = CurrentTenant.Id;
if (!tenantId.HasValue)
{
return;
}
var propertyInfo = entity.GetType().GetProperty(nameof(IMultiTenant.TenantId));
if (propertyInfo != null && propertyInfo.GetSetMethod() != null)
{
propertyInfo.SetValue(entity, tenantId, null);
}
}
}
protected virtual bool HasTenantIdProperty(TEntity entity)
{
return entity.GetType().GetProperty(nameof(IMultiTenant.TenantId)) != null;
}
}
}

@ -1,49 +0,0 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.Application.Services
{
public interface IAsyncCrudAppService<TEntityDto, in TKey>
: IAsyncCrudAppService<TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput>
: IAsyncCrudAppService<TEntityDto, TKey, TGetListInput, TEntityDto, TEntityDto>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput>
: IAsyncCrudAppService<TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: IAsyncCrudAppService<TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntityDto : IEntityDto<TKey>
{
}
public interface IAsyncCrudAppService<TGetOutputDto, TGetListOutputDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: IApplicationService
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
Task<TGetOutputDto> GetAsync(TKey id);
Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input);
Task<TGetOutputDto> CreateAsync(TCreateInput input);
Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input);
Task DeleteAsync(TKey id);
}
}

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.Application.Services
@ -24,7 +25,7 @@ namespace Volo.Abp.Application.Services
}
public interface ICrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
: ICrudAppService<TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
: ICrudAppService<TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntityDto : IEntityDto<TKey>
{
@ -35,14 +36,14 @@ namespace Volo.Abp.Application.Services
where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey>
{
TGetOutputDto Get(TKey id);
Task<TGetOutputDto> GetAsync(TKey id);
PagedResultDto<TGetListOutputDto> GetList(TGetListInput input);
Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input);
TGetOutputDto Create(TCreateInput input);
Task<TGetOutputDto> CreateAsync(TCreateInput input);
TGetOutputDto Update(TKey id, TUpdateInput input);
Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input);
void Delete(TKey id);
Task DeleteAsync(TKey id);
}
}

@ -5,7 +5,6 @@ using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading;
namespace Volo.Abp.Domain.Repositories
{
@ -27,17 +26,6 @@ namespace Volo.Abp.Domain.Repositories
}
}
public static void EnsureCollectionLoaded<TEntity, TKey, TProperty>(
this IBasicRepository<TEntity, TKey> repository,
TEntity entity,
Expression<Func<TEntity, IEnumerable<TProperty>>> propertyExpression
)
where TEntity : class, IEntity<TKey>
where TProperty : class
{
AsyncHelper.RunSync(() => repository.EnsureCollectionLoadedAsync(entity, propertyExpression));
}
public static async Task EnsurePropertyLoadedAsync<TEntity, TKey, TProperty>(
this IBasicRepository<TEntity, TKey> repository,
TEntity entity,
@ -53,16 +41,5 @@ namespace Volo.Abp.Domain.Repositories
await repo.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken);
}
}
public static void EnsurePropertyLoaded<TEntity, TKey, TProperty>(
this IBasicRepository<TEntity, TKey> repository,
TEntity entity,
Expression<Func<TEntity, TProperty>> propertyExpression
)
where TEntity : class, IEntity<TKey>
where TProperty : class
{
AsyncHelper.RunSync(() => repository.EnsurePropertyLoadedAsync(entity, propertyExpression));
}
}
}

@ -1,5 +1,6 @@
using Volo.Abp.BackgroundJobs;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.Emailing
{
@ -14,7 +15,7 @@ namespace Volo.Abp.Emailing
public override void Execute(BackgroundEmailSendingJobArgs args)
{
EmailSender.Send(args.To, args.Subject, args.Body, args.IsBodyHtml);
AsyncHelper.RunSync(() => EmailSender.SendAsync(args.To, args.Subject, args.Body, args.IsBodyHtml));
}
}
}

@ -3,7 +3,6 @@ using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Threading;
namespace Volo.Abp.Emailing
{
@ -36,27 +35,11 @@ namespace Volo.Abp.Emailing
});
}
public virtual void Send(string to, string subject, string body, bool isBodyHtml = true)
{
Send(new MailMessage
{
To = { to },
Subject = subject,
Body = body,
IsBodyHtml = isBodyHtml
});
}
public virtual async Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true)
{
await SendAsync(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml });
}
public virtual void Send(string from, string to, string subject, string body, bool isBodyHtml = true)
{
Send(new MailMessage(from, to, subject, body) { IsBodyHtml = isBodyHtml });
}
public virtual async Task SendAsync(MailMessage mail, bool normalize = true)
{
if (normalize)
@ -86,28 +69,12 @@ namespace Volo.Abp.Emailing
);
}
public virtual void Send(MailMessage mail, bool normalize = true)
{
if (normalize)
{
AsyncHelper.RunSync(() => NormalizeMailAsync(mail));
}
SendEmail(mail);
}
/// <summary>
/// Should implement this method to send email in derived classes.
/// </summary>
/// <param name="mail">Mail to be sent</param>
protected abstract Task SendEmailAsync(MailMessage mail);
/// <summary>
/// Should implement this method to send email in derived classes.
/// </summary>
/// <param name="mail">Mail to be sent</param>
protected abstract void SendEmail(MailMessage mail);
/// <summary>
/// Normalizes given email.
/// Fills <see cref="MailMessage.From"/> if it's not filled before.

@ -13,31 +13,11 @@ namespace Volo.Abp.Emailing
/// </summary>
Task SendAsync(string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
void Send(string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
Task SendAsync(string from, string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
void Send(string from, string to, string subject, string body, bool isBodyHtml = true);
/// <summary>
/// Sends an email.
/// </summary>
/// <param name="mail">Mail to be sent</param>
/// <param name="normalize">
/// Should normalize email?
/// If true, it sets sender address/name if it's not set before and makes mail encoding UTF-8.
/// </param>
void Send(MailMessage mail, bool normalize = true);
/// <summary>
/// Sends an email.
/// </summary>

@ -31,13 +31,6 @@ namespace Volo.Abp.Emailing
return Task.FromResult(0);
}
protected override void SendEmail(MailMessage mail)
{
Logger.LogWarning("USING NullEmailSender!");
Logger.LogWarning("SendEmail:");
LogEmail(mail);
}
private void LogEmail(MailMessage mail)
{
Logger.LogDebug(mail.To.ToString());

@ -75,13 +75,5 @@ namespace Volo.Abp.Emailing.Smtp
await smtpClient.SendMailAsync(mail);
}
}
protected override void SendEmail(MailMessage mail)
{
using (var smtpClient = AsyncHelper.RunSync(BuildClientAsync))
{
smtpClient.Send(mail);
}
}
}
}

@ -1,36 +0,0 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Threading;
namespace Volo.Abp.EventBus
{
public static class EventBusExtensions
{
/// <summary>
/// Triggers an event.
/// </summary>
/// <typeparam name="TEvent">Event type</typeparam>
/// <param name="eventBus">Event bus instance</param>
/// <param name="eventData">Related data for the event</param>
public static void Publish<TEvent>([NotNull] this IEventBus eventBus, [NotNull] TEvent eventData)
where TEvent : class
{
Check.NotNull(eventBus, nameof(eventBus));
AsyncHelper.RunSync(() => eventBus.PublishAsync(eventData));
}
/// <summary>
/// Triggers an event.
/// </summary>
/// <param name="eventBus">Event bus instance</param>
/// <param name="eventType">Event type</param>
/// <param name="eventData">Related data for the event</param>
public static void Publish([NotNull] this IEventBus eventBus, [NotNull] Type eventType, [NotNull] object eventData)
{
Check.NotNull(eventBus, nameof(eventBus));
AsyncHelper.RunSync(() => eventBus.PublishAsync(eventType, eventData));
}
}
}

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Authorization;
using Volo.Abp.Threading;
namespace Volo.Abp.Features
{
@ -22,30 +21,6 @@ namespace Volo.Abp.Features
return value?.To<T>() ?? defaultValue;
}
public static string GetOrNull(
[NotNull] this IFeatureChecker featureChecker,
[NotNull] string name)
{
Check.NotNull(featureChecker, nameof(featureChecker));
return AsyncHelper.RunSync(() => featureChecker.GetOrNullAsync(name));
}
public static T Get<T>(
[NotNull] this IFeatureChecker featureChecker,
[NotNull] string name,
T defaultValue = default)
where T : struct
{
return AsyncHelper.RunSync(() => featureChecker.GetAsync(name, defaultValue));
}
public static bool IsEnabled(
[NotNull] this IFeatureChecker featureChecker,
[NotNull] string name)
{
return AsyncHelper.RunSync(() => featureChecker.IsEnabledAsync(name));
}
public static async Task<bool> IsEnabledAsync(this IFeatureChecker featureChecker, bool requiresAll, params string[] featureNames)
{
if (featureNames.IsNullOrEmpty())
@ -77,11 +52,6 @@ namespace Volo.Abp.Features
return false;
}
public static bool IsEnabled(this IFeatureChecker featureChecker, bool requiresAll, params string[] featureNames)
{
return AsyncHelper.RunSync(() => featureChecker.IsEnabledAsync(requiresAll, featureNames));
}
public static async Task CheckEnabledAsync(this IFeatureChecker featureChecker, string featureName)
{
if (!(await featureChecker.IsEnabledAsync(featureName)))
@ -89,15 +59,7 @@ namespace Volo.Abp.Features
throw new AbpAuthorizationException("Feature is not enabled: " + featureName);
}
}
public static void CheckEnabled(this IFeatureChecker featureChecker, string featureName)
{
if (!featureChecker.IsEnabled(featureName))
{
throw new AbpAuthorizationException("Feature is not enabled: " + featureName);
}
}
public static async Task CheckEnabledAsync(this IFeatureChecker featureChecker, bool requiresAll, params string[] featureNames)
{
if (featureNames.IsNullOrEmpty())
@ -134,10 +96,5 @@ namespace Volo.Abp.Features
);
}
}
public static void CheckEnabled(this IFeatureChecker featureChecker, bool requiresAll, params string[] featureNames)
{
AsyncHelper.RunSync(() => featureChecker.CheckEnabledAsync(requiresAll, featureNames));
}
}
}

@ -18,9 +18,7 @@ namespace Volo.Abp.Features
public override void Intercept(IAbpMethodInvocation invocation)
{
if (AbpCrossCuttingConcerns.IsApplied(
invocation.TargetObject,
AbpCrossCuttingConcerns.FeatureChecking))
if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.FeatureChecking))
{
invocation.Proceed();
return;
@ -32,21 +30,19 @@ namespace Volo.Abp.Features
public override async Task InterceptAsync(IAbpMethodInvocation invocation)
{
if (AbpCrossCuttingConcerns.IsApplied(
invocation.TargetObject,
AbpCrossCuttingConcerns.FeatureChecking))
if (AbpCrossCuttingConcerns.IsApplied(invocation.TargetObject, AbpCrossCuttingConcerns.FeatureChecking))
{
await invocation.ProceedAsync();
return;
}
AsyncHelper.RunSync(() => CheckFeaturesAsync(invocation));
await CheckFeaturesAsync(invocation);
await invocation.ProceedAsync();
}
protected virtual Task CheckFeaturesAsync(IAbpMethodInvocation invocation)
protected virtual async Task CheckFeaturesAsync(IAbpMethodInvocation invocation)
{
return _methodInvocationFeatureCheckerService.CheckAsync(
await _methodInvocationFeatureCheckerService.CheckAsync(
new MethodInvocationFeatureCheckerContext(
invocation.Method
)

@ -4,6 +4,6 @@ namespace Volo.Abp.Http.Client.Authentication
{
public interface IRemoteServiceHttpClientAuthenticator
{
Task Authenticate(RemoteServiceHttpClientAuthenticateContext context);
Task Authenticate(RemoteServiceHttpClientAuthenticateContext context); //TODO: Rename to AuthenticateAsync
}
}

@ -0,0 +1,9 @@
using Newtonsoft.Json;
namespace Volo.Abp.Json
{
public class AbpJsonOptions
{
public JsonSerializerSettings SerializerSettings { get; } = new JsonSerializerSettings();
}
}

@ -1,4 +1,5 @@
using System;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Volo.Abp.DependencyInjection;
@ -10,9 +11,10 @@ namespace Volo.Abp.Json.Newtonsoft
{
private readonly IClock _clock;
public AbpJsonIsoDateTimeConverter(IClock clock)
public AbpJsonIsoDateTimeConverter(IClock clock, IOptions<AbpJsonOptions> abpJsonOptions)
{
_clock = clock;
DateTimeFormat = abpJsonOptions.Value.SerializerSettings.DateFormatString;
}
public override bool CanConvert(Type objectType)

@ -1,4 +1,5 @@
using System;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Volo.Abp.DependencyInjection;
@ -8,10 +9,12 @@ namespace Volo.Abp.Json.Newtonsoft
public class NewtonsoftJsonSerializer : IJsonSerializer, ITransientDependency
{
private readonly AbpJsonIsoDateTimeConverter _dateTimeConverter;
private readonly AbpJsonOptions _abpJsonOptions;
public NewtonsoftJsonSerializer(AbpJsonIsoDateTimeConverter dateTimeConverter)
public NewtonsoftJsonSerializer(AbpJsonIsoDateTimeConverter dateTimeConverter, IOptions<AbpJsonOptions> abpJsonOptions)
{
_dateTimeConverter = dateTimeConverter;
_abpJsonOptions = abpJsonOptions.Value;
}
public string Serialize(object obj, bool camelCase = true, bool indented = false)
@ -31,7 +34,7 @@ namespace Volo.Abp.Json.Newtonsoft
protected virtual JsonSerializerSettings CreateSerializerSettings(bool camelCase = true, bool indented = false)
{
var settings = new JsonSerializerSettings();
var settings = _abpJsonOptions.SerializerSettings;
settings.Converters.Insert(0, _dateTimeConverter);

@ -1,13 +0,0 @@
using System.Collections.Generic;
using Volo.Abp.Threading;
namespace Volo.Abp.Localization
{
public static class LanguageProviderExtensions
{
public static IReadOnlyList<LanguageInfo> GetLanguages(this ILanguageProvider languageProvider)
{
return AsyncHelper.RunSync(languageProvider.GetLanguagesAsync);
}
}
}

@ -88,11 +88,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
{
SetDeletionAuditProperties(entity);
AsyncHelper.RunSync(() => TriggerEntityDeleteEvents(entity));
AsyncHelper.RunSync(() => TriggerEntityDeleteEventsAsync(entity));
}
else
{
AsyncHelper.RunSync(() => TriggerEntityUpdateEvents(entity));
AsyncHelper.RunSync(() => TriggerEntityUpdateEventsAsync(entity));
}
AsyncHelper.RunSync(() => TriggerDomainEventsAsync(entity));
@ -122,11 +122,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
if (entity is ISoftDelete softDeleteEntity && softDeleteEntity.IsDeleted)
{
SetDeletionAuditProperties(entity);
await TriggerEntityDeleteEvents(entity);
await TriggerEntityDeleteEventsAsync(entity);
}
else
{
await TriggerEntityUpdateEvents(entity);
await TriggerEntityUpdateEventsAsync(entity);
}
await TriggerDomainEventsAsync(entity);
@ -294,7 +294,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
await EntityChangeEventHelper.TriggerEntityCreatingEventAsync(entity);
}
protected virtual async Task TriggerEntityUpdateEvents(TEntity entity)
protected virtual async Task TriggerEntityUpdateEventsAsync(TEntity entity)
{
await EntityChangeEventHelper.TriggerEntityUpdatedEventOnUowCompletedAsync(entity);
await EntityChangeEventHelper.TriggerEntityUpdatingEventAsync(entity);
@ -303,11 +303,11 @@ namespace Volo.Abp.Domain.Repositories.MongoDB
protected virtual async Task ApplyAbpConceptsForDeletedEntityAsync(TEntity entity)
{
SetDeletionAuditProperties(entity);
await TriggerEntityDeleteEvents(entity);
await TriggerEntityDeleteEventsAsync(entity);
await TriggerDomainEventsAsync(entity);
}
protected virtual async Task TriggerEntityDeleteEvents(TEntity entity)
protected virtual async Task TriggerEntityDeleteEventsAsync(TEntity entity)
{
await EntityChangeEventHelper.TriggerEntityDeletedEventOnUowCompletedAsync(entity);
await EntityChangeEventHelper.TriggerEntityDeletingEventAsync(entity);

@ -20,7 +20,7 @@ namespace Volo.Abp.MongoDB.DependencyInjection
protected override Type GetRepositoryType(Type dbContextType, Type entityType)
{
return typeof(MongoDbRepository<,,>).MakeGenericType(dbContextType, entityType);
return typeof(MongoDbRepository<,>).MakeGenericType(dbContextType, entityType);
}
protected override Type GetRepositoryType(Type dbContextType, Type entityType, Type primaryKeyType)

@ -18,12 +18,22 @@ namespace Volo.Abp.MultiTenancy.ConfigurationStore
public Task<TenantConfiguration> FindAsync(string name)
{
return Task.FromResult(_options.Tenants?.FirstOrDefault(t => t.Name == name));
return Task.FromResult(Find(name));
}
public Task<TenantConfiguration> FindAsync(Guid id)
{
return Task.FromResult(_options.Tenants?.FirstOrDefault(t => t.Id == id));
return Task.FromResult(Find(id));
}
public TenantConfiguration Find(string name)
{
return _options.Tenants?.FirstOrDefault(t => t.Name == name);
}
public TenantConfiguration Find(Guid id)
{
return _options.Tenants?.FirstOrDefault(t => t.Id == id);
}
}
}

@ -8,5 +8,9 @@ namespace Volo.Abp.MultiTenancy
Task<TenantConfiguration> FindAsync(string name);
Task<TenantConfiguration> FindAsync(Guid id);
TenantConfiguration Find(string name);
TenantConfiguration Find(Guid id);
}
}

@ -4,7 +4,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.MultiTenancy
{
@ -38,7 +37,7 @@ namespace Volo.Abp.MultiTenancy
.ServiceProvider
.GetRequiredService<ITenantStore>();
var tenant = AsyncHelper.RunSync(() => tenantStore.FindAsync(_currentTenant.Id.Value)); //TODO: Can we avoid from RunSync?
var tenant = tenantStore.Find(_currentTenant.Id.Value);
if (tenant?.ConnectionStrings == null)
{

@ -1,21 +0,0 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Threading;
namespace Volo.Abp.MultiTenancy
{
public static class TenantStoreExtensions
{
[CanBeNull]
public static TenantConfiguration Find(this ITenantStore tenantStore, string name)
{
return AsyncHelper.RunSync(() => tenantStore.FindAsync(name));
}
[CanBeNull]
public static TenantConfiguration Find(this ITenantStore tenantStore, Guid id)
{
return AsyncHelper.RunSync(() => tenantStore.FindAsync(id));
}
}
}

@ -72,7 +72,7 @@ namespace Volo.Abp.RabbitMQ
await TrySendQueueBindCommandsAsync();
}
protected virtual Task TrySendQueueBindCommandsAsync()
protected virtual void TrySendQueueBindCommands()
{
try
{
@ -80,7 +80,7 @@ namespace Volo.Abp.RabbitMQ
{
if (Channel == null || Channel.IsClosed)
{
return Task.CompletedTask;
return;
}
lock (ChannelSendSyncLock)
@ -115,7 +115,11 @@ namespace Volo.Abp.RabbitMQ
{
Logger.LogException(ex, LogLevel.Warning);
}
}
protected virtual Task TrySendQueueBindCommandsAsync()
{
TrySendQueueBindCommands();
return Task.CompletedTask;
}
@ -129,7 +133,7 @@ namespace Volo.Abp.RabbitMQ
if (Channel == null || Channel.IsOpen == false)
{
TryCreateChannel();
AsyncHelper.RunSync(TrySendQueueBindCommandsAsync);
TrySendQueueBindCommands();
}
}

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Threading;
namespace Volo.Abp.Settings
{
@ -29,28 +27,5 @@ namespace Volo.Abp.Settings
var value = await settingProvider.GetOrNullAsync(name);
return value?.To<T>() ?? defaultValue;
}
public static string GetOrNull([NotNull] this ISettingProvider settingProvider, [NotNull] string name)
{
Check.NotNull(settingProvider, nameof(settingProvider));
return AsyncHelper.RunSync(() => settingProvider.GetOrNullAsync(name));
}
public static List<SettingValue> GetAll([NotNull] this ISettingProvider settingProvider)
{
Check.NotNull(settingProvider, nameof(settingProvider));
return AsyncHelper.RunSync(settingProvider.GetAllAsync);
}
public static T Get<T>([NotNull] this ISettingProvider settingProvider, [NotNull] string name, T defaultValue = default)
where T : struct
{
return AsyncHelper.RunSync(() => settingProvider.GetAsync(name, defaultValue));
}
public static bool IsTrue([NotNull] this ISettingProvider settingProvider, [NotNull] string name)
{
return AsyncHelper.RunSync(() => settingProvider.IsTrueAsync(name));
}
}
}

@ -1,6 +1,5 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.DependencyInjection;
@ -10,7 +9,7 @@ namespace Volo.Abp.Threading
/// <summary>
/// A roboust timer implementation that ensures no overlapping occurs. It waits exactly specified <see cref="Period"/> between ticks.
/// </summary>
public class AbpTimer : IRunnable, ITransientDependency
public class AbpTimer : ITransientDependency
{
/// <summary>
/// This event is raised periodically according to Period of Timer.
@ -41,7 +40,7 @@ namespace Volo.Abp.Threading
_taskTimer = new Timer(TimerCallBack, null, Timeout.Infinite, Timeout.Infinite);
}
public Task StartAsync(CancellationToken cancellationToken = default)
public void Start(CancellationToken cancellationToken = default)
{
if (Period <= 0)
{
@ -53,11 +52,9 @@ namespace Volo.Abp.Threading
_taskTimer.Change(RunOnStart ? 0 : Period, Timeout.Infinite);
_isRunning = true;
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken = default)
public void Stop(CancellationToken cancellationToken = default)
{
lock (_taskTimer)
{
@ -69,8 +66,6 @@ namespace Volo.Abp.Threading
_isRunning = false;
}
return Task.CompletedTask;
}
/// <summary>

@ -1,21 +0,0 @@
using JetBrains.Annotations;
namespace Volo.Abp.Threading
{
public static class RunnableExtensions
{
public static void Start([NotNull] this IRunnable runnable)
{
Check.NotNull(runnable, nameof(runnable));
AsyncHelper.RunSync(() => runnable.StartAsync());
}
public static void Stop([NotNull] this IRunnable runnable)
{
Check.NotNull(runnable, nameof(runnable));
AsyncHelper.RunSync(() => runnable.StopAsync());
}
}
}

@ -1,6 +1,5 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.UI.Navigation
{

@ -1,7 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Volo.Abp.Aspects;
using Volo.Abp.DependencyInjection;
using Volo.Abp.DynamicProxy;

@ -0,0 +1,27 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Volo.Abp.AspNetCore.Mvc.Json
{
[Route("api/json-result-test")]
public class JsonResultController : AbpController
{
[HttpGet]
[Route("json-result-action")]
public Task<JsonResultModel> ObjectResultAction()
{
return Task.FromResult(new JsonResultModel
{
Time = DateTime.Parse("2019-01-01 11:59:59")
});
}
public class JsonResultModel
{
public DateTime Time { get; set; }
}
}
}

@ -0,0 +1,32 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Json;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Json
{
public class JsonResultController_Tests : AspNetCoreMvcTestBase
{
protected override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services)
{
services.Configure<AbpJsonOptions>(options =>
{
options.SerializerSettings.DateFormatString = "yyyy*MM*dd";
});
base.ConfigureServices(context, services);
}
[Fact]
public async Task DateFormatString_Test()
{
var time = await GetResponseAsStringAsync(
"/api/json-result-test/json-result-action"
);
time.ShouldContain("2019*01*01");
}
}
}

@ -0,0 +1,40 @@
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Json;
using Xunit;
namespace Volo.Abp.AspNetCore.Mvc.Json
{
public class JsonSerializer_Tests : AspNetCoreMvcTestBase
{
private readonly IJsonSerializer _jsonSerializer;
public JsonSerializer_Tests()
{
_jsonSerializer = ServiceProvider.GetRequiredService<IJsonSerializer>();
}
protected override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services)
{
services.Configure<AbpJsonOptions>(options =>
{
options.SerializerSettings.DateFormatString = "yyyy*MM*dd";
});
base.ConfigureServices(context, services);
}
[Fact]
public void DateFormatString_Test()
{
var output = _jsonSerializer.Serialize(new
{
Time = DateTime.Parse("2019-01-01 11:59:59")
});
output.ShouldContain("2019*01*01");
}
}
}

@ -6,7 +6,7 @@ using Volo.Abp.TestApp.Application.Dto;
namespace Volo.Abp.TestApp.Application
{
public interface IPeopleAppService : IAsyncCrudAppService<PersonDto, Guid>
public interface IPeopleAppService : ICrudAppService<PersonDto, Guid>
{
Task<ListResultDto<PhoneDto>> GetPhones(Guid id, GetPersonPhonesFilter filter);

@ -10,7 +10,7 @@ using Volo.Abp.TestApp.Application.Dto;
namespace Volo.Abp.TestApp.Application
{
public class PeopleAppService : AsyncCrudAppService<Person, PersonDto, Guid>, IPeopleAppService
public class PeopleAppService : CrudAppService<Person, PersonDto, Guid>, IPeopleAppService
{
public PeopleAppService(IRepository<Person, Guid> repository)
: base(repository)

@ -1,4 +1,6 @@
using Volo.Abp.DependencyInjection;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs
{
@ -13,10 +15,15 @@ namespace Volo.Abp.BackgroundJobs.DemoApp.Shared.Jobs
public void CreateJobs()
{
_backgroundJobManager.Enqueue(new WriteToConsoleGreenJobArgs { Value = "test 1 (green)" });
_backgroundJobManager.Enqueue(new WriteToConsoleGreenJobArgs { Value = "test 2 (green)" });
_backgroundJobManager.Enqueue(new WriteToConsoleYellowJobArgs { Value = "test 1 (yellow)" });
_backgroundJobManager.Enqueue(new WriteToConsoleYellowJobArgs { Value = "test 2 (yellow)" });
AsyncHelper.RunSync(CreateJobsAsync);
}
public async Task CreateJobsAsync()
{
await _backgroundJobManager.EnqueueAsync(new WriteToConsoleGreenJobArgs { Value = "test 1 (green)" });
await _backgroundJobManager.EnqueueAsync(new WriteToConsoleGreenJobArgs { Value = "test 2 (green)" });
await _backgroundJobManager.EnqueueAsync(new WriteToConsoleYellowJobArgs { Value = "test 1 (yellow)" });
await _backgroundJobManager.EnqueueAsync(new WriteToConsoleYellowJobArgs { Value = "test 2 (yellow)" });
}
}
}

@ -19,6 +19,13 @@ namespace Volo.Abp.BackgroundJobs
BackgroundJobRepository = backgroundJobRepository;
}
public BackgroundJobInfo Find(Guid jobId)
{
return ObjectMapper.Map<BackgroundJobRecord, BackgroundJobInfo>(
BackgroundJobRepository.Find(jobId)
);
}
public virtual async Task<BackgroundJobInfo> FindAsync(Guid jobId)
{
return ObjectMapper.Map<BackgroundJobRecord, BackgroundJobInfo>(
@ -26,6 +33,13 @@ namespace Volo.Abp.BackgroundJobs
);
}
public void Insert(BackgroundJobInfo jobInfo)
{
BackgroundJobRepository.Insert(
ObjectMapper.Map<BackgroundJobInfo, BackgroundJobRecord>(jobInfo)
);
}
public virtual async Task InsertAsync(BackgroundJobInfo jobInfo)
{
await BackgroundJobRepository.InsertAsync(
@ -33,6 +47,13 @@ namespace Volo.Abp.BackgroundJobs
);
}
public List<BackgroundJobInfo> GetWaitingJobs(int maxResultCount)
{
return ObjectMapper.Map<List<BackgroundJobRecord>, List<BackgroundJobInfo>>(
BackgroundJobRepository.GetWaitingList(maxResultCount)
);
}
public virtual async Task<List<BackgroundJobInfo>> GetWaitingJobsAsync(int maxResultCount)
{
return ObjectMapper.Map<List<BackgroundJobRecord>, List<BackgroundJobInfo>>(
@ -40,11 +61,23 @@ namespace Volo.Abp.BackgroundJobs
);
}
public void Delete(Guid jobId)
{
BackgroundJobRepository.Delete(jobId);
}
public virtual async Task DeleteAsync(Guid jobId)
{
await BackgroundJobRepository.DeleteAsync(jobId);
}
public void Update(BackgroundJobInfo jobInfo)
{
BackgroundJobRepository.Update(
ObjectMapper.Map<BackgroundJobInfo, BackgroundJobRecord>(jobInfo)
);
}
public virtual async Task UpdateAsync(BackgroundJobInfo jobInfo)
{
await BackgroundJobRepository.UpdateAsync(

@ -7,6 +7,8 @@ namespace Volo.Abp.BackgroundJobs
{
public interface IBackgroundJobRepository : IBasicRepository<BackgroundJobRecord, Guid>
{
List<BackgroundJobRecord> GetWaitingList(int maxResultCount);
Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount);
}
}

@ -21,16 +21,27 @@ namespace Volo.Abp.BackgroundJobs.EntityFrameworkCore
Clock = clock;
}
public List<BackgroundJobRecord> GetWaitingList(int maxResultCount)
{
return GetWaitingListQuery(maxResultCount)
.ToList();
}
public async Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount)
{
return await GetWaitingListQuery(maxResultCount)
.ToListAsync();
}
private IQueryable<BackgroundJobRecord> GetWaitingListQuery(int maxResultCount)
{
var now = Clock.Now;
return await DbSet
return DbSet
.Where(t => !t.IsAbandoned && t.NextTryTime <= now)
.OrderByDescending(t => t.Priority)
.ThenBy(t => t.TryCount)
.ThenBy(t => t.NextTryTime)
.Take(maxResultCount)
.ToListAsync();
.Take(maxResultCount);
}
}
}

@ -21,16 +21,27 @@ namespace Volo.Abp.BackgroundJobs.MongoDB
Clock = clock;
}
public List<BackgroundJobRecord> GetWaitingList(int maxResultCount)
{
return GetWaitingListQuery(maxResultCount)
.ToList();
}
public async Task<List<BackgroundJobRecord>> GetWaitingListAsync(int maxResultCount)
{
return await GetWaitingListQuery(maxResultCount)
.ToListAsync();
}
private IMongoQueryable<BackgroundJobRecord> GetWaitingListQuery(int maxResultCount)
{
var now = Clock.Now;
return await GetMongoQueryable()
return GetMongoQueryable()
.Where(t => !t.IsAbandoned && t.NextTryTime <= now)
.OrderByDescending(t => t.Priority)
.ThenBy(t => t.TryCount)
.ThenBy(t => t.NextTryTime)
.Take(maxResultCount)
.ToListAsync();
.Take(maxResultCount);
}
}
}

@ -34,7 +34,10 @@ namespace Volo.Blogging.Pages.Blog
var closingTag = "</p>";
var html = RenderMarkdownToString(content);
if (string.IsNullOrWhiteSpace(html))
{
return "";
}
var splittedHtml = html.Split(closingTag);
if (splittedHtml.Length < 1)

@ -5,7 +5,7 @@ using Volo.Abp.Application.Services;
namespace Volo.Abp.Identity
{
public interface IIdentityRoleAppService : IAsyncCrudAppService<IdentityRoleDto, Guid, GetIdentityRolesInput, IdentityRoleCreateDto, IdentityRoleUpdateDto>
public interface IIdentityRoleAppService : ICrudAppService<IdentityRoleDto, Guid, GetIdentityRolesInput, IdentityRoleCreateDto, IdentityRoleUpdateDto>
{
//TODO: remove after a better design
Task<List<IdentityRoleDto>> GetAllListAsync();

@ -5,7 +5,7 @@ using Volo.Abp.Application.Services;
namespace Volo.Abp.Identity
{
public interface IIdentityUserAppService : IAsyncCrudAppService<IdentityUserDto, Guid, GetIdentityUsersInput, IdentityUserCreateDto, IdentityUserUpdateDto>
public interface IIdentityUserAppService : ICrudAppService<IdentityUserDto, Guid, GetIdentityUsersInput, IdentityUserCreateDto, IdentityUserUpdateDto>
{
Task<ListResultDto<IdentityRoleDto>> GetRolesAsync(Guid id);

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Volo.Abp.Identity.Settings;
using Volo.Abp.Options;
using Volo.Abp.Settings;
using Volo.Abp.Threading;
namespace Volo.Abp.Identity
{
@ -32,20 +34,25 @@ namespace Volo.Abp.Identity
protected virtual void OverrideOptions(IdentityOptions options)
{
options.Password.RequiredLength = _settingProvider.Get(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength);
options.Password.RequiredUniqueChars = _settingProvider.Get(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars);
options.Password.RequireNonAlphanumeric = _settingProvider.Get(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric);
options.Password.RequireLowercase = _settingProvider.Get(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase);
options.Password.RequireUppercase = _settingProvider.Get(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase);
options.Password.RequireDigit = _settingProvider.Get(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit);
options.Lockout.AllowedForNewUsers = _settingProvider.Get(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers);
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(_settingProvider.Get(IdentitySettingNames.Lockout.LockoutDuration, options.Lockout.DefaultLockoutTimeSpan.TotalSeconds.To<int>()));
options.Lockout.MaxFailedAccessAttempts = _settingProvider.Get(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts);
options.SignIn.RequireConfirmedEmail = _settingProvider.Get(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail);
options.SignIn.RequireConfirmedPhoneNumber = _settingProvider.Get(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber);
AsyncHelper.RunSync(()=>OverrideOptionsAsync(options));
}
protected virtual async Task OverrideOptionsAsync(IdentityOptions options)
{
options.Password.RequiredLength = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength);
options.Password.RequiredUniqueChars = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars);
options.Password.RequireNonAlphanumeric = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric);
options.Password.RequireLowercase = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase);
options.Password.RequireUppercase = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase);
options.Password.RequireDigit = await _settingProvider.GetAsync(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit);
options.Lockout.AllowedForNewUsers = await _settingProvider.GetAsync(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers);
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(await _settingProvider.GetAsync(IdentitySettingNames.Lockout.LockoutDuration, options.Lockout.DefaultLockoutTimeSpan.TotalSeconds.To<int>()));
options.Lockout.MaxFailedAccessAttempts = await _settingProvider.GetAsync(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts);
options.SignIn.RequireConfirmedEmail = await _settingProvider.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail);
options.SignIn.RequireConfirmedPhoneNumber = await _settingProvider.GetAsync(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber);
}
}
}

@ -4,7 +4,7 @@ using Volo.Abp.Application.Services;
namespace Volo.Abp.TenantManagement
{
public interface ITenantAppService : IAsyncCrudAppService<TenantDto, Guid, GetTenantsInput, TenantCreateDto, TenantUpdateDto>
public interface ITenantAppService : ICrudAppService<TenantDto, Guid, GetTenantsInput, TenantCreateDto, TenantUpdateDto>
{
Task<string> GetDefaultConnectionStringAsync(Guid id);

@ -13,6 +13,11 @@ namespace Volo.Abp.TenantManagement
bool includeDetails = true,
CancellationToken cancellationToken = default);
Tenant FindByName(
string name,
bool includeDetails = true
);
Task<List<Tenant>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,

@ -51,5 +51,33 @@ namespace Volo.Abp.TenantManagement
return _objectMapper.Map<Tenant, TenantConfiguration>(tenant);
}
}
public TenantConfiguration Find(string name)
{
using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities!
{
var tenant = _tenantRepository.FindByName(name);
if (tenant == null)
{
return null;
}
return _objectMapper.Map<Tenant, TenantConfiguration>(tenant);
}
}
public TenantConfiguration Find(Guid id)
{
using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities!
{
var tenant = _tenantRepository.Find(id);
if (tenant == null)
{
return null;
}
return _objectMapper.Map<Tenant, TenantConfiguration>(tenant);
}
}
}
}

@ -25,7 +25,14 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
return await DbSet
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(t => t.Name == name, cancellationToken);
.FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken));
}
public Tenant FindByName(string name, bool includeDetails = true)
{
return DbSet
.IncludeDetails(includeDetails)
.FirstOrDefault(t => t.Name == name);
}
public virtual async Task<List<Tenant>> GetListAsync(
@ -45,7 +52,7 @@ namespace Volo.Abp.TenantManagement.EntityFrameworkCore
)
.OrderBy(sorting ?? nameof(Tenant.Name))
.PageBy(skipCount, maxResultCount)
.ToListAsync(cancellationToken);
.ToListAsync(GetCancellationToken(cancellationToken));
}
public override IQueryable<Tenant> WithDetails()

@ -25,7 +25,13 @@ namespace Volo.Abp.TenantManagement.MongoDB
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.FirstOrDefaultAsync(t => t.Name == name, cancellationToken);
.FirstOrDefaultAsync(t => t.Name == name, GetCancellationToken(cancellationToken));
}
public Tenant FindByName(string name, bool includeDetails = true)
{
return GetMongoQueryable()
.FirstOrDefault(t => t.Name == name);
}
public virtual async Task<List<Tenant>> GetListAsync(
@ -45,7 +51,7 @@ namespace Volo.Abp.TenantManagement.MongoDB
.OrderBy(sorting ?? nameof(Tenant.Name))
.As<IMongoQueryable<Tenant>>()
.PageBy<Tenant, IMongoQueryable<Tenant>>(skipCount, maxResultCount)
.ToListAsync(cancellationToken);
.ToListAsync(GetCancellationToken(cancellationToken));
}
}
}

@ -5,50 +5,49 @@ $rootFolder = Join-Path $packFolder "../"
# List of solutions
$solutions = (
"framework",
"modules/users",
"modules/setting-management",
"modules/permission-management",
"modules/feature-management",
"modules/tenant-management",
"modules/identity",
"modules/identityserver",
"modules/account",
"modules/audit-logging",
"modules/background-jobs",
"modules/blogging",
"modules/client-simulation",
"modules/docs",
"modules/client-simulation"
"modules/feature-management",
"modules/identity",
"modules/identityserver",
"modules/permission-management",
"modules/setting-management",
"modules/tenant-management",
"modules/users"
)
# List of projects
$projects = (
# framework
"framework/src/Volo.Abp",
# framework
"framework/src/Volo.Abp.ApiVersioning.Abstractions",
"framework/src/Volo.Abp.AspNetCore",
"framework/src/Volo.Abp.AspNetCore.Authentication.JwtBearer",
"framework/src/Volo.Abp.AspNetCore.Authentication.OAuth",
"framework/src/Volo.Abp.AspNetCore",
"framework/src/Volo.Abp.AspNetCore.MultiTenancy",
"framework/src/Volo.Abp.AspNetCore.Mvc",
"framework/src/Volo.Abp.AspNetCore.Mvc.Contracts",
"framework/src/Volo.Abp.AspNetCore.Mvc.Client",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI",
"framework/src/Volo.Abp.AspNetCore.Mvc.Contracts",
"framework/src/Volo.Abp.AspNetCore.Mvc",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Dashboards",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Packages",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared",
"framework/src/Volo.Abp.AspNetCore.Mvc.UI.Widgets",
"framework/src/Volo.Abp.AspNetCore.TestBase",
"framework/src/Volo.Abp.AspNetCore.TestBase",
"framework/src/Volo.Abp.Auditing",
"framework/src/Volo.Abp.Authorization",
"framework/src/Volo.Abp.Autofac",
"framework/src/Volo.Abp.AutoMapper",
"framework/src/Volo.Abp.BackgroundJobs",
"framework/src/Volo.Abp.BackgroundJobs.Abstractions",
"framework/src/Volo.Abp.BackgroundJobs",
"framework/src/Volo.Abp.BackgroundJobs.HangFire",
"framework/src/Volo.Abp.BackgroundJobs.RabbitMQ",
"framework/src/Volo.Abp.BackgroundWorkers",
@ -57,31 +56,33 @@ $projects = (
"framework/src/Volo.Abp.Cli.Core",
"framework/src/Volo.Abp.Cli",
"framework/src/Volo.Abp.Core",
"framework/src/Volo.Abp",
"framework/src/Volo.Abp.Dapper",
"framework/src/Volo.Abp.Data",
"framework/src/Volo.Abp.Ddd.Application",
"framework/src/Volo.Abp.Ddd.Domain",
"framework/src/Volo.Abp.Emailing",
"framework/src/Volo.Abp.EntityFrameworkCore",
"framework/src/Volo.Abp.EntityFrameworkCore.SqlServer",
"framework/src/Volo.Abp.EntityFrameworkCore.MySQL",
"framework/src/Volo.Abp.EntityFrameworkCore.PostgreSql",
"framework/src/Volo.Abp.EntityFrameworkCore.Sqlite",
"framework/src/Volo.Abp.EntityFrameworkCore.SqlServer",
"framework/src/Volo.Abp.EventBus",
"framework/src/Volo.Abp.EventBus.RabbitMQ",
"framework/src/Volo.Abp.Features",
"framework/src/Volo.Abp.FluentValidation",
"framework/src/Volo.Abp.Guids",
"framework/src/Volo.Abp.HangFire",
"framework/src/Volo.Abp.Http",
"framework/src/Volo.Abp.Http.Abstractions",
"framework/src/Volo.Abp.Http.Client",
"framework/src/Volo.Abp.Http.Client.IdentityModel",
"framework/src/Volo.Abp.Http",
"framework/src/Volo.Abp.IdentityModel",
"framework/src/Volo.Abp.Json",
"framework/src/Volo.Abp.Localization",
"framework/src/Volo.Abp.Ldap",
"framework/src/Volo.Abp.Localization.Abstractions",
"framework/src/Volo.Abp.MailKit",
"framework/src/Volo.Abp.Localization",
"framework/src/Volo.Abp.MemoryDb",
"framework/src/Volo.Abp.MongoDB",
"framework/src/Volo.Abp.MultiTenancy",
@ -100,112 +101,122 @@ $projects = (
"framework/src/Volo.Abp.Uow",
"framework/src/Volo.Abp.Validation",
"framework/src/Volo.Abp.VirtualFileSystem",
# modules/users
"modules/users/src/Volo.Abp.Users.Abstractions",
"modules/users/src/Volo.Abp.Users.Domain",
"modules/users/src/Volo.Abp.Users.Domain.Shared",
"modules/users/src/Volo.Abp.Users.EntityFrameworkCore",
"modules/users/src/Volo.Abp.Users.MongoDB",
# modules/setting-management
"modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared",
"modules/setting-management/src/Volo.Abp.SettingManagement.Domain",
"modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore",
"modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB",
"modules/setting-management/src/Volo.Abp.SettingManagement.Web",
# modules/account
"modules/account/src/Volo.Abp.Account.Application.Contracts",
"modules/account/src/Volo.Abp.Account.Application",
"modules/account/src/Volo.Abp.Account.HttpApi.Client",
"modules/account/src/Volo.Abp.Account.HttpApi",
"modules/account/src/Volo.Abp.Account.Web",
"modules/account/src/Volo.Abp.Account.Web.IdentityServer",
# modules/audit-logging
"modules/audit-logging/src/Volo.Abp.AuditLogging.Domain",
"modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared",
"modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore",
"modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB",
# modules/permission-management
"modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Domain",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Application",
"modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore",
"modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB",
"modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi",
"modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Web",
# modules/background-jobs
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain",
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared",
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore",
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB",
# modules/blogging
"modules/blogging/src/Volo.Blogging.Application.Contracts",
"modules/blogging/src/Volo.Blogging.Application",
"modules/blogging/src/Volo.Blogging.Domain",
"modules/blogging/src/Volo.Blogging.Domain.Shared",
"modules/blogging/src/Volo.Blogging.EntityFrameworkCore",
"modules/blogging/src/Volo.Blogging.HttpApi.Client",
"modules/blogging/src/Volo.Blogging.HttpApi",
"modules/blogging/src/Volo.Blogging.MongoDB",
"modules/blogging/src/Volo.Blogging.Web",
# modules/client-simulation
"modules/client-simulation/src/Volo.ClientSimulation",
"modules/client-simulation/src/Volo.ClientSimulation.Web",
# modules/docs
"modules/docs/src/Volo.Docs.Admin.Application.Contracts",
"modules/docs/src/Volo.Docs.Admin.Application",
"modules/docs/src/Volo.Docs.Admin.HttpApi.Client",
"modules/docs/src/Volo.Docs.Admin.HttpApi",
"modules/docs/src/Volo.Docs.Admin.Web",
"modules/docs/src/Volo.Docs.Application.Contracts",
"modules/docs/src/Volo.Docs.Application",
"modules/docs/src/Volo.Docs.Domain",
"modules/docs/src/Volo.Docs.Domain.Shared",
"modules/docs/src/Volo.Docs.EntityFrameworkCore",
"modules/docs/src/Volo.Docs.HttpApi.Client",
"modules/docs/src/Volo.Docs.HttpApi",
"modules/docs/src/Volo.Docs.MongoDB",
"modules/docs/src/Volo.Docs.Web",
# modules/feature-management
"modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared",
"modules/feature-management/src/Volo.Abp.FeatureManagement.Domain",
"modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts",
"modules/feature-management/src/Volo.Abp.FeatureManagement.Application",
"modules/feature-management/src/Volo.Abp.FeatureManagement.Domain",
"modules/feature-management/src/Volo.Abp.FeatureManagement.Domain.Shared",
"modules/feature-management/src/Volo.Abp.FeatureManagement.EntityFrameworkCore",
"modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB",
"modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi",
"modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi.Client",
"modules/feature-management/src/Volo.Abp.FeatureManagement.HttpApi",
"modules/feature-management/src/Volo.Abp.FeatureManagement.MongoDB",
"modules/feature-management/src/Volo.Abp.FeatureManagement.Web",
# modules/tenant-management
"modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Domain",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Application",
"modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore",
"modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB",
"modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi",
"modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi.Client",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Web",
# modules/identity
"modules/identity/src/Volo.Abp.Identity.AspNetCore",
"modules/identity/src/Volo.Abp.Identity.Application",
"modules/identity/src/Volo.Abp.Identity.Application.Contracts",
"modules/identity/src/Volo.Abp.Identity.Application",
"modules/identity/src/Volo.Abp.Identity.AspNetCore",
"modules/identity/src/Volo.Abp.Identity.Domain",
"modules/identity/src/Volo.Abp.Identity.Domain.Shared",
"modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore",
"modules/identity/src/Volo.Abp.Identity.MongoDB",
"modules/identity/src/Volo.Abp.Identity.HttpApi",
"modules/identity/src/Volo.Abp.Identity.HttpApi.Client",
"modules/identity/src/Volo.Abp.Identity.Web",
"modules/identity/src/Volo.Abp.Identity.HttpApi",
"modules/identity/src/Volo.Abp.Identity.MongoDB",
"modules/identity/src/Volo.Abp.Identity.Web",
"modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity",
# modules/identityserver
"modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared",
"modules/identityserver/src/Volo.Abp.IdentityServer.Domain",
"modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer",
"modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore",
"modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared",
"modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore",
"modules/identityserver/src/Volo.Abp.IdentityServer.MongoDB",
"modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer",
# modules/account
"modules/account/src/Volo.Abp.Account.Web",
"modules/account/src/Volo.Abp.Account.Web.IdentityServer",
# modules/docs
"modules/docs/src/Volo.Docs.Application",
"modules/docs/src/Volo.Docs.Application.Contracts",
"modules/docs/src/Volo.Docs.Domain",
"modules/docs/src/Volo.Docs.Domain.Shared",
"modules/docs/src/Volo.Docs.EntityFrameworkCore",
"modules/docs/src/Volo.Docs.HttpApi",
"modules/docs/src/Volo.Docs.HttpApi.Client",
"modules/docs/src/Volo.Docs.Web",
# modules/blogging
"modules/blogging/src/Volo.Blogging.Application",
"modules/blogging/src/Volo.Blogging.Application.Contracts",
"modules/blogging/src/Volo.Blogging.Domain",
"modules/blogging/src/Volo.Blogging.Domain.Shared",
"modules/blogging/src/Volo.Blogging.EntityFrameworkCore",
"modules/blogging/src/Volo.Blogging.MongoDB",
"modules/blogging/src/Volo.Blogging.HttpApi",
"modules/blogging/src/Volo.Blogging.HttpApi.Client",
"modules/blogging/src/Volo.Blogging.Web",
# modules/audit-logging
"modules/audit-logging/src/Volo.Abp.AuditLogging.Domain.Shared",
"modules/audit-logging/src/Volo.Abp.AuditLogging.Domain",
"modules/audit-logging/src/Volo.Abp.AuditLogging.EntityFrameworkCore",
"modules/audit-logging/src/Volo.Abp.AuditLogging.MongoDB",
# modules/background-jobs
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain.Shared",
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.Domain",
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.EntityFrameworkCore",
"modules/background-jobs/src/Volo.Abp.BackgroundJobs.MongoDB",
# modules/client-simulation
"modules/client-simulation/src/Volo.ClientSimulation",
"modules/client-simulation/src/Volo.ClientSimulation.Web"
# modules/permission-management
"modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Application",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Domain",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared",
"modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore",
"modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi.Client",
"modules/permission-management/src/Volo.Abp.PermissionManagement.HttpApi",
"modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB",
"modules/permission-management/src/Volo.Abp.PermissionManagement.Web",
# modules/setting-management
"modules/setting-management/src/Volo.Abp.SettingManagement.Domain",
"modules/setting-management/src/Volo.Abp.SettingManagement.Domain.Shared",
"modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore",
"modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB",
"modules/setting-management/src/Volo.Abp.SettingManagement.Web",
# modules/tenant-management
"modules/tenant-management/src/Volo.Abp.TenantManagement.Application.Contracts",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Application",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Domain",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Domain.Shared",
"modules/tenant-management/src/Volo.Abp.TenantManagement.EntityFrameworkCore",
"modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi.Client",
"modules/tenant-management/src/Volo.Abp.TenantManagement.HttpApi",
"modules/tenant-management/src/Volo.Abp.TenantManagement.MongoDB",
"modules/tenant-management/src/Volo.Abp.TenantManagement.Web",
# modules/users
"modules/users/src/Volo.Abp.Users.Abstractions",
"modules/users/src/Volo.Abp.Users.Domain",
"modules/users/src/Volo.Abp.Users.Domain.Shared",
"modules/users/src/Volo.Abp.Users.EntityFrameworkCore",
"modules/users/src/Volo.Abp.Users.MongoDB"
)

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
namespace DashboardDemo
{
public class DemoStatisticAppService : ApplicationService, IDemoStatisticAppService
{
public async Task<GetMonthlyUserStatisticDto> GetMonthlyUserStatistic(FilterDto filter)
{
var monthCount = GetLabels(filter, out var monthList);
var data = Enumerable
.Repeat(0, monthCount)
.Select(i => new Random().Next(750, 960))
.ToArray();
return new GetMonthlyUserStatisticDto{Labels = monthList.ToArray(), Data = data};
}
public async Task<MonthlyProfitStatisticDto> GetMonthlyProfitStatistic(FilterDto filter)
{
var monthCount = GetLabels(filter, out var monthList);
var data = Enumerable
.Repeat(0, monthCount)
.Select(i => new Random().Next(-20, 40))
.ToArray();
return new MonthlyProfitStatisticDto { Labels = monthList.ToArray(), Data = data };
}
private static int GetLabels(FilterDto filter, out List<string> monthList)
{
DateTime endDate = filter.EndDate ?? DateTime.Now;
DateTime startDate = filter.StartDate ?? DateTime.Now.AddYears(-1);
if (filter.StartDate > filter.EndDate)
{
throw new BusinessException("Start date can not be greater than end date.");
}
var months = new[] {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
var monthCount = (endDate.Year - startDate.Year) * 12 + endDate.Month - startDate.Month +1;
monthList = new List<string>();
for (int i = 0; i < monthCount; i++)
{
monthList.Add(months[endDate.Month-1]);
endDate = endDate.AddMonths(-1);
}
monthList.Reverse();
return monthCount;
}
}
}

@ -0,0 +1,11 @@
using System;
namespace DashboardDemo
{
public class FilterDto
{
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
}
}

@ -0,0 +1,9 @@
namespace DashboardDemo
{
public class GetMonthlyUserStatisticDto
{
public string[] Labels { get; set; }
public int[] Data { get; set; }
}
}

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace DashboardDemo
{
public interface IDemoStatisticAppService : IApplicationService
{
Task<GetMonthlyUserStatisticDto> GetMonthlyUserStatistic(FilterDto filter);
Task<MonthlyProfitStatisticDto> GetMonthlyProfitStatistic(FilterDto filter);
}
}

@ -0,0 +1,9 @@
namespace DashboardDemo
{
public class MonthlyProfitStatisticDto
{
public string[] Labels { get; set; }
public int[] Data { get; set; }
}
}

@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using DashboardDemo.EntityFrameworkCore;
using DashboardDemo.GlobalFilters;
using DashboardDemo.Localization.DashboardDemo;
using DashboardDemo.Menus;
using DashboardDemo.Pages;
@ -75,6 +76,7 @@ namespace DashboardDemo
var configuration = context.Services.GetConfiguration();
ConfigureWidgets();
ConfigureGlobalFilters();
ConfigureDashboards();
ConfigureDatabaseServices();
ConfigureAutoMapper();
@ -93,6 +95,14 @@ namespace DashboardDemo
});
}
private void ConfigureGlobalFilters()
{
Configure<GlobalFilterOptions>(options =>
{
options.GlobalFilters.AddRange(GlobalFilterDefinitionProvider.GetDefinitions());
});
}
private void ConfigureDashboards()
{
Configure<DashboardOptions>(options =>
@ -106,7 +116,7 @@ namespace DashboardDemo
{
configuration.AddContributors(typeof(MyDashboardScriptBundleContributor));
});
options.ScriptBundles.Add(UserCountWidgetViewComponent.WidgetName, configuration =>
options.ScriptBundles.Add(UserCountWidgetViewComponent.Name, configuration =>
{
configuration.AddContributors(typeof(UserCountWidgetScriptBundleContributor));
});
@ -114,7 +124,7 @@ namespace DashboardDemo
{
configuration.AddContributors(typeof(MyDashboardStyleBundleContributor));
});
options.StyleBundles.Add(UserCountWidgetViewComponent.WidgetName, configuration =>
options.StyleBundles.Add(UserCountWidgetViewComponent.Name, configuration =>
{
configuration.AddContributors(typeof(UserCountWidgetStyleBundleContributor));
});

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save