pull/4371/head
Akın Sabri Çam 5 years ago
commit bc9f8f26a5

@ -1,3 +1,356 @@
## Unit of Work
# Unit of Work
ABP Framework's Unit Of Work (UOW) implementation provides an abstraction and control on a **database connection and transaction** scope in an application.
Once a new UOW started, it creates an **ambient scope** that is participated by **all the database operations** performed in the current scope and considered as a **single transaction boundary**. The operations are **committed** (on success) or **rolled back** (on exception) all together.
ABP's UOW system is;
* **Works conventional**, so most of the times you don't deal with UOW at all.
* **Database provider independent**.
* **Web independent**, that means you can create unit of work scopes in any type of applications beside web applications/services.
## Conventions
The following method types are considered as a unit of work:
* ASP.NET Core MVC **Controller Actions**.
* ASP.NET Core Razor **Page Handlers**.
* **Application service** methods.
* **Repository methods**.
A UOW automatically begins for these methods **except** if there is already a **surrounding (ambient)** UOW in action. Examples;
* If you call a [repository](Repositories.md) method and there is no UOW started yet, it automatically **begins a new transactional UOW** that involves all the operations done in the repository method and **commits the transaction** if the repository method **doesn't throw any exception.** The repository method doesn't know about UOW or transaction at all. It just works on a regular database objects (`DbContext` for [EF Core](Entity-Framework-Core.md), for example) and the UOW is handled by the ABP Framework.
* If you call an [application service](Application-Services.md) method, the same UOW system works just as explained above. If the application service method uses some repositories, the repositories **don't begin a new UOW**, but **participates to the current unit of work** started by the ABP Framework for the application service method.
* The same is true for an ASP.NET Core controller action. If the operation has started with a controller action, then the **UOW scope is the controller action's method body**.
All of these are automatically handled by the ABP Framework.
### Database Transaction Behavior
While the section above explains the UOW as it is database transaction, actually a UOW doesn't have to be transactional. By default;
* **HTTP GET** requests don't start a transactional UOW. They still starts a UOW, but **doesn't create a database transaction**.
* All other HTTP request types start a UOW with a database transaction, if database level transactions are supported by the underlying database provider.
This is because an HTTP GET request doesn't (and shouldn't) make any change in the database. You can change this behavior using the options explained below.
## Default Options
`AbpUnitOfWorkDefaultOptions` is used to configure the default options for the unit of work system. Configure the options in the `ConfigureServices` method of your [module](Module-Development-Basics.md).
**Example: Completely disable the database transactions**
````csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
});
````
### Option Properties
* `TransactionBehavior` (`enum`: `UnitOfWorkTransactionBehavior`). A global point to configure the transaction behavior. Default value is `Auto` and work as explained in the "*Database Transaction Behavior*" section above. You can enable (even for HTTP GET requests) or disable transactions with this option.
* `TimeOut` (`int?`): Used to set the timeout value for UOWs. **Default value is `null`** and uses to the default of the underlying database provider.
* `IsolationLevel` (`IsolationLevel?`): Used to set the [isolation level](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel) of the database transaction, if the UOW is transactional.
## Controlling the Unit Of Work
In some cases, you may want to change the conventional transaction scope, create inner scopes or fine control the transaction behavior. The following sections cover these possibilities.
### IUnitOfWorkEnabled Interface
This is an easy way to enable UOW for a class (or a hierarchy of classes) that is not unit of work by the conventions explained above.
**Example: Implement `IUnitOfWorkEnabled` for an arbitrary service**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency, IUnitOfWorkEnabled
{
public virtual async Task FooAsync()
{
//this is a method with a UOW scope
}
}
}
````
Then `MyService` (and any class derived from it) methods will be UOW.
However, there are **some rules should be followed** in order to make it working;
* If you are **not injecting** the service over an interface (like `IMyService`), then the methods of the service must be `virtual` (otherwise, [dynamic proxy / interception](Dynamic-Proxying-Interceptors.md) system can not work).
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted. So, sync methods can not start a UOW.
> Notice that if `FooAsync` is called inside a UOW scope, then it already participates to the UOW without needing to the `IUnitOfWorkEnabled` or any other configuration.
### UnitOfWorkAttribute
`UnitOfWork` attribute provides much more possibility like enabling or disabling UOW and controlling the transaction behavior.
`UnitOfWork` attribute can be used for a **class** or a **method** level.
**Example: Enable UOW for a specific method of a class**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency
{
[UnitOfWork]
public virtual async Task FooAsync()
{
//this is a method with a UOW scope
}
public virtual async Task BarAsync()
{
//this is a method without UOW
}
}
}
````
**Example: Enable UOW for all the methods of a class**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
[UnitOfWork]
public class MyService : ITransientDependency
{
public virtual async Task FooAsync()
{
//this is a method with a UOW scope
}
public virtual async Task BarAsync()
{
//this is a method with a UOW scope
}
}
}
````
Again, the **same rules** are valid here:
* If you are **not injecting** the service over an interface (like `IMyService`), then the methods of the service must be `virtual` (otherwise, [dynamic proxy / interception](Dynamic-Proxying-Interceptors.md) system can not work).
* Only `async` methods (methods returning a `Task` or `Task<T>`) are intercepted. So, sync methods can not start a UOW.
#### UnitOfWorkAttribute Properties
* `IsTransactional` (`bool?`): Used to set whether the UOW should be transactional or not. **Default value is `null`**. if you leave it `null`, it is determined automatically based on the conventions and the configuration.
* `TimeOut` (`int?`): Used to set the timeout value for this UOW. **Default value is `null`** and fallbacks to the default configured value.
* `IsolationLevel` (`IsolationLevel?`): Used to set the [isolation level](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel) of the database transaction, if the UOW is transactional. If not set, uses the default configured value.
* `IsDisabled` (`bool`): Used to disable the UOW for the current method/class.
> If a method is called in an ambient UOW scope, then the `UnitOfWork` attribute is ignored and the method participates to the surrounding transaction in any way.
**Example: Disable UOW for a controller action**
````csharp
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Uow;
namespace AbpDemo.Web
{
public class MyController : AbpController
{
[UnitOfWork(IsDisabled = true)]
public virtual async Task FooAsync()
{
//...
}
}
}
````
## IUnitOfWorkManager
`IUnitOfWorkManager` is the main service that is used to control the unit of work system. The following sections explains how to directly work with this service (while most of the times you won't need).
### Begin a New Unit Of Work
`IUnitOfWorkManager.Begin` method is used to create a new UOW scope.
**Example: Create a new non-transactional UOW scope**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
public MyService(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public virtual async Task FooAsync()
{
using (var uow = _unitOfWorkManager.Begin(
requiresNew: true, isTransactional: false
))
{
//...
await uow.CompleteAsync();
}
}
}
}
````
`Begin` method gets the following optional parameters:
* `requiresNew` (`bool`): Set `true` to ignore the surrounding unit of work and start a new UOW with the provided options. **Default value is `false`. If it is `false` and there is a surrounding UOW, `Begin` method doesn't actually begin a new UOW, but silently participates to the existing UOW.**
* `isTransactional` (`bool`). Default value is `false`.
* `isolationLevel` (`IsolationLevel?`): Used to set the [isolation level](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel) of the database transaction, if the UOW is transactional. If not set, uses the default configured value.
* `TimeOut` (`int?`): Used to set the timeout value for this UOW. **Default value is `null`** and fallbacks to the default configured value.
### The Current Unit Of Work
UOW is ambient, as explained before. If you need to access to the current unit of work, you can use the `IUnitOfWorkManager.Current` property.
**Example: Get the current UOW**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyProductService : ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
public MyProductService(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public async Task FooAsync()
{
var uow = _unitOfWorkManager.Current;
//...
}
}
}
````
`Current` property returns a `IUnitOfWork` object.
> **Current Unit Of Work can be `null`** if there is no surrounding unit of work. It won't be `null` if your class is a conventional UOW class, you manually made it UOW or it was called inside a UOW scope, as explained before.
#### SaveChangesAsync
`IUnitOfWork.SaveChangesAsync()` method can be needed to save all the changes until now to the database. If you are using EF Core, it behaves exactly same. If the current UOW is transactional, even saved changes can be rolled back on an error (for the supporting database providers).
**Example: Save changes after inserting an entity to get its auto-increment id**
````csharp
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace AbpDemo
{
public class CategoryAppService : ApplicationService, ICategoryAppService
{
private readonly IRepository<Category, int> _categoryRepository;
public CategoryAppService(IRepository<Category, int> categoryRepository)
{
_categoryRepository = categoryRepository;
}
public async Task<int> CreateAsync(string name)
{
var category = new Category {Name = name};
await _categoryRepository.InsertAsync(category);
//Saving changes to be able to get the auto increment id
await UnitOfWorkManager.Current.SaveChangesAsync();
return category.Id;
}
}
}
````
This example uses auto-increment `int` primary key for the `Category` [entity](Entities.md). Auto-increment PKs require to save the entity to the database to get the id of the new entity.
This example is an [application service](Application-Services.md) derived from the base `ApplicationService` class, which already has the `IUnitOfWorkManager` service injected as the `UnitOfWorkManager` property. So, no need to inject it manually.
Since getting the current UOW is pretty common, there is also a `CurrentUnitOfWork` property as a shortcut to the `UnitOfWorkManager.Current`. So, the example above can be changed to use it:
````csharp
await CurrentUnitOfWork.SaveChangesAsync();
````
##### Alternative to the SaveChanges()
Since saving changes after inserting, updating or deleting an entity can be frequently needed, corresponding [repository](Repositories.md) methods has an optional `autoSave` parameter. So, the `CreateAsync` method above could be re-written as shown below:
````csharp
public async Task<int> CreateAsync(string name)
{
var category = new Category {Name = name};
await _categoryRepository.InsertAsync(category, autoSave: true);
return category.Id;
}
````
If your intent is just to save the changes after creating/updating/deleting an entity, it is suggested to use the `autoSave` option instead of manually using the `CurrentUnitOfWork.SaveChangesAsync()`.
> **Note-1**: All changes are automatically saved when a unit of work ends without any error. So, don't call `SaveChangesAsync()` unless you really need it.
>
> **Note-2**: If you use `Guid` as the primary key, you never need to save changes on insert to just get the generated id, because `Guid` keys are set in the application and are immediately available once you create a new entity.
#### Other IUnitOfWork Properties/Methods
* `OnCompleted` method gets a callback action which is called when the unit of work successfully completed (where you can be sure that all changes are saved).
* `Failed` and `Disposed` events can be used to be notified if the UOW fails or when it is disposed.
* `Complete` and `Rollback` methods are used to complete (commit) or roll backs the current UOW, which are normally used internally by the ABP Framework but can be used if you manually start a transaction using the `IUnitOfWorkManager.Begin` method.
* `Options` can be used to get options that was used while starting the UOW.
* `Items` dictionary can be used to store and get arbitrary objects inside the same unit of work, which can be a point to implement custom logics.
## ASP.NET Core Integration
Unit of work system is fully integrated to the ASP.NET Core. It properly works when you use ASP.NET Core MVC Controllers or Razor Pages. It defines action filters and page filters for the UOW system.
> You typically do nothing to configure the UOW when you use ASP.NET Core.
### Unit Of Work Middleware
`AbpUnitOfWorkMiddleware` is a middleware that can enable UOW in the ASP.NET Core request pipeline. This might be needed if you need to enlarge the UOW scope to cover some other middleware(s).
**Example:**
````csharp
app.UseUnitOfWork();
app.UseConfiguredEndpoints();
````
TODO

@ -285,7 +285,8 @@
"path": "Data-Transfer-Objects.md"
},
{
"text": "Unit Of Work"
"text": "Unit Of Work",
"path": "Unit-Of-Work.md"
}
]
}

@ -1,3 +1,355 @@
## Unit of Work
# 工作单元
待添加
ABP框架的工作单元(UOW)实现提供了对应用程序中的**数据库连接和事务范围**的抽象和控制.
一旦一个新的UOW启动,它将创建一个**环境作用域**,当前作用域中执行的**所有数据库操作**都将参与该作用域并将其视为单个事务边界. 操作一起**提交**(成功时)或**回滚**(异常时).
ABP的UOW系统是;
* **按约定工作**, 所以大部分情况下你不需要处理UOW.
* **数据库提供者独立**.
* **Web独立**, 这意味着你可以在Web应用程序/服务之外的任何类型的应用程序中创建工作单元作用域.
## 约定
以下方法类型被认为是一个工作单元:
* ASP.NET Core MVC **Controller Actions**.
* ASP.NET Core Razor **Page Handlers**.
* **应用程序** 方法.
* **仓储方法**.
UOW自动针对这些方法开始,除非**周围已经有一个(环境)**UOW在运行.示例;
* 如果你调用一个[仓储]方法(Repositories.md),但还没有启动UOW,它将自动**启动一个新的事务UOW**,其中包括在仓储方法中完成的所有操作,如果仓储方法没有抛出任何异常,则**提交事务**. 仓储方法根本不知道UOW或事务. 它只在一个常规的数据库对象上工作(例如用于[EF Core](Entity-Framework-Core.md)的`DbContext`),而UOW由ABP框架处理.
* 如果调用[应用服务](Application-Services.md)方法,则相同的UOW系统将按上述说明工作. 如果应用服务方法使用某些仓储,这些仓储**不会开始新的UOW**,而是**参与由ABP框架为应用程序服务方法启动的当前工作单元中**.
* ASP.NET Core控制器操作也是如此. 如果操作以控制器action开始,**UOW范围是控制器action的方法主体**.
所有这些都是由ABP框架自动处理的.
### 数据库事务行为
虽然上一节解释了UOW是数据库事务,但实际上UOW不必是事务性的. 默认情况下;
* **HTTP GET**请求不会启动事务性UOW. 它们仍然启动UOW,但**不创建数据库事务**.
* 如果底层数据库提供程序支持数据库事务,那么所有其他HTTP请求类型都使用数据库事务启动UOW.
这是因为HTTP GET请求不会(也不应该)在数据库中进行任何更改. 你可以使用下面解释的选项来更改此行为.
## 默认选项
`AbpUnitOfWorkDefaultOptions` 用于配置工作单元系统的默认选项.在你的[模块](Module-Development-Basics.md)的 `ConfigureServices` 方法中配置选项.
**示例: 完全禁用数据库事务**
````csharp
Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled;
});
````
### 选项属性
* `TransactionBehavior` (`enum`: `UnitOfWorkTransactionBehavior`). 配置事务行为的全局点. 默认值为 `Auto` ,按照上面"*数据库事务行为"*一节的说明工作. 你可以使用此选项启用(甚至对于HTTP GET请求)或禁用事务.
* `TimeOut` (`int?`): 用于设置UOW的超时值. **默认值是 `null`** 并使用基础数据库提供程序的默认值.
* `IsolationLevel` (`IsolationLevel?`): 如果UOW是事务性的用于设置数据库事务的[隔离级别](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel).
## 控制工作单元
在某些情况下你可能希望更改常规事务作用域,创建内部作用域或精细控制事务行为. 下面几节将介绍这些可能性.
### IUnitOfWorkEnabled 接口
这是为不是按照上面解释的约定作为工作单元的类(或类的层次结构)启用UOW的一种简单方法.
**示例: 为任意服务实现 `IUnitOfWorkEnabled`**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency, IUnitOfWorkEnabled
{
public virtual async Task FooAsync()
{
//this is a method with a UOW scope
}
}
}
````
然后 `MyService`(和它的派生类)方法都将是UOW.
但是为了使它工作,**有些规则应该被遵守**;
* 如果你不是通过接口(如`IMyService`)注入服务,则服务的方法必须是 `virtual` 的(否则[动态代理/拦截](Dynamic-Proxying-Interceptors.md)系统将无法工作).
* 仅异步方法(返回`Task`或`Task<T>`的方法)被拦截. 因此同步方法无法启动UOW.
> 注意,如果 `FooAsync` 在UOW作用域内被调用,那么它已经参与了UOW,不需要 `IUnitOfWorkEnabled` 或其他配置.
### UnitOfWorkAttribute
`UnitOfWork` attribute提供了更多的可能性,比如启用或禁用UOW和控制事务行为.
`UnitOfWork` attribute可以用于**类**或**方法**级别.
**示例: 为类的特定方法启用UOW**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency
{
[UnitOfWork]
public virtual async Task FooAsync()
{
//this is a method with a UOW scope
}
public virtual async Task BarAsync()
{
//this is a method without UOW
}
}
}
````
**示例: 为类的所有方法启用UOW**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
[UnitOfWork]
public class MyService : ITransientDependency
{
public virtual async Task FooAsync()
{
//this is a method with a UOW scope
}
public virtual async Task BarAsync()
{
//this is a method with a UOW scope
}
}
}
````
**同样的规则**也适用于此:
* 如果你不是通过接口(如`IMyService`)注入服务,则服务的方法必须是 `virtual` 的(否则[动态代理/拦截](Dynamic-Proxying-Interceptors.md)系统将无法工作).
* 仅异步方法(返回`Task`或`Task<T>`的方法)被拦截. 因此同步方法无法启动UOW.
#### UnitOfWorkAttribute 属性
* `IsTransactional` (`bool?`): 用于设置UOW是否是事务性的. **默认值为 `null`**. 如果你让它为 `null`,它会通过约定和配置自动确定.
* `TimeOut` (`int?`): 用于设置UOW的超时值. **默认值为 `null`**并回退到默认配置值.
* `IsolationLevel` (`IsolationLevel?`): 如果UOW是事务的,用于设置数据库事务的[隔离级别](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel). 如果未设置,则使用默认值.
* `IsDisabled` (`bool`): 用于禁用当前方法/类的UOW.
> 如果在环境UOW作用域内调用方法,将忽略 `UnitOfWork` 属性,并且该方法参与周围的事务.
**示例: 为控制器action禁用UOW**
````csharp
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Uow;
namespace AbpDemo.Web
{
public class MyController : AbpController
{
[UnitOfWork(IsDisabled = true)]
public virtual async Task FooAsync()
{
//...
}
}
}
````
## IUnitOfWorkManager
`IUnitOfWorkManager` 是用于控制工作单元系统的主要服务. 下面的部分解释了如何使用此服务(大多数时候你并不需要).
### 开始新的工作单元
`IUnitOfWorkManager.Begin` 方法用于创建一个新的UOW作用域.
**示例: 创建一个新的非事务性UOW作用域**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyService : ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
public MyService(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public virtual async Task FooAsync()
{
using (var uow = _unitOfWorkManager.Begin(
requiresNew: true, isTransactional: false
))
{
//...
await uow.CompleteAsync();
}
}
}
}
````
`Begin` 方法有以下可选参数:
* `requiresNew` (`bool`): 设置为 `true` 可忽略周围的工作单元,并使用提供的选项启动新的UOW. **默认值为`false`. 如果为`false`,并且周围有UOW,则 `Begin` 方法实际上不会开始新的UOW,而是以静默方式参与现有的UOW**.
* `isTransactional` (`bool`). 默认为 `false`.
* `isolationLevel` (`IsolationLevel?`): 如果UOW是事务的,用于设置数据库事务的[隔离级别](https://docs.microsoft.com/en-us/dotnet/api/system.data.isolationlevel). 如果未设置,则使用默认值.
* `TimeOut` (`int?`): 用于设置UOW的超时值. **默认值为 `null`**并回退到默认配置值.
### 当前工作单元
如上所述UOW是环境的. 如果需要访问当前的工作单元,可以使用 `IUnitOfWorkManager.Current` 属性.
**示例: 获取当前UOW**
````csharp
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace AbpDemo
{
public class MyProductService : ITransientDependency
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
public MyProductService(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public async Task FooAsync()
{
var uow = _unitOfWorkManager.Current;
//...
}
}
}
````
`Current` 属性返回一个 `IUnitOfWork` 对象.
> 如果没有周围的工作单元,则**当前工作单元可以为`null`**. 如上所述,如果你的类是常规的UOW类,你将其手动设置为UOW或在UOW作用域内调用它,那么该值就不会为 `null`.
#### SaveChangesAsync
`IUnitOfWork.SaveChangesAsync()` 方法将到目前为止的所有更改保存到数据库中. 如果你正在使用EF Core,它的行为完全相同. 如果当前UOW是事务性的,即使已保存的更改也可以在错误时回滚(对于支持的数据库提供程序).
**示例: 插入实体后保存更改以获取其自动增量ID**
````csharp
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace AbpDemo
{
public class CategoryAppService : ApplicationService, ICategoryAppService
{
private readonly IRepository<Category, int> _categoryRepository;
public CategoryAppService(IRepository<Category, int> categoryRepository)
{
_categoryRepository = categoryRepository;
}
public async Task<int> CreateAsync(string name)
{
var category = new Category {Name = name};
await _categoryRepository.InsertAsync(category);
//Saving changes to be able to get the auto increment id
await UnitOfWorkManager.Current.SaveChangesAsync();
return category.Id;
}
}
}
````
示例的 `Category` [实体](Entities.md)使用自动递增的 `int` 主键. 自动增量PK需要将实体保存到数据库中来获得新实体的ID.
示例是从基类 `ApplicationService` 派生的[应用服务](Application-Services.md), `IUnitOfWorkManager` 服务已经作为 `UnitOfWorkManager` 属性注入,所以无需手动注入.
获取当前UOW非常常见,所以还有一个 `UnitOfWorkManager.Current` 的快捷属性 `CurrentUnitOfWork`. 所以可以对上面的例子进行以下更改:
````csharp
await CurrentUnitOfWork.SaveChangesAsync();
````
##### SaveChanges() 的替代方法
由于经常需要在插入,更新或删除实体后保存更改,相应的[仓储](Repositories.md)方法有一个可选的 `autoSave` 参数. 可以将上面的 `CreateAsync` 方法按如下重写:
````csharp
public async Task<int> CreateAsync(string name)
{
var category = new Category {Name = name};
await _categoryRepository.InsertAsync(category, autoSave: true);
return category.Id;
}
````
如果你的目的只是在创建/更新/删除实体后保存更改,建议你使用 `autoSave` 选项,而不是手动使用 `CurrentUnitOfWork.SaveChangesAsync()`.
> **Note-1**: 当工作单元结束而没有任何错误时,所有更改都会自动保存. 所以除非确实需要,否则不要调用 `SaveChangesAsync()`.
>
> **Note-2**: 如果你使用 `Guid` 作为主键,则无需插入时保存来获取生成的id,因为 `Guid` 主键是在应用程序中设置的,创建新实体后立即可用.
#### IUnitOfWork 其他属性/方法
* `OnCompleted` 方法获得一个回调动作,当工作单元成功完成时调用(在这里你可以确保所有更改都保存了).
* `Failed``Disposed` 事件可以用于UOW失败和被销毁的通知.
* `Complete``Rollback` 方法用于完成(提交)或回滚当前 UOW, 通常ABP框架在内部使用,如果你使用 `IUnitOfWorkManager.Begin` 方法手动启动事务,那么你可以手动使用这些方法.
* `Options` 可用于获取启动UOW时使用的选项.
* `Items` 字典可用于在同一工作单元内存储和获取任意对象,可以实现自定义逻辑.
## ASP.NET Core 集成
工作单元系统已完全集成到ASP.NET Core. 它为UOW系统定义了动作过滤器和页面过滤器. 当你使用ASP.NET Core MVC控制器或Razor页面时,它可以正常工作.
> 使用ASP.NET Core时,通常你不需要做任何操作配置UOW.
### 工作单元中间件
`AbpUnitOfWorkMiddleware` 是可以在ASP.NET Core请求管道中启用UOW的中间件. 如果你需要扩大UOW范围以涵盖其他一些中间件,可以这样做.
**示例:**
````csharp
app.UseUnitOfWork();
app.UseConfiguredEndpoints();
````

@ -287,7 +287,8 @@
"path": "Data-Transfer-Objects.md"
},
{
"text": "工作单元"
"text": "工作单元",
"path": "Unit-Of-Work.md"
}
]
}

@ -16,10 +16,14 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
public string DefaultResourceName { get; set; }
public Dictionary<string, List<NameValue>> LanguagesMap { get; set; }
public Dictionary<string, List<NameValue>> LanguageFilesMap { get; set; }
public ApplicationLocalizationConfigurationDto()
{
Values = new Dictionary<string, Dictionary<string, string>>();
Languages = new List<LanguageInfo>();
}
}
}
}

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Volo.Abp.Localization;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{
@ -8,8 +11,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{
public List<string> Files { get; }
public IServiceProvider ServiceProvider { get; }
public IFileProvider FileProvider { get; }
public BundleConfigurationContext(IServiceProvider serviceProvider, IFileProvider fileProvider)
@ -18,5 +19,29 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
ServiceProvider = serviceProvider;
FileProvider = fileProvider;
}
public IServiceProvider ServiceProvider { get; }
private readonly object _serviceProviderLock = new object();
private TRef LazyGetRequiredService<TRef>(Type serviceType, ref TRef reference)
{
if (reference == null)
{
lock (_serviceProviderLock)
{
if (reference == null)
{
reference = (TRef)ServiceProvider.GetRequiredService(serviceType);
}
}
}
return reference;
}
private IOptions<AbpLocalizationOptions> _abpLocalizationOptions;
public AbpLocalizationOptions LocalizationOptions =>
LazyGetRequiredService(typeof(IOptions<AbpLocalizationOptions>), ref _abpLocalizationOptions).Value;
}
}
}

@ -1,4 +1,6 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages
@ -6,6 +8,18 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))]
public class AbpAspNetCoreMvcUiPackagesModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.AddLanguagesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName,
new NameValue("zh-Hans", "zh-CN"),
new NameValue("zh-Hant", "zh-TW"));
options.AddLanguageFilesMapOrUpdate(BootstrapDatepickerScriptContributor.PackageName,
new NameValue("zh-Hans", "zh-CN"),
new NameValue("zh-Hant", "zh-TW"));
});
}
}
}

@ -1,7 +1,8 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker
@ -9,11 +10,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker
[DependsOn(typeof(JQueryScriptContributor))]
public class BootstrapDatepickerScriptContributor : BundleContributor
{
public static readonly Dictionary<string, string> CultureMap = new Dictionary<string, string>
{
{"zh-Hans", "zh-CN"}
};
public const string PackageName = "bootstrap-datepicker";
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/bootstrap-datepicker/bootstrap-datepicker.min.js");
@ -26,12 +24,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker
? "en"
: CultureInfo.CurrentUICulture.Name;
TryAddCultureFile(context, MapCultureName(cultureName));
TryAddCultureFile(context, cultureName);
}
protected virtual bool TryAddCultureFile(BundleConfigurationContext context, string cultureName)
{
var filePath = $"/libs/bootstrap-datepicker/locales/bootstrap-datepicker.{cultureName}.min.js";
var fileName = context.LocalizationOptions.GetLanguageFilesMap(PackageName, cultureName);
var filePath = $"/libs/bootstrap-datepicker/locales/bootstrap-datepicker.{fileName}.min.js";
if (!context.FileProvider.GetFileInfo(filePath).Exists)
{
@ -41,11 +40,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.BootstrapDatepicker
context.Files.AddIfNotContains(filePath);
return true;
}
protected virtual string MapCultureName(string cultureName)
{
return CultureMap.GetOrDefault(cultureName) ??
cultureName;
}
}
}

@ -2,6 +2,7 @@
using System.Globalization;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Packages.JQuery;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
@ -11,6 +12,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
{
public const string DefaultLocalizationFolder = "/libs/jquery-validation/localization/";
public const string PackageName = "jquery-validation";
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/jquery-validation/jquery.validate.js");
@ -25,7 +28,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
var cultureName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName.Replace('-', '_');
if (TryAddCultureFile(context, MapCultureName(cultureName)))
var fileName = context.LocalizationOptions.GetLanguageFilesMap(PackageName, cultureName);
if (TryAddCultureFile(context, fileName))
{
return;
}
@ -35,7 +39,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
return;
}
TryAddCultureFile(context, MapCultureName(cultureName.Substring(0, cultureName.IndexOf('_'))));
fileName = context.LocalizationOptions.GetLanguageFilesMap(PackageName,
cultureName.Substring(0, cultureName.IndexOf('_')));
TryAddCultureFile(context, fileName);
}
protected virtual bool TryAddCultureFile(BundleConfigurationContext context, string cultureName)
@ -51,10 +57,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.JQueryValidation
context.Files.AddIfNotContains(filePath);
return true;
}
protected virtual string MapCultureName(string cultureName)
{
return cultureName;
}
}
}

@ -12,7 +12,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Select2
{
//TODO: Add select2.full.min.js or localize!
context.Files.AddIfNotContains("/libs/select2/js/select2.min.js");
context.Files.AddIfNotContains("/libs/select2/js/select2-bootstrap-modal-patch.js");
}
}
}

@ -1,4 +1,4 @@
(function ($) {
(function ($) {
abp.dom = abp.dom || {};
@ -73,25 +73,12 @@
abp.libs = abp.libs = abp.libs || {};
abp.libs.bootstrapDatepicker = {
languageMap: {
'zh-Hans': 'zh-CN'
},
mapLanguageName: function (name) {
return abp.libs.bootstrapDatepicker.languageMap[abp.localization.currentCulture.name] || name;
},
isLanguageMapped: function (name) {
return abp.libs.bootstrapDatepicker.languageMap[abp.localization.currentCulture.name] !== undefined;
},
getCurrentLanguageConfig: function () {
var mappedName = abp.libs.bootstrapDatepicker.mapLanguageName(abp.localization.currentCulture.name);
return $.fn.datepicker.dates[mappedName];
},
packageName: "bootstrap-datepicker",
normalizeLanguageConfig: function () {
var languageConfig = abp.libs.bootstrapDatepicker.getCurrentLanguageConfig();
if (languageConfig) {
if (!languageConfig.format || abp.libs.bootstrapDatepicker.isLanguageMapped(abp.localization.currentCulture.name)) {
languageConfig.format = abp.localization.currentCulture.dateTimeFormat.shortDatePattern.toLowerCase();
}
var language = abp.localization.getLanguagesMap(this.packageName);
var languageConfig = $.fn.datepicker.dates[language];
if (languageConfig && (!languageConfig.format || language !== abp.localization.currentCulture.name)) {
languageConfig.format = abp.localization.currentCulture.dateTimeFormat.shortDatePattern.toLowerCase();
}
},
getFormattedValue: function (isoFormattedValue) {
@ -108,7 +95,7 @@
return {
todayBtn: "linked",
autoclose: true,
language: abp.libs.bootstrapDatepicker.mapLanguageName(abp.localization.currentCulture.cultureName)
language: abp.localization.getLanguagesMap(this.packageName)
};
}
};
@ -132,7 +119,6 @@
abp.dom.initializers.initializeToolTips(args.$el.findWithSelf('[data-toggle="tooltip"]'));
abp.dom.initializers.initializePopovers(args.$el.findWithSelf('[data-toggle="popover"]'));
abp.dom.initializers.initializeTimeAgos(args.$el.findWithSelf('.timeago'));
abp.dom.initializers.initializeDatepickers(args.$el);
abp.dom.initializers.initializeForms(args.$el.findWithSelf('form'), true);
abp.dom.initializers.initializeScript(args.$el);
});
@ -156,4 +142,4 @@
$('[data-auto-focus="true"]').first().findWithSelf('input,select').focus();
});
})(jQuery);
})(jQuery);

@ -171,6 +171,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
);
}
localizationConfig.LanguagesMap = _localizationOptions.LanguagesMap;
localizationConfig.LanguageFilesMap = _localizationOptions.LanguageFilesMap;
return localizationConfig;
}
@ -267,4 +270,4 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
};
}
}
}
}

@ -47,6 +47,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
if (context.BuildArgs.DatabaseProvider != DatabaseProvider.MongoDb)
{
steps.Add(new AppTemplateRemoveMongodbCollectionFixtureStep());
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.MongoDB"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.MongoDB.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.MongoDB.Tests"));
}
@ -167,4 +168,4 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
}
}
}
}
}

@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Building;
namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
public class AppTemplateRemoveMongodbCollectionFixtureStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
//MyCompanyName.MyProjectName.Application.Tests
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.Application.Tests/MyProjectNameApplicationCollection.cs");
RemoveKeyword(context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Application.Tests/Samples/SampleAppServiceTests.cs",
"[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]");
//MyCompanyName.MyProjectName.Domain.Tests
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.Domain.Tests/MyProjectNameDomainCollection.cs");
RemoveKeyword(context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Domain.Tests/Samples/SampleDomainTests.cs",
"[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]");
//MyCompanyName.MyProjectName.EntityFrameworkCore.Tests
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreCollection.cs");
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreCollectionFixtureBase.cs");
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/MyProjectNameEntityFrameworkCoreFixture.cs");
RemoveKeyword(context,
"/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests/EntityFrameworkCore/Samples/SampleRepositoryTests.cs",
"[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]");
//MyCompanyName.MyProjectName.Web.Tests
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebCollection.cs");
RemoveKeyword(context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/Pages/Index_Tests.cs",
"[Collection(MyProjectNameTestConsts.CollectionDefinitionName)]");
//MyCompanyName.MyProjectName.TestBase
RemoveFile(context, "/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/MyProjectNameTestConsts.cs");
}
private static void RemoveFile(ProjectBuildContext context, string targetModuleFilePath)
{
var file = context.Files.FirstOrDefault(x => x.Name == targetModuleFilePath);
if (file != null)
{
context.Files.Remove(file);
}
}
private static void RemoveKeyword(ProjectBuildContext context, string targetModuleFilePath, string keyword)
{
var file = context.GetFile(targetModuleFilePath);
file.NormalizeLineEndings();
var lines = file.GetLines();
var newLines = new List<string>();
for (var i = 0; i < lines.Length; i++)
{
if (!lines[i].Contains(keyword))
{
newLines.Add(lines[i]);
}
}
file.SetLines(newLines);
}
}
}

@ -16,7 +16,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MongoDB"
);
ChangeModuleDependency(
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
@ -39,7 +39,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MongoDB"
);
ChangeModuleDependency(
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/src/MyCompanyName.MyProjectName.IdentityServer/MyProjectNameIdentityServerModule.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
@ -62,7 +62,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MongoDB"
);
ChangeModuleDependency(
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
@ -85,7 +85,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MongoDB"
);
ChangeModuleDependency(
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
@ -108,7 +108,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MongoDB"
);
ChangeModuleDependency(
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/src/MyCompanyName.MyProjectName.DbMigrator/MyProjectNameDbMigratorModule.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
@ -131,7 +131,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MongoDB.Tests"
);
ChangeModuleDependency(
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Domain.Tests/MyProjectNameDomainTestModule.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
@ -139,6 +139,37 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
"MyProjectNameEntityFrameworkCoreTestModule",
"MyProjectNameMongoDbTestModule"
);
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Domain.Tests/MyProjectNameDomainCollection.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
"MyCompanyName.MyProjectName.MongoDB",
"MyProjectNameEntityFrameworkCoreCollectionFixtureBase",
"MyProjectNameMongoDbCollectionFixtureBase"
);
//MyCompanyName.MyProjectName.Application.Tests
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Application.Tests/MyProjectNameApplicationCollection.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
"MyCompanyName.MyProjectName.MongoDB",
"MyProjectNameEntityFrameworkCoreCollectionFixtureBase",
"MyProjectNameMongoDbCollectionFixtureBase"
);
//MyCompanyName.MyProjectName.Web.Tests
ChangeNamespaceAndKeyword(
context,
"/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests/MyProjectNameWebCollection.cs",
"MyCompanyName.MyProjectName.EntityFrameworkCore",
"MyCompanyName.MyProjectName.MongoDB",
"MyProjectNameEntityFrameworkCoreCollectionFixtureBase",
"MyProjectNameMongoDbCollectionFixtureBase"
);
}
private void ChangeProjectReference(
@ -165,13 +196,13 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
throw new ApplicationException($"Could not find the '{oldReference}' reference in the project '{targetProjectFilePath}'!");
}
private void ChangeModuleDependency(
private void ChangeNamespaceAndKeyword(
ProjectBuildContext context,
string targetModuleFilePath,
string oldNamespace,
string newNamespace,
string oldModuleName,
string newModuleName)
string oldKeyword,
string newKeyword)
{
var file = context.GetFile(targetModuleFilePath);
@ -185,9 +216,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
lines[i] = $"using {newNamespace};";
}
else if (lines[i].Contains(oldModuleName))
else if (lines[i].Contains(oldKeyword))
{
lines[i] = lines[i].Replace(oldModuleName, newModuleName);
lines[i] = lines[i].Replace(oldKeyword, newKeyword);
}
}
@ -216,4 +247,4 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
throw new ApplicationException("Could not find the 'Default' connection string in appsettings.json file!");
}
}
}
}

@ -118,7 +118,7 @@ namespace Volo.Abp.EntityFrameworkCore
modelBuilder.SetDatabaseProvider(provider.Value);
}
}
protected virtual EfCoreDatabaseProvider? GetDatabaseProviderOrNull(ModelBuilder modelBuilder)
{
switch (Database.ProviderName)
@ -187,7 +187,7 @@ namespace Volo.Abp.EntityFrameworkCore
Database.IsRelational() &&
!Database.GetCommandTimeout().HasValue)
{
Database.SetCommandTimeout(initializationContext.UnitOfWork.Options.Timeout.Value.TotalSeconds.To<int>());
Database.SetCommandTimeout(TimeSpan.FromMilliseconds(initializationContext.UnitOfWork.Options.Timeout.Value));
}
ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
@ -627,4 +627,4 @@ namespace Volo.Abp.EntityFrameworkCore
}
}
}
}
}

@ -1,5 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
@ -16,19 +18,332 @@ namespace Volo.Abp.EntityFrameworkCore
return queryable.Provider is EntityQueryProvider;
}
public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default)
{
return queryable.ContainsAsync(item, cancellationToken);
}
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.AnyAsync(predicate, cancellationToken);
}
public Task<bool> AllAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.AllAsync(predicate, cancellationToken);
}
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.CountAsync(cancellationToken);
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.ToListAsync(cancellationToken);
return queryable.CountAsync(predicate, cancellationToken);
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.LongCountAsync(cancellationToken);
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.LongCountAsync(predicate, cancellationToken);
}
public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.FirstAsync(cancellationToken);
}
public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.FirstAsync(predicate, cancellationToken);
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.FirstOrDefaultAsync(cancellationToken);
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return queryable.FirstOrDefaultAsync(predicate, cancellationToken);
}
public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.LastAsync(cancellationToken);
}
public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.LastAsync(predicate, cancellationToken);
}
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.LastOrDefaultAsync(cancellationToken);
}
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return queryable.LastOrDefaultAsync(predicate, cancellationToken);
}
public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.SingleAsync(cancellationToken);
}
public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return queryable.SingleAsync(predicate, cancellationToken);
}
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.SingleOrDefaultAsync(cancellationToken);
}
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return queryable.SingleOrDefaultAsync(predicate, cancellationToken);
}
public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.MinAsync(cancellationToken);
}
public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{
return queryable.MinAsync(selector, cancellationToken);
}
public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.MaxAsync(cancellationToken);
}
public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{
return queryable.MaxAsync(selector, cancellationToken);
}
public Task<decimal> SumAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<decimal?> SumAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<int> SumAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<int?> SumAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<long> SumAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<long?> SumAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<double> SumAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<double?> SumAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<float> SumAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<float?> SumAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(cancellationToken);
}
public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{
return queryable.SumAsync(selector, cancellationToken);
}
public Task<decimal> AverageAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<decimal?> AverageAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<double> AverageAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<double?> AverageAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<double> AverageAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<double?> AverageAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<double> AverageAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<double?> AverageAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<float> AverageAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<float?> AverageAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(cancellationToken);
}
public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{
return queryable.AverageAsync(selector, cancellationToken);
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.ToListAsync(cancellationToken);
}
public Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return queryable.ToArrayAsync(cancellationToken);
}
}
}
}

@ -45,11 +45,8 @@ namespace Microsoft.Extensions.DependencyInjection
AddHttpClientFactoryAndPolicy(services, remoteServiceConfigurationName, configureHttpClientBuilder);
//TODO: Make a configuration option and add remoteServiceName inside it!
//TODO: Add option to change type filter
var serviceTypes = assembly.GetTypes().Where(t =>
t.IsInterface && t.IsPublic && typeof(IRemoteService).IsAssignableFrom(t)
);
var serviceTypes = assembly.GetTypes().Where(IsSuitableForDynamicClientProxying);
foreach (var serviceType in serviceTypes)
{
@ -155,7 +152,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddTransient(interceptorType);
var interceptorAdapterType = typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(interceptorType);
var validationInterceptorAdapterType =
typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(typeof(ValidationInterceptor));
@ -191,5 +188,21 @@ namespace Microsoft.Extensions.DependencyInjection
return services;
}
/// <summary>
/// Checks wether the type is suitable to use with the dynamic proxying.
/// Currently the type is checked statically against some fixed conditions.
/// </summary>
/// <param name="type">Type to check</param>
/// <returns>True, if the type is suitable for dynamic proxying. Otherwise false.</returns>
static bool IsSuitableForDynamicClientProxying(Type type)
{
//TODO: Add option to change type filter
return type.IsInterface
&& type.IsPublic
&& !type.IsGenericType
&& typeof(IRemoteService).IsAssignableFrom(type);
}
}
}

@ -1,4 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http;
using Volo.Abp.Castle;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
@ -21,5 +23,24 @@ namespace Volo.Abp.Http.Client
var configuration = context.Services.GetConfiguration();
Configure<AbpRemoteServiceOptions>(configuration);
}
public override void PostConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpHttpClientOptions>(options =>
{
if (options.HttpClientActions.Any())
{
var httpClientNames = options.HttpClientProxies.Select(x => x.Value.RemoteServiceName);
foreach (var httpClientName in httpClientNames)
{
foreach (var httpClientAction in options.HttpClientActions)
{
context.Services.Configure<HttpClientFactoryOptions>(httpClientName,
x => x.HttpClientActions.Add(httpClientAction.Invoke(httpClientName)));
}
}
}
});
}
}
}

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using Volo.Abp.Http.Client.DynamicProxying;
namespace Volo.Abp.Http.Client
@ -8,9 +9,12 @@ namespace Volo.Abp.Http.Client
{
public Dictionary<Type, DynamicHttpClientProxyConfig> HttpClientProxies { get; set; }
public List<Func<string, Action<HttpClient>>> HttpClientActions { get; }
public AbpHttpClientOptions()
{
HttpClientProxies = new Dictionary<Type, DynamicHttpClientProxyConfig>();
HttpClientActions = new List<Func<string, Action<HttpClient>>>();
}
}
}
}

@ -25,17 +25,20 @@ namespace Volo.Abp.IdentityModel
protected ICancellationTokenProvider CancellationTokenProvider { get; }
protected IHttpClientFactory HttpClientFactory { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; }
public IdentityModelAuthenticationService(
IOptions<AbpIdentityClientOptions> options,
ICancellationTokenProvider cancellationTokenProvider,
IHttpClientFactory httpClientFactory,
ICurrentTenant currentTenant)
ICurrentTenant currentTenant,
IOptions<IdentityModelHttpRequestMessageOptions> identityModelHttpRequestMessageOptions)
{
ClientOptions = options.Value;
CancellationTokenProvider = cancellationTokenProvider;
HttpClientFactory = httpClientFactory;
CurrentTenant = currentTenant;
IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value;
Logger = NullLogger<IdentityModelAuthenticationService>.Instance;
}
@ -74,7 +77,7 @@ namespace Volo.Abp.IdentityModel
}
var tokenResponse = await GetTokenResponse(discoveryResponse, configuration);
if (tokenResponse.IsError)
{
if (tokenResponse.ErrorDescription != null)
@ -112,14 +115,16 @@ namespace Volo.Abp.IdentityModel
{
using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
{
return await httpClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
var request = new DiscoveryDocumentRequest
{
Address = configuration.Authority,
Policy =
{
RequireHttps = configuration.RequireHttps
}
});
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage(request);
return await httpClient.GetDiscoveryDocumentAsync(request);
}
}
@ -160,6 +165,7 @@ namespace Volo.Abp.IdentityModel
UserName = configuration.UserName,
Password = configuration.UserPassword
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage(request);
AddParametersToRequestAsync(configuration, request);
@ -177,6 +183,7 @@ namespace Volo.Abp.IdentityModel
ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret
};
IdentityModelHttpRequestMessageOptions.ConfigureHttpRequestMessage(request);
AddParametersToRequestAsync(configuration, request);

@ -0,0 +1,10 @@
using System;
using System.Net.Http;
namespace Volo.Abp.IdentityModel
{
public class IdentityModelHttpRequestMessageOptions
{
public Action<HttpRequestMessage> ConfigureHttpRequestMessage { get; set; }
}
}

@ -17,11 +17,17 @@ namespace Volo.Abp.Localization
public List<LanguageInfo> Languages { get; }
public Dictionary<string, List<NameValue>> LanguagesMap { get; }
public Dictionary<string, List<NameValue>> LanguageFilesMap { get; }
public AbpLocalizationOptions()
{
Resources = new LocalizationResourceDictionary();
GlobalContributors = new TypeList<ILocalizationResourceContributor>();
Languages = new List<LanguageInfo>();
LanguagesMap = new Dictionary<string, List<NameValue>>();
LanguageFilesMap = new Dictionary<string, List<NameValue>>();
}
}
}

@ -0,0 +1,58 @@
using System.Collections.Generic;
using System.Linq;
namespace Volo.Abp.Localization
{
public static class AbpLocalizationOptionsExtensions
{
public static AbpLocalizationOptions AddLanguagesMapOrUpdate(this AbpLocalizationOptions localizationOptions,
string packageName, params NameValue[] maps)
{
foreach (var map in maps)
{
AddOrUpdate(localizationOptions.LanguagesMap, packageName, map);
}
return localizationOptions;
}
public static string GetLanguagesMap(this AbpLocalizationOptions localizationOptions, string packageName,
string language)
{
return localizationOptions.LanguagesMap.TryGetValue(packageName, out var maps)
? maps.FirstOrDefault(x => x.Name == language)?.Value ?? language
: language;
}
public static AbpLocalizationOptions AddLanguageFilesMapOrUpdate(this AbpLocalizationOptions localizationOptions,
string packageName, params NameValue[] maps)
{
foreach (var map in maps)
{
AddOrUpdate(localizationOptions.LanguageFilesMap, packageName, map);
}
return localizationOptions;
}
public static string GetLanguageFilesMap(this AbpLocalizationOptions localizationOptions, string packageName,
string language)
{
return localizationOptions.LanguageFilesMap.TryGetValue(packageName, out var maps)
? maps.FirstOrDefault(x => x.Name == language)?.Value ?? language
: language;
}
private static void AddOrUpdate(IDictionary<string, List<NameValue>> maps, string packageName, NameValue value)
{
if (maps.TryGetValue(packageName, out var existMaps))
{
existMaps.GetOrAdd(x => x.Name == value.Name, () => value).Value = value.Value;
}
else
{
maps.Add(packageName, new List<NameValue> {value});
}
}
}
}

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
@ -17,19 +18,337 @@ namespace Volo.Abp.MongoDB
return queryable.Provider.GetType().Namespace?.StartsWith("MongoDB") ?? false;
}
protected IMongoQueryable<T> GetMongoQueryable<T>(IQueryable<T> queryable)
{
return (IMongoQueryable<T>) queryable;
}
public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default)
{
return Task.FromResult(GetMongoQueryable(queryable).Contains(item));
}
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AnyAsync(predicate, cancellationToken);
}
public Task<bool> AllAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return Task.FromResult(GetMongoQueryable(queryable).All(predicate));
}
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return ((IMongoQueryable<T>) queryable).CountAsync(cancellationToken);
return GetMongoQueryable(queryable).CountAsync(cancellationToken);
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).CountAsync(predicate, cancellationToken);
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).LongCountAsync(cancellationToken);
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).LongCountAsync(predicate, cancellationToken);
}
public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).FirstAsync(cancellationToken);
}
public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return ((IMongoQueryable<T>) queryable).ToListAsync(cancellationToken);
return GetMongoQueryable(queryable).FirstAsync(predicate, cancellationToken);
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return ((IMongoQueryable<T>) queryable).FirstOrDefaultAsync(cancellationToken);
return GetMongoQueryable(queryable).FirstOrDefaultAsync(cancellationToken);
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).FirstOrDefaultAsync(predicate, cancellationToken);
}
public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(GetMongoQueryable(queryable).Last());
}
public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return Task.FromResult(GetMongoQueryable(queryable).Last(predicate));
}
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return Task.FromResult(GetMongoQueryable(queryable).LastOrDefault());
}
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return Task.FromResult(GetMongoQueryable(queryable).LastOrDefault(predicate));
}
public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SingleAsync(cancellationToken);
}
public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SingleAsync(predicate, cancellationToken);
}
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SingleOrDefaultAsync(cancellationToken);
}
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SingleOrDefaultAsync(predicate, cancellationToken);
}
public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).MinAsync(cancellationToken);
}
public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).MinAsync(selector, cancellationToken);
}
public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).MaxAsync(cancellationToken);
}
public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).MaxAsync(selector, cancellationToken);
}
public Task<decimal> SumAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<decimal?> SumAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<int> SumAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<int?> SumAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<long> SumAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<long?> SumAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<double> SumAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<double?> SumAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<float> SumAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<float?> SumAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(cancellationToken);
}
public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).SumAsync(selector, cancellationToken);
}
public Task<decimal> AverageAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<decimal?> AverageAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<double> AverageAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<double?> AverageAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<double> AverageAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<double?> AverageAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<double> AverageAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<double?> AverageAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<float> AverageAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<float?> AverageAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(cancellationToken);
}
public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).AverageAsync(selector, cancellationToken);
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return GetMongoQueryable(queryable).ToListAsync(cancellationToken);
}
public async Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
return (await GetMongoQueryable(queryable).ToListAsync(cancellationToken)).ToArray();
}
}
}
}

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
@ -15,9 +17,36 @@ namespace Volo.Abp.Linq
Providers = providers;
}
public virtual Task<int> CountAsync<T>(
IQueryable<T> queryable,
CancellationToken cancellationToken = default)
protected virtual IAsyncQueryableProvider FindProvider<T>(IQueryable<T> queryable)
{
return Providers.FirstOrDefault(p => p.CanExecute(queryable));
}
public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.ContainsAsync(queryable, item, cancellationToken)
: Task.FromResult(queryable.Contains(item));
}
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AnyAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.Any(predicate));
}
public Task<bool> AllAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AllAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.All(predicate));
}
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
@ -25,19 +54,47 @@ namespace Volo.Abp.Linq
: Task.FromResult(queryable.Count());
}
public virtual Task<List<T>> ToListAsync<T>(
IQueryable<T> queryable,
CancellationToken cancellationToken = default)
public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.ToListAsync(queryable, cancellationToken)
: Task.FromResult(queryable.ToList());
? provider.CountAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.Count(predicate));
}
public virtual Task<T> FirstOrDefaultAsync<T>(
IQueryable<T> queryable,
CancellationToken cancellationToken = default)
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.LongCountAsync(queryable, cancellationToken)
: Task.FromResult(queryable.LongCount());
}
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.LongCountAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.LongCount(predicate));
}
public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.FirstAsync(queryable, cancellationToken)
: Task.FromResult(queryable.First());
}
public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.FirstAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.First(predicate));
}
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
@ -45,9 +102,447 @@ namespace Volo.Abp.Linq
: Task.FromResult(queryable.FirstOrDefault());
}
protected virtual IAsyncQueryableProvider FindProvider<T>(IQueryable<T> queryable)
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
return Providers.FirstOrDefault(p => p.CanExecute(queryable));
var provider = FindProvider(queryable);
return provider != null
? provider.FirstOrDefaultAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.FirstOrDefault(predicate));
}
public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.LastAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Last());
}
public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.LastAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.Last(predicate));
}
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.LastOrDefaultAsync(queryable, cancellationToken)
: Task.FromResult(queryable.LastOrDefault());
}
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.LastOrDefaultAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.LastOrDefault(predicate));
}
public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SingleAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Single());
}
public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SingleAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.Single(predicate));
}
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SingleOrDefaultAsync(queryable, cancellationToken)
: Task.FromResult(queryable.SingleOrDefault());
}
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SingleOrDefaultAsync(queryable, predicate, cancellationToken)
: Task.FromResult(queryable.SingleOrDefault(predicate));
}
public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.MinAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Min());
}
public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.MinAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Min(selector));
}
public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.MaxAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Max());
}
public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.MaxAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Max(selector));
}
public Task<decimal> SumAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<decimal?> SumAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<int> SumAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<int?> SumAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<long> SumAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<long?> SumAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<double> SumAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<double?> SumAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<float> SumAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<float?> SumAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Sum());
}
public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.SumAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Sum(selector));
}
public Task<decimal> AverageAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<decimal?> AverageAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<double> AverageAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<double?> AverageAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<double> AverageAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<double?> AverageAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<double> AverageAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<double?> AverageAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<float> AverageAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<float?> AverageAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, cancellationToken)
: Task.FromResult(queryable.Average());
}
public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.AverageAsync(queryable, selector, cancellationToken)
: Task.FromResult(queryable.Average(selector));
}
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.ToListAsync(queryable, cancellationToken)
: Task.FromResult(queryable.ToList());
}
public Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default)
{
var provider = FindProvider(queryable);
return provider != null
? provider.ToArrayAsync(queryable, cancellationToken)
: Task.FromResult(queryable.ToArray());
}
}
}
}

@ -1,25 +1,398 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.Linq
{
public interface IAsyncQueryableExecuter
{
#region Contains
Task<bool> ContainsAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] T item,
CancellationToken cancellationToken = default);
#endregion
#region Any/All
Task<bool> AnyAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<bool> AllAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Count/LongCount
Task<int> CountAsync<T>(
IQueryable<T> queryable,
CancellationToken cancellationToken = default
);
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<int> CountAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<long> LongCountAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<long> LongCountAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region First/FirstOrDefault
Task<T> FirstAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> FirstAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<List<T>> ToListAsync<T>(
IQueryable<T> queryable,
CancellationToken cancellationToken = default
);
Task<T> FirstOrDefaultAsync<T>(
IQueryable<T> queryable,
CancellationToken cancellationToken = default
);
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> FirstOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Last/LastOrDefault
Task<T> LastAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> LastAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<T> LastOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> LastOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Single/SingleOrDefault
Task<T> SingleAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> SingleAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<T> SingleOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> SingleOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Min
Task<T> MinAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<TResult> MinAsync<T, TResult>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default);
#endregion
#region Max
Task<T> MaxAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<TResult> MaxAsync<T, TResult>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default);
#endregion
#region Sum
Task<decimal> SumAsync(
[NotNull] IQueryable<decimal> source,
CancellationToken cancellationToken = default);
Task<decimal?> SumAsync(
[NotNull] IQueryable<decimal?> source,
CancellationToken cancellationToken = default);
Task<decimal> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal>> selector,
CancellationToken cancellationToken = default);
Task<decimal?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal?>> selector,
CancellationToken cancellationToken = default);
Task<int> SumAsync(
[NotNull] IQueryable<int> source,
CancellationToken cancellationToken = default);
Task<int?> SumAsync(
[NotNull] IQueryable<int?> source,
CancellationToken cancellationToken = default);
Task<int> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default);
Task<int?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int?>> selector,
CancellationToken cancellationToken = default);
Task<long> SumAsync(
[NotNull] IQueryable<long> source,
CancellationToken cancellationToken = default);
Task<long?> SumAsync(
[NotNull] IQueryable<long?> source,
CancellationToken cancellationToken = default);
Task<long> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long>> selector,
CancellationToken cancellationToken = default);
Task<long?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long?>> selector,
CancellationToken cancellationToken = default);
Task<double> SumAsync(
[NotNull] IQueryable<double> source,
CancellationToken cancellationToken = default);
Task<double?> SumAsync(
[NotNull] IQueryable<double?> source,
CancellationToken cancellationToken = default);
Task<double> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double>> selector,
CancellationToken cancellationToken = default);
Task<double?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double?>> selector,
CancellationToken cancellationToken = default);
Task<float> SumAsync(
[NotNull] IQueryable<float> source,
CancellationToken cancellationToken = default);
Task<float?> SumAsync(
[NotNull] IQueryable<float?> source,
CancellationToken cancellationToken = default);
Task<float> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float>> selector,
CancellationToken cancellationToken = default);
Task<float?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float?>> selector,
CancellationToken cancellationToken = default);
#endregion
#region Average
Task<decimal> AverageAsync(
[NotNull] IQueryable<decimal> source,
CancellationToken cancellationToken = default);
Task<decimal?> AverageAsync(
[NotNull] IQueryable<decimal?> source,
CancellationToken cancellationToken = default);
Task<decimal> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal>> selector,
CancellationToken cancellationToken = default);
Task<decimal?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal?>> selector,
CancellationToken cancellationToken = default);
Task<double> AverageAsync(
[NotNull] IQueryable<int> source,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync(
[NotNull] IQueryable<int?> source,
CancellationToken cancellationToken = default);
Task<double> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int?>> selector,
CancellationToken cancellationToken = default);
Task<double> AverageAsync(
[NotNull] IQueryable<long> source,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync(
[NotNull] IQueryable<long?> source,
CancellationToken cancellationToken = default);
Task<double> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long>> selector,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long?>> selector,
CancellationToken cancellationToken = default);
Task<double> AverageAsync(
[NotNull] IQueryable<double> source,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync(
[NotNull] IQueryable<double?> source,
CancellationToken cancellationToken = default);
Task<double> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double>> selector,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double?>> selector,
CancellationToken cancellationToken = default);
Task<float> AverageAsync(
[NotNull] IQueryable<float> source,
CancellationToken cancellationToken = default);
Task<float?> AverageAsync(
[NotNull] IQueryable<float?> source,
CancellationToken cancellationToken = default);
Task<float> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float>> selector,
CancellationToken cancellationToken = default);
Task<float?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float?>> selector,
CancellationToken cancellationToken = default);
#endregion
#region ToList/Array
Task<List<T>> ToListAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T[]> ToArrayAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
#endregion
}
}
}

@ -1,18 +1,400 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace Volo.Abp.Linq
{
public interface IAsyncQueryableProvider
{
bool CanExecute<T>(IQueryable<T> queryable);
Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default);
Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default);
#region Contains
Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default);
Task<bool> ContainsAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] T item,
CancellationToken cancellationToken = default);
#endregion
#region Any/All
Task<bool> AnyAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<bool> AllAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Count/LongCount
Task<int> CountAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<int> CountAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<long> LongCountAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<long> LongCountAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region First/FirstOrDefault
Task<T> FirstAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> FirstAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<T> FirstOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> FirstOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Last/LastOrDefault
Task<T> LastAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> LastAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<T> LastOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> LastOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Single/SingleOrDefault
Task<T> SingleAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> SingleAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
Task<T> SingleOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T> SingleOrDefaultAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, bool>> predicate,
CancellationToken cancellationToken = default);
#endregion
#region Min
Task<T> MinAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<TResult> MinAsync<T, TResult>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default);
#endregion
#region Max
Task<T> MaxAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<TResult> MaxAsync<T, TResult>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, TResult>> selector,
CancellationToken cancellationToken = default);
#endregion
#region Sum
Task<decimal> SumAsync(
[NotNull] IQueryable<decimal> source,
CancellationToken cancellationToken = default);
Task<decimal?> SumAsync(
[NotNull] IQueryable<decimal?> source,
CancellationToken cancellationToken = default);
Task<decimal> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal>> selector,
CancellationToken cancellationToken = default);
Task<decimal?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal?>> selector,
CancellationToken cancellationToken = default);
Task<int> SumAsync(
[NotNull] IQueryable<int> source,
CancellationToken cancellationToken = default);
Task<int?> SumAsync(
[NotNull] IQueryable<int?> source,
CancellationToken cancellationToken = default);
Task<int> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default);
Task<int?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int?>> selector,
CancellationToken cancellationToken = default);
Task<long> SumAsync(
[NotNull] IQueryable<long> source,
CancellationToken cancellationToken = default);
Task<long?> SumAsync(
[NotNull] IQueryable<long?> source,
CancellationToken cancellationToken = default);
Task<long> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long>> selector,
CancellationToken cancellationToken = default);
Task<long?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long?>> selector,
CancellationToken cancellationToken = default);
Task<double> SumAsync(
[NotNull] IQueryable<double> source,
CancellationToken cancellationToken = default);
Task<double?> SumAsync(
[NotNull] IQueryable<double?> source,
CancellationToken cancellationToken = default);
Task<double> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double>> selector,
CancellationToken cancellationToken = default);
Task<double?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double?>> selector,
CancellationToken cancellationToken = default);
Task<float> SumAsync(
[NotNull] IQueryable<float> source,
CancellationToken cancellationToken = default);
Task<float?> SumAsync(
[NotNull] IQueryable<float?> source,
CancellationToken cancellationToken = default);
Task<float> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float>> selector,
CancellationToken cancellationToken = default);
Task<float?> SumAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float?>> selector,
CancellationToken cancellationToken = default);
#endregion
#region Average
Task<decimal> AverageAsync(
[NotNull] IQueryable<decimal> source,
CancellationToken cancellationToken = default);
Task<decimal?> AverageAsync(
[NotNull] IQueryable<decimal?> source,
CancellationToken cancellationToken = default);
Task<decimal> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal>> selector,
CancellationToken cancellationToken = default);
Task<decimal?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, decimal?>> selector,
CancellationToken cancellationToken = default);
Task<double> AverageAsync(
[NotNull] IQueryable<int> source,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync(
[NotNull] IQueryable<int?> source,
CancellationToken cancellationToken = default);
Task<double> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int>> selector,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, int?>> selector,
CancellationToken cancellationToken = default);
Task<double> AverageAsync(
[NotNull] IQueryable<long> source,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync(
[NotNull] IQueryable<long?> source,
CancellationToken cancellationToken = default);
Task<double> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long>> selector,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, long?>> selector,
CancellationToken cancellationToken = default);
Task<double> AverageAsync(
[NotNull] IQueryable<double> source,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync(
[NotNull] IQueryable<double?> source,
CancellationToken cancellationToken = default);
Task<double> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double>> selector,
CancellationToken cancellationToken = default);
Task<double?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, double?>> selector,
CancellationToken cancellationToken = default);
Task<float> AverageAsync(
[NotNull] IQueryable<float> source,
CancellationToken cancellationToken = default);
Task<float?> AverageAsync(
[NotNull] IQueryable<float?> source,
CancellationToken cancellationToken = default);
Task<float> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float>> selector,
CancellationToken cancellationToken = default);
Task<float?> AverageAsync<T>(
[NotNull] IQueryable<T> queryable,
[NotNull] Expression<Func<T, float?>> selector,
CancellationToken cancellationToken = default);
#endregion
#region ToList/Array
Task<List<T>> ToListAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
Task<T[]> ToArrayAsync<T>(
[NotNull] IQueryable<T> queryable,
CancellationToken cancellationToken = default);
#endregion
}
}
}

@ -4,7 +4,7 @@ using System.Data;
namespace Volo.Abp.Uow
{
//TODO: Implement default options!
/// <summary>
/// Global (default) unit of work options
/// </summary>
@ -17,7 +17,7 @@ namespace Volo.Abp.Uow
public IsolationLevel? IsolationLevel { get; set; }
public TimeSpan? Timeout { get; set; }
public int? Timeout { get; set; }
internal AbpUnitOfWorkOptions Normalize(AbpUnitOfWorkOptions options)
{
@ -49,4 +49,4 @@ namespace Volo.Abp.Uow
}
}
}
}
}

@ -12,14 +12,17 @@ namespace Volo.Abp.Uow
public IsolationLevel? IsolationLevel { get; set; }
public TimeSpan? Timeout { get; set; }
/// <summary>
/// Milliseconds
/// </summary>
public int? Timeout { get; set; }
public AbpUnitOfWorkOptions()
{
}
public AbpUnitOfWorkOptions(bool isTransactional = false, IsolationLevel? isolationLevel = null, TimeSpan? timeout = null)
public AbpUnitOfWorkOptions(bool isTransactional = false, IsolationLevel? isolationLevel = null, int? timeout = null)
{
IsTransactional = isTransactional;
IsolationLevel = isolationLevel;
@ -36,4 +39,4 @@ namespace Volo.Abp.Uow
};
}
}
}
}

@ -9,6 +9,9 @@ namespace Volo.Abp.Uow
IsolationLevel? IsolationLevel { get; }
TimeSpan? Timeout { get; }
/// <summary>
/// Milliseconds
/// </summary>
int? Timeout { get; }
}
}
}

@ -22,7 +22,7 @@ namespace Volo.Abp.Uow
/// Timeout of UOW As milliseconds.
/// Uses default value if not supplied.
/// </summary>
public TimeSpan? Timeout { get; set; }
public int? Timeout { get; set; }
/// <summary>
/// If this UOW is transactional, this option indicated the isolation level of the transaction.
@ -39,7 +39,7 @@ namespace Volo.Abp.Uow
public UnitOfWorkAttribute()
{
}
public UnitOfWorkAttribute(bool isTransactional)
@ -53,7 +53,7 @@ namespace Volo.Abp.Uow
IsolationLevel = isolationLevel;
}
public UnitOfWorkAttribute(bool isTransactional, IsolationLevel isolationLevel, TimeSpan timeout)
public UnitOfWorkAttribute(bool isTransactional, IsolationLevel isolationLevel, int timeout)
{
IsTransactional = isTransactional;
IsolationLevel = isolationLevel;

@ -8,11 +8,11 @@ namespace Volo.Abp.Uow
{
[NotNull]
public static IUnitOfWork Begin(
[NotNull] this IUnitOfWorkManager unitOfWorkManager,
[NotNull] this IUnitOfWorkManager unitOfWorkManager,
bool requiresNew = false,
bool isTransactional = false,
IsolationLevel? isolationLevel = null,
TimeSpan? timeout = null)
IsolationLevel? isolationLevel = null,
int? timeout = null)
{
Check.NotNull(unitOfWorkManager, nameof(unitOfWorkManager));
@ -40,4 +40,4 @@ namespace Volo.Abp.Uow
unitOfWorkManager.TryBeginReserved(reservationName, new AbpUnitOfWorkOptions());
}
}
}
}

@ -43,6 +43,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Blogging.MongoDB.Tests
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Blogging.Domain.Tests", "test\Volo.Blogging.Domain.Tests\Volo.Blogging.Domain.Tests.csproj", "{B6D7EF20-9921-490A-AA95-47E3E174DC9B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "admin-app", "admin-app", "{BE2A423C-271E-469A-AD90-5640DEBEE9C1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "domain", "domain", "{A9EF3061-5205-46C7-ACAA-23931CB98E4F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "public-app", "public-app", "{1314C122-18F0-4C6B-895F-27645B6121FF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Blogging.Admin.Application.Contracts", "src\Volo.Blogging.Admin.Application.Contracts\Volo.Blogging.Admin.Application.Contracts.csproj", "{D8DF4D56-644E-4ADF-9DB9-712DDA62B129}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Blogging.Admin.Application", "src\Volo.Blogging.Admin.Application\Volo.Blogging.Admin.Application.csproj", "{CB5DEBB3-5C2E-48E9-AA42-497575BCC7A4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Blogging.Admin.HttpApi", "src\Volo.Blogging.Admin.HttpApi\Volo.Blogging.Admin.HttpApi.csproj", "{59BBAF94-CC8E-4313-9143-F2F5C36A7C45}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Blogging.Admin.HttpApi.Client", "src\Volo.Blogging.Admin.HttpApi.Client\Volo.Blogging.Admin.HttpApi.Client.csproj", "{58A63CC9-C886-448B-AB4E-068600294D86}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Blogging.Admin.Web", "src\Volo.Blogging.Admin.Web\Volo.Blogging.Admin.Web.csproj", "{DB75CA32-96A5-4D10-8DD0-E62A3D0DDBCB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -117,28 +133,56 @@ Global
{B6D7EF20-9921-490A-AA95-47E3E174DC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6D7EF20-9921-490A-AA95-47E3E174DC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6D7EF20-9921-490A-AA95-47E3E174DC9B}.Release|Any CPU.Build.0 = Release|Any CPU
{D8DF4D56-644E-4ADF-9DB9-712DDA62B129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8DF4D56-644E-4ADF-9DB9-712DDA62B129}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8DF4D56-644E-4ADF-9DB9-712DDA62B129}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8DF4D56-644E-4ADF-9DB9-712DDA62B129}.Release|Any CPU.Build.0 = Release|Any CPU
{CB5DEBB3-5C2E-48E9-AA42-497575BCC7A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB5DEBB3-5C2E-48E9-AA42-497575BCC7A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB5DEBB3-5C2E-48E9-AA42-497575BCC7A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB5DEBB3-5C2E-48E9-AA42-497575BCC7A4}.Release|Any CPU.Build.0 = Release|Any CPU
{59BBAF94-CC8E-4313-9143-F2F5C36A7C45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{59BBAF94-CC8E-4313-9143-F2F5C36A7C45}.Debug|Any CPU.Build.0 = Debug|Any CPU
{59BBAF94-CC8E-4313-9143-F2F5C36A7C45}.Release|Any CPU.ActiveCfg = Release|Any CPU
{59BBAF94-CC8E-4313-9143-F2F5C36A7C45}.Release|Any CPU.Build.0 = Release|Any CPU
{58A63CC9-C886-448B-AB4E-068600294D86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58A63CC9-C886-448B-AB4E-068600294D86}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58A63CC9-C886-448B-AB4E-068600294D86}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58A63CC9-C886-448B-AB4E-068600294D86}.Release|Any CPU.Build.0 = Release|Any CPU
{DB75CA32-96A5-4D10-8DD0-E62A3D0DDBCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB75CA32-96A5-4D10-8DD0-E62A3D0DDBCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB75CA32-96A5-4D10-8DD0-E62A3D0DDBCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB75CA32-96A5-4D10-8DD0-E62A3D0DDBCB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F1D954AD-001A-4533-A8CC-94DDCF70B552} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{9F3AECDD-0B96-4EB4-BB86-59B488350B76} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{237BF49B-5FD8-413C-BBD7-2313D91D0553} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{1678D922-E56D-4D6F-94F5-12AD13C1D919} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{87A423C6-900E-4D59-A4F2-B7C49D91E6F0} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{C20F42B4-0E93-43D3-B7CD-363D7E1B4750} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{03328648-6DE6-43C1-9A27-64771A73FAAD} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{A4DBA051-7FB9-4AD7-B9B7-6810B2268122} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{0D50B2EE-5F62-4C1D-B04D-56BE0CF75967} = {EB4FB44A-FE39-4245-9DAD-D6437BCE3870}
{14409939-5A35-4145-A5C4-F3AED1617243} = {EB4FB44A-FE39-4245-9DAD-D6437BCE3870}
{BBE8D8BE-1B24-49FE-86EF-3848D4BB6829} = {25B3A516-5C0D-42E3-9294-E8A9346CEE4B}
{0B9AAD44-1FCF-4AF1-838F-A09446E98E37} = {25B3A516-5C0D-42E3-9294-E8A9346CEE4B}
{C949B953-80B3-4B36-B535-1AD74A34FEAC} = {25B3A516-5C0D-42E3-9294-E8A9346CEE4B}
{98C2D36A-F874-405D-8565-9CE59438E879} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{4C818374-2DE8-422F-8585-975E8366DB26} = {EB4FB44A-FE39-4245-9DAD-D6437BCE3870}
{0A29F64C-11F1-40B6-8E6D-91E86823775E} = {25B3A516-5C0D-42E3-9294-E8A9346CEE4B}
{B6D7EF20-9921-490A-AA95-47E3E174DC9B} = {25B3A516-5C0D-42E3-9294-E8A9346CEE4B}
{BE2A423C-271E-469A-AD90-5640DEBEE9C1} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{A9EF3061-5205-46C7-ACAA-23931CB98E4F} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{1314C122-18F0-4C6B-895F-27645B6121FF} = {42BF26EF-B8C7-42DC-9FFB-3653109B7776}
{9F3AECDD-0B96-4EB4-BB86-59B488350B76} = {A9EF3061-5205-46C7-ACAA-23931CB98E4F}
{F1D954AD-001A-4533-A8CC-94DDCF70B552} = {A9EF3061-5205-46C7-ACAA-23931CB98E4F}
{87A423C6-900E-4D59-A4F2-B7C49D91E6F0} = {A9EF3061-5205-46C7-ACAA-23931CB98E4F}
{98C2D36A-F874-405D-8565-9CE59438E879} = {A9EF3061-5205-46C7-ACAA-23931CB98E4F}
{1678D922-E56D-4D6F-94F5-12AD13C1D919} = {1314C122-18F0-4C6B-895F-27645B6121FF}
{237BF49B-5FD8-413C-BBD7-2313D91D0553} = {1314C122-18F0-4C6B-895F-27645B6121FF}
{C20F42B4-0E93-43D3-B7CD-363D7E1B4750} = {1314C122-18F0-4C6B-895F-27645B6121FF}
{03328648-6DE6-43C1-9A27-64771A73FAAD} = {1314C122-18F0-4C6B-895F-27645B6121FF}
{A4DBA051-7FB9-4AD7-B9B7-6810B2268122} = {1314C122-18F0-4C6B-895F-27645B6121FF}
{D8DF4D56-644E-4ADF-9DB9-712DDA62B129} = {BE2A423C-271E-469A-AD90-5640DEBEE9C1}
{CB5DEBB3-5C2E-48E9-AA42-497575BCC7A4} = {BE2A423C-271E-469A-AD90-5640DEBEE9C1}
{59BBAF94-CC8E-4313-9143-F2F5C36A7C45} = {BE2A423C-271E-469A-AD90-5640DEBEE9C1}
{58A63CC9-C886-448B-AB4E-068600294D86} = {BE2A423C-271E-469A-AD90-5640DEBEE9C1}
{DB75CA32-96A5-4D10-8DD0-E62A3D0DDBCB} = {BE2A423C-271E-469A-AD90-5640DEBEE9C1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F2BAE819-78D4-407A-9201-22473B2850B0}

@ -33,6 +33,7 @@ using Volo.Abp.Threading;
using Volo.Abp.UI;
using Volo.Abp.VirtualFileSystem;
using Volo.Blogging;
using Volo.Blogging.Admin;
using Volo.Blogging.Files;
using Volo.BloggingTestApp.EntityFrameworkCore;
using Volo.BloggingTestApp.MongoDB;
@ -42,6 +43,8 @@ namespace Volo.BloggingTestApp
[DependsOn(
typeof(BloggingWebModule),
typeof(BloggingApplicationModule),
typeof(BloggingAdminWebModule),
typeof(BloggingAdminApplicationModule),
#if MONGODB
typeof(BloggingTestAppMongoDbModule),
#else
@ -105,12 +108,12 @@ namespace Volo.BloggingTestApp
options.CustomSchemaIds(type => type.FullName);
});
var cultures = new List<CultureInfo>
{
new CultureInfo("cs"),
new CultureInfo("en"),
new CultureInfo("tr"),
new CultureInfo("zh-Hans")
var cultures = new List<CultureInfo>
{
new CultureInfo("cs"),
new CultureInfo("en"),
new CultureInfo("tr"),
new CultureInfo("zh-Hans")
};
Configure<RequestLocalizationOptions>(options =>

@ -26,6 +26,8 @@
<ProjectReference Include="..\Volo.BloggingTestApp.EntityFrameworkCore\Volo.BloggingTestApp.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\src\Volo.Blogging.Application\Volo.Blogging.Application.csproj" />
<ProjectReference Include="..\..\src\Volo.Blogging.Web\Volo.Blogging.Web.csproj" />
<ProjectReference Include="..\..\src\Volo.Blogging.Admin.Application\Volo.Blogging.Admin.Application.csproj" />
<ProjectReference Include="..\..\src\Volo.Blogging.Admin.Web\Volo.Blogging.Admin.Web.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj" />
<ProjectReference Include="..\..\..\..\modules\identity\src\Volo.Abp.Identity.Application\Volo.Abp.Identity.Application.csproj" />

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Blogging.Admin.Application.Contracts</AssemblyName>
<PackageId>Volo.Blogging.Admin.Application.Contracts</PackageId>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Blogging.Domain.Shared\Volo.Blogging.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\cs.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\de.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\en.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\nl.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\pl-PL.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\pt-BR.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\sl.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\tr.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\vi.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\zh-Hans.json" />
<EmbeddedResource Include="Volo\Blogging\Admin\Localization\Resources\Blogging\Admin\ApplicationContracts\zh-Hant.json" />
</ItemGroup>
</Project>

@ -0,0 +1,25 @@
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin
{
[DependsOn(typeof(BloggingDomainSharedModule))]
public class BloggingAdminApplicationContractsModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<BloggingAdminApplicationContractsModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<BloggingResource>()
.AddVirtualJson("Volo/Blogging/Admin/Localization/Resources/Blogging/Admin/ApplicationContracts");
});
}
}
}

@ -0,0 +1,25 @@
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin
{
public class BloggingAdminPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var bloggingGroup = context.AddGroup(BloggingAdminPermissions.GroupName, L("Permission:BloggingAdmin"));
var blogs = bloggingGroup.AddPermission(BloggingAdminPermissions.Blogs.Default, L("Permission:Blogs"));
blogs.AddChild(BloggingAdminPermissions.Blogs.Management, L("Permission:Management"));
blogs.AddChild(BloggingAdminPermissions.Blogs.Update, L("Permission:Edit"));
blogs.AddChild(BloggingAdminPermissions.Blogs.Delete, L("Permission:Delete"));
blogs.AddChild(BloggingAdminPermissions.Blogs.Create, L("Permission:Create"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<BloggingResource>(name);
}
}
}

@ -0,0 +1,23 @@
using Volo.Abp.Reflection;
namespace Volo.Blogging.Admin
{
public class BloggingAdminPermissions
{
public const string GroupName = "Blogging.Admin";
public static class Blogs
{
public const string Default = GroupName + ".Blog";
public const string Management = Default + ".Management";
public const string Delete = Default + ".Delete";
public const string Update = Default + ".Update";
public const string Create = Default + ".Create";
}
public static string[] GetAll()
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(BloggingAdminPermissions));
}
}
}

@ -0,0 +1,7 @@
namespace Volo.Blogging.Admin
{
public static class BloggingAdminRemoteServiceConsts
{
public const string RemoteServiceName = "BloggingAdmin";
}
}

@ -0,0 +1,14 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Volo.Blogging.Admin.Blogs
{
public class BlogDto : FullAuditedEntityDto<Guid>
{
public string Name { get; set; }
public string ShortName { get; set; }
public string Description { get; set; }
}
}

@ -1,4 +1,4 @@
namespace Volo.Blogging.Blogs.Dtos
namespace Volo.Blogging.Admin.Blogs
{
public class CreateBlogDto
{
@ -8,4 +8,4 @@ namespace Volo.Blogging.Blogs.Dtos
public string Description { get; set; }
}
}
}

@ -0,0 +1,20 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Volo.Blogging.Admin.Blogs
{
public interface IBlogManagementAppService : IApplicationService
{
Task<ListResultDto<BlogDto>> GetListAsync();
Task<BlogDto> GetAsync(Guid id);
Task<BlogDto> CreateAsync(CreateBlogDto input);
Task<BlogDto> UpdateAsync(Guid id, UpdateBlogDto input);
Task DeleteAsync(Guid id);
}
}

@ -1,4 +1,4 @@
namespace Volo.Blogging.Blogs.Dtos
namespace Volo.Blogging.Admin.Blogs
{
public class UpdateBlogDto
{
@ -8,4 +8,4 @@
public string Description { get; set; }
}
}
}

@ -0,0 +1,11 @@
{
"culture": "cs",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogy",
"Permission:Management": "Správa",
"Permission:Edit": "Upravit",
"Permission:Create": "Vytvořit",
"Permission:Delete": "Smazat"
}
}

@ -0,0 +1,11 @@
{
"culture": "de",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogs",
"Permission:Management": "Verwaltung",
"Permission:Edit": "Bearbeiten",
"Permission:Create": "Erstellen",
"Permission:Delete": "Löschen"
}
}

@ -0,0 +1,11 @@
{
"culture": "en",
"texts": {
"Permission:BloggingAdmin": "Blogging",
"Permission:Blogs": "Blogs",
"Permission:Management": "Management",
"Permission:Edit": "Edit",
"Permission:Create": "Create",
"Permission:Delete": "Delete"
}
}

@ -0,0 +1,11 @@
{
"culture": "nl",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogs",
"Permission:Management": "Beheer",
"Permission:Edit": "Bewerk",
"Permission:Create": "Maak aan",
"Permission:Delete": "Verwijder"
}
}

@ -0,0 +1,11 @@
{
"culture": "pl-PL",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogi",
"Permission:Management": "Zarządzanie",
"Permission:Edit": "Edytuj",
"Permission:Create": "Utwórz",
"Permission:Delete": "Usuń"
}
}

@ -0,0 +1,11 @@
{
"culture": "pt-BR",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogs",
"Permission:Management": "Gerenciamento",
"Permission:Edit": "Editar",
"Permission:Create": "Criar",
"Permission:Delete": "Excluir"
}
}

@ -0,0 +1,11 @@
{
"culture": "sl",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogi",
"Permission:Management": "Upravljanje",
"Permission:Edit": "Urejanje",
"Permission:Create": "Ustvarjanje",
"Permission:Delete": "Brisanje"
}
}

@ -0,0 +1,11 @@
{
"culture": "tr",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Bloglar",
"Permission:Management": "Yönetme",
"Permission:Edit": "Düzenle",
"Permission:Create": "Ekle",
"Permission:Delete": "Sil"
}
}

@ -0,0 +1,11 @@
{
"culture": "vi",
"texts": {
"Permission:BloggingAdmin": "Blog",
"Permission:Blogs": "Blogs",
"Permission:Management": "Quản lý",
"Permission:Edit": "Sửa",
"Permission:Create": "Tạo",
"Permission:Delete": "Xóa"
}
}

@ -0,0 +1,11 @@
{
"culture": "zh-Hans",
"texts": {
"Permission:BloggingAdmin": "博客",
"Permission:Blogs": "博客",
"Permission:Management": "管理",
"Permission:Edit": "编辑",
"Permission:Create": "创建",
"Permission:Delete": "删除"
}
}

@ -0,0 +1,11 @@
{
"culture": "zh-Hant",
"texts": {
"Permission:BloggingAdmin": "部落格",
"Permission:Blogs": "部落格",
"Permission:Management": "管理",
"Permission:Edit": "標及",
"Permission:Create": "新增",
"Permission:Delete": "刪除"
}
}

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Blogging.Admin.Application</AssemblyName>
<PackageId>Volo.Blogging.Admin.Application</PackageId>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
<ProjectReference Include="..\Volo.Blogging.Admin.Application.Contracts\Volo.Blogging.Admin.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.Blogging.Domain\Volo.Blogging.Domain.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,14 @@
using Volo.Abp.Application.Services;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin
{
public abstract class BloggingAdminAppServiceBase : ApplicationService
{
protected BloggingAdminAppServiceBase()
{
ObjectMapperContext = typeof(BloggingAdminApplicationModule);
LocalizationResource = typeof(BloggingResource);
}
}
}

@ -0,0 +1,14 @@
using AutoMapper;
using Volo.Blogging.Admin.Blogs;
using Volo.Blogging.Blogs;
namespace Volo.Blogging.Admin
{
public class BloggingAdminApplicationAutoMapperProfile : Profile
{
public BloggingAdminApplicationAutoMapperProfile()
{
CreateMap<Blog, BlogDto>();
}
}
}

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Blogging.Comments;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Admin
{
[DependsOn(
typeof(BloggingDomainModule),
typeof(BloggingAdminApplicationContractsModule),
typeof(AbpCachingModule),
typeof(AbpAutoMapperModule))]
public class BloggingAdminApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAutoMapperObjectMapper<BloggingAdminApplicationModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<BloggingAdminApplicationAutoMapperProfile>(validate: true);
});
}
}
}

@ -0,0 +1,64 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Blogging.Blogs;
namespace Volo.Blogging.Admin.Blogs
{
public class BlogManagementAppService : BloggingAdminAppServiceBase, IBlogManagementAppService
{
private readonly IBlogRepository _blogRepository;
public BlogManagementAppService(IBlogRepository blogRepository)
{
_blogRepository = blogRepository;
}
public async Task<ListResultDto<BlogDto>> GetListAsync()
{
var blogs = await _blogRepository.GetListAsync();
return new ListResultDto<BlogDto>(
ObjectMapper.Map<List<Blog>, List<BlogDto>>(blogs)
);
}
public async Task<BlogDto> GetAsync(Guid id)
{
var blog = await _blogRepository.GetAsync(id);
return ObjectMapper.Map<Blog, BlogDto>(blog);
}
[Authorize(BloggingAdminPermissions.Blogs.Create)]
public async Task<BlogDto> CreateAsync(CreateBlogDto input)
{
var newBlog = await _blogRepository.InsertAsync(new Blog(GuidGenerator.Create(), input.Name, input.ShortName)
{
Description = input.Description
});
return ObjectMapper.Map<Blog, BlogDto>(newBlog);
}
[Authorize(BloggingAdminPermissions.Blogs.Update)]
public async Task<BlogDto> UpdateAsync(Guid id, UpdateBlogDto input)
{
var blog = await _blogRepository.GetAsync(id);
blog.SetName(input.Name);
blog.SetShortName(input.ShortName);
blog.Description = input.Description;
return ObjectMapper.Map<Blog, BlogDto>(blog);
}
[Authorize(BloggingAdminPermissions.Blogs.Delete)]
public async Task DeleteAsync(Guid id)
{
await _blogRepository.DeleteAsync(id);
}
}
}

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Blogging.Admin.HttpApi.Client</AssemblyName>
<PackageId>Volo.Blogging.Admin.HttpApi.Client</PackageId>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Blogging.Admin.Application.Contracts\Volo.Blogging.Admin.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,19 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace Volo.Blogging.Admin
{
[DependsOn(
typeof(BloggingAdminApplicationContractsModule),
typeof(AbpHttpClientModule))]
public class BloggingAdminHttpApiClientModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddHttpClientProxies(typeof(BloggingAdminApplicationContractsModule).Assembly,
BloggingAdminRemoteServiceConsts.RemoteServiceName);
}
}
}

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyName>Volo.Blogging.Admin.HttpApi</AssemblyName>
<PackageId>Volo.Blogging.Admin.HttpApi</PackageId>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Blogging.Admin.Application.Contracts\Volo.Blogging.Admin.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,56 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Blogging.Admin.Blogs;
namespace Volo.Blogging.Admin
{
[RemoteService(Name = BloggingAdminRemoteServiceConsts.RemoteServiceName)]
[Area("bloggingAdmin")]
[Route("api/blogging/blogs/admin")]
public class BlogManagementController : AbpController, IBlogManagementAppService
{
private readonly IBlogManagementAppService _blogManagementAppService;
public BlogManagementController(IBlogManagementAppService blogManagementAppService)
{
_blogManagementAppService = blogManagementAppService;
}
[HttpGet]
public async Task<ListResultDto<BlogDto>> GetListAsync()
{
return await _blogManagementAppService.GetListAsync();
}
[HttpGet]
[Route("{id}")]
public async Task<BlogDto> GetAsync(Guid id)
{
return await _blogManagementAppService.GetAsync(id);
}
[HttpPost]
public async Task<BlogDto> CreateAsync(CreateBlogDto input)
{
return await _blogManagementAppService.CreateAsync(input);
}
[HttpPut]
[Route("{id}")]
public async Task<BlogDto> UpdateAsync(Guid id, UpdateBlogDto input)
{
return await _blogManagementAppService.UpdateAsync(id, input);
}
[HttpDelete]
[Route("{id}")]
public async Task DeleteAsync(Guid id)
{
await _blogManagementAppService.DeleteAsync(id);
}
}
}

@ -0,0 +1,33 @@
using Localization.Resources.AbpUi;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Blogging.Localization;
using Microsoft.Extensions.DependencyInjection;
namespace Volo.Blogging.Admin
{
[DependsOn(
typeof(BloggingAdminApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule))]
public class BloggingAdminHttpApiModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(BloggingAdminHttpApiModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<BloggingResource>()
.AddBaseTypes(typeof(AbpUiResource));
});
}
}
}

@ -0,0 +1,16 @@
using AutoMapper;
using Volo.Blogging.Admin.Blogs;
using Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs;
using EditModel = Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs.EditModel;
namespace Volo.Blogging.Admin
{
public class AbpBloggingAdminWebAutoMapperProfile : Profile
{
public AbpBloggingAdminWebAutoMapperProfile()
{
CreateMap<CreateModel.BlogCreateModalView, CreateBlogDto>();
CreateMap<BlogDto, EditModel.BlogEditViewModel>();
}
}
}

@ -1,13 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Volo.Abp.UI.Navigation;
using Volo.Blogging.Localization;
namespace Volo.Blogging
namespace Volo.Blogging.Admin
{
public class BloggingMenuContributor : IMenuContributor
public class BloggingAdminMenuContributor : IMenuContributor
{
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
@ -21,17 +18,17 @@ namespace Volo.Blogging
{
var l = context.GetLocalizer<BloggingResource>();
if (await context.IsGrantedAsync(BloggingPermissions.Blogs.Management))
if (await context.IsGrantedAsync(BloggingAdminPermissions.Blogs.Management))
{
var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"]);
//TODO: Using the same permission. Reconsider.
if (await context.IsGrantedAsync(BloggingPermissions.Blogs.Management))
if (await context.IsGrantedAsync(BloggingAdminPermissions.Blogs.Management))
{
managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Admin/Blogs"));
managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Blogging/Admin/Blogs"));
}
context.Menu.AddItem(managementRootMenuItem);
context.Menu.GetAdministration().AddItem(managementRootMenuItem);
}
}
}

@ -0,0 +1,53 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin
{
[DependsOn(
typeof(BloggingAdminHttpApiModule),
typeof(AbpAspNetCoreMvcUiBootstrapModule),
typeof(AbpAspNetCoreMvcUiBundlingModule),
typeof(AbpAutoMapperModule)
)]
public class BloggingAdminWebModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(typeof(BloggingResource), typeof(BloggingAdminWebModule).Assembly);
});
PreConfigure<IMvcBuilder>(mvcBuilder =>
{
mvcBuilder.AddApplicationPartIfNotExists(typeof(BloggingAdminWebModule).Assembly);
});
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new BloggingAdminMenuContributor());
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<BloggingAdminWebModule>("Volo.Blogging.Admin");
});
context.Services.AddAutoMapperObjectMapper<BloggingAdminWebModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpBloggingAdminWebAutoMapperProfile>(validate: true);
});
}
}
}

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

@ -1,7 +1,7 @@
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using Volo.Blogging.Pages.Blog
@model Volo.Blogging.Pages.Admin.Blogs.CreateModel
@inherits Volo.Blogging.Admin.Pages.Blogging.BloggingAdminPage
@model Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs.CreateModel
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Blogging.Localization
@inject IHtmlLocalizer<BloggingResource> L
@ -10,7 +10,7 @@
}
<abp-dynamic-form submit-button="false" abp-model="Blog" asp-page="/Admin/Blogs/Create">
<abp-dynamic-form submit-button="false" abp-model="Blog" asp-page="/Blogging/Admin/Blogs/Create">
<abp-modal size="@(AbpModalSize.Large)">
<abp-modal-header title="@L["Create"].Value"></abp-modal-header>
<abp-modal-body>

@ -2,23 +2,20 @@ using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Admin.Blogs;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
using Volo.Blogging.Pages.Blog;
namespace Volo.Blogging.Pages.Admin.Blogs
namespace Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs
{
public class CreateModel : BloggingPageModel
public class CreateModel : BloggingAdminPageModel
{
private readonly IBlogAppService _blogAppService;
private readonly IBlogManagementAppService _blogAppService;
private readonly IAuthorizationService _authorization;
[BindProperty]
public BlogCreateModalView Blog { get; set; } = new BlogCreateModalView();
public CreateModel(IBlogAppService blogAppService, IAuthorizationService authorization)
public CreateModel(IBlogManagementAppService blogAppService, IAuthorizationService authorization)
{
_blogAppService = blogAppService;
_authorization = authorization;
@ -26,7 +23,7 @@ namespace Volo.Blogging.Pages.Admin.Blogs
public virtual async Task<ActionResult> OnGetAsync()
{
if (!await _authorization.IsGrantedAsync(BloggingPermissions.Blogs.Create))
if (!await _authorization.IsGrantedAsync(BloggingAdminPermissions.Blogs.Create))
{
return Redirect("/");
}
@ -38,7 +35,7 @@ namespace Volo.Blogging.Pages.Admin.Blogs
{
var blogDto = ObjectMapper.Map<BlogCreateModalView, CreateBlogDto>(Blog);
await _blogAppService.Create(blogDto);
await _blogAppService.CreateAsync(blogDto);
return NoContent();
}
@ -59,4 +56,4 @@ namespace Volo.Blogging.Pages.Admin.Blogs
}
}
}
}

@ -1,7 +1,7 @@
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using Volo.Blogging.Pages.Blog
@model Volo.Blogging.Pages.Admin.Blogs.EditModel
@inherits Volo.Blogging.Admin.Pages.Blogging.BloggingAdminPage
@model Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs.EditModel
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Blogging.Localization
@inject IHtmlLocalizer<BloggingResource> L
@ -9,8 +9,7 @@
Layout = null;
}
<abp-dynamic-form abp-model="Blog" asp-page="/Admin/Blogs/Edit">
<abp-dynamic-form abp-model="Blog" asp-page="/Blogging/Admin/Blogs/Edit">
<abp-modal size="@(AbpModalSize.Large)">
<abp-modal-header title="@L["Edit"].Value"></abp-modal-header>
<abp-modal-body>

@ -1,20 +1,16 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Admin.Blogs;
using Volo.Blogging.Blogs;
using Volo.Blogging.Blogs.Dtos;
using Volo.Blogging.Pages.Blog;
using Volo.Blogging.Posts;
namespace Volo.Blogging.Pages.Admin.Blogs
namespace Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs
{
public class EditModel : BloggingPageModel
public class EditModel : BloggingAdminPageModel
{
private readonly IBlogAppService _blogAppService;
private readonly IBlogManagementAppService _blogAppService;
private readonly IAuthorizationService _authorization;
[BindProperty(SupportsGet = true)]
@ -23,7 +19,7 @@ namespace Volo.Blogging.Pages.Admin.Blogs
[BindProperty]
public BlogEditViewModel Blog { get; set; } = new BlogEditViewModel();
public EditModel(IBlogAppService blogAppService, IAuthorizationService authorization)
public EditModel(IBlogManagementAppService blogAppService, IAuthorizationService authorization)
{
_blogAppService = blogAppService;
_authorization = authorization;
@ -31,7 +27,7 @@ namespace Volo.Blogging.Pages.Admin.Blogs
public virtual async Task<ActionResult> OnGetAsync()
{
if (!await _authorization.IsGrantedAsync(BloggingPermissions.Blogs.Update))
if (!await _authorization.IsGrantedAsync(BloggingAdminPermissions.Blogs.Update))
{
return Redirect("/");
}
@ -45,7 +41,7 @@ namespace Volo.Blogging.Pages.Admin.Blogs
public virtual async Task<IActionResult> OnPostAsync()
{
await _blogAppService.Update(Blog.Id, new UpdateBlogDto()
await _blogAppService.UpdateAsync(Blog.Id, new UpdateBlogDto()
{
Name = Blog.Name,
ShortName = Blog.ShortName,
@ -74,5 +70,5 @@ namespace Volo.Blogging.Pages.Admin.Blogs
}
}
}
}

@ -1,10 +1,12 @@
@page
@using Microsoft.AspNetCore.Authorization
@using Volo.Blogging.Admin
@using Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs
@using Volo.Blogging
@using Volo.Blogging.Pages.Blog
@model Volo.Blogging.Pages.Admin.Blogs.IndexModel
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Blogging.Localization
@inherits Volo.Blogging.Admin.Pages.Blogging.BloggingAdminPage
@model IndexModel
@inject IHtmlLocalizer<BloggingResource> L
@inject IAuthorizationService Authorization
@{
@ -12,9 +14,11 @@
}
@section scripts {
<abp-script src="/Pages/Admin/Blogs/index.js" />
<abp-script src="/Pages/Admin/Blogs/create.js" />
<abp-script src="/Pages/Admin/Blogs/edit.js" />
<abp-script-bundle name="@typeof(IndexModel).FullName">
<abp-script src="/Pages/Blogging/Admin/Blogs/index.js" />
<abp-script src="/Pages/Blogging/Admin/Blogs/create.js" />
<abp-script src="/Pages/Blogging/Admin/Blogs/edit.js" />
</abp-script-bundle>
}
<abp-card>
@ -24,7 +28,7 @@
<h2>@L["Blogs"]</h2>
</abp-column>
<abp-column size-md="_6" class="text-right">
@if (await Authorization.IsGrantedAsync(BloggingPermissions.Blogs.Create))
@if (await Authorization.IsGrantedAsync(BloggingAdminPermissions.Blogs.Create))
{
<abp-button icon="plus" text="@L["CreateANewBlog"].Value" button-type="Primary" id="CreateNewBlogButtonId"></abp-button>
}

@ -1,12 +1,10 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Pages.Blog;
namespace Volo.Blogging.Pages.Admin.Blogs
namespace Volo.Blogging.Admin.Pages.Blogging.Admin.Blogs
{
public class IndexModel : BloggingPageModel
public class IndexModel : BloggingAdminPageModel
{
private readonly IAuthorizationService _authorization;
@ -17,7 +15,7 @@ namespace Volo.Blogging.Pages.Admin.Blogs
public virtual async Task<ActionResult> OnGetAsync()
{
if (!await _authorization.IsGrantedAsync(BloggingPermissions.Blogs.Management))
if (!await _authorization.IsGrantedAsync(BloggingAdminPermissions.Blogs.Management))
{
return Redirect("/");
}
@ -25,4 +23,4 @@ namespace Volo.Blogging.Pages.Admin.Blogs
return Page();
}
}
}
}

@ -1,8 +1,8 @@
$(function () {
var l = abp.localization.getResource('Blogging');
var _createModal = new abp.ModalManager(abp.appPath + 'Admin/Blogs/Create');
var _editModal = new abp.ModalManager(abp.appPath + 'Admin/Blogs/Edit');
var _createModal = new abp.ModalManager(abp.appPath + 'Blogging/Admin/Blogs/Create');
var _editModal = new abp.ModalManager(abp.appPath + 'Blogging/Admin/Blogs/Edit');
var _dataTable = $('#BlogsTable').DataTable(abp.libs.datatables.normalizeConfiguration({
processing: true,
@ -14,7 +14,7 @@
autoWidth: false,
scrollCollapse: true,
order: [[3, "desc"]],
ajax: abp.libs.datatables.createAjax(volo.blogging.blogs.getList),
ajax: abp.libs.datatables.createAjax(volo.blogging.admin.blogManagement.getList),
columnDefs: [
{
rowAction: {
@ -22,7 +22,7 @@
[
{
text: l('Edit'),
visible: abp.auth.isGranted('Blogging.Blog.Update'),
visible: abp.auth.isGranted('Blogging.Admin.Blog.Update'),
action: function (data) {
_editModal.open({
blogId: data.record.id
@ -31,10 +31,10 @@
},
{
text: l('Delete'),
visible: abp.auth.isGranted('Blogging.Blog.Delete'),
visible: abp.auth.isGranted('Blogging.Admin.Blog.Delete'),
confirmMessage: function (data) { return l('BlogDeletionWarningMessage') },
action: function (data) {
volo.blogging.blogs
volo.blogging.admin.blogManagement
.delete(data.record.id)
.then(function () {
_dataTable.ajax.reload();
@ -79,4 +79,4 @@
_dataTable.ajax.reload();
});
});
});

@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin.Pages.Blogging
{
public abstract class BloggingAdminPage : AbpPage
{
[RazorInject]
public IHtmlLocalizer<BloggingResource> L { get; set; }
public const string DefaultTitle = "Blogging";
public const int MaxShortContentLength = 200;
}
}

@ -0,0 +1,12 @@
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace Volo.Blogging.Admin.Pages
{
public abstract class BloggingAdminPageModel : AbpPageModel
{
public BloggingAdminPageModel()
{
ObjectMapperContext = typeof(BloggingAdminWebModule);
}
}
}

@ -0,0 +1,5 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
@addTagHelper *, Volo.Blogging.Web

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50000/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Blogging.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:50014/"
}
}
}

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyName>Volo.Blogging.Admin.Web</AssemblyName>
<PackageId>Volo.Blogging.Admin.Web</PackageId>
<TypeScriptToolsVersion>2.8</TypeScriptToolsVersion>
<OutputType>Library</OutputType>
<IsPackable>true</IsPackable>
<RootNamespace>Volo.Blogging.Admin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Packages\Volo.Abp.AspNetCore.Mvc.UI.Packages.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AspNetCore.Mvc.UI.Bundling\Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\Volo.Blogging.Admin.HttpApi\Volo.Blogging.Admin.HttpApi.csproj" />
<PackageReference Include="Markdig.Signed" Version="0.18.0" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Pages\**\*.js" />
<EmbeddedResource Include="Pages\**\*.css" />
<Content Remove="Pages\**\*.js" />
<Content Remove="Pages\**\*.css" />
<Content Remove="compilerconfig.json" />
<Content Remove="Properties\launchSettings.json" />
</ItemGroup>
</Project>

@ -0,0 +1,18 @@
[
{
"outputFile": "Pages/Blog/Shared/Styles/blog.css",
"inputFile": "Pages/Blog/Shared/Styles/blog.scss"
},
{
"outputFile": "Pages/Blog/Shared/Styles/_home.css",
"inputFile": "Pages/Blog/Shared/Styles/_home.scss"
},
{
"outputFile": "Pages/Blog/Posts/Index.css",
"inputFile": "Pages/Blog/Posts/Index.scss"
},
{
"outputFile": "Pages/Blogs/Shared/Styles/blog.css",
"inputFile": "Pages/Blogs/Shared/Styles/blog.scss"
}
]

@ -0,0 +1,49 @@
{
"compilers": {
"less": {
"autoPrefix": "",
"cssComb": "none",
"ieCompat": true,
"strictMath": false,
"strictUnits": false,
"relativeUrls": true,
"rootPath": "",
"sourceMapRoot": "",
"sourceMapBasePath": "",
"sourceMap": false
},
"sass": {
"includePath": "",
"indentType": "space",
"indentWidth": 2,
"outputStyle": "nested",
"Precision": 5,
"relativeUrls": true,
"sourceMapRoot": "",
"sourceMap": false
},
"stylus": {
"sourceMap": false
},
"babel": {
"sourceMap": false
},
"coffeescript": {
"bare": false,
"runtimeMode": "node",
"sourceMap": false
}
},
"minifiers": {
"css": {
"enabled": true,
"termSemicolons": true,
"gzip": false
},
"javascript": {
"enabled": true,
"termSemicolons": true,
"gzip": false
}
}
}

@ -10,12 +10,6 @@ namespace Volo.Blogging
{
var bloggingGroup = context.AddGroup(BloggingPermissions.GroupName, L("Permission:Blogging"));
var blogs = bloggingGroup.AddPermission(BloggingPermissions.Blogs.Default, L("Permission:Blogs"));
blogs.AddChild(BloggingPermissions.Blogs.Management, L("Permission:Management"));
blogs.AddChild(BloggingPermissions.Blogs.Update, L("Permission:Edit"));
blogs.AddChild(BloggingPermissions.Blogs.Delete, L("Permission:Delete"));
blogs.AddChild(BloggingPermissions.Blogs.Create, L("Permission:Create"));
var posts = bloggingGroup.AddPermission(BloggingPermissions.Posts.Default, L("Permission:Posts"));
posts.AddChild(BloggingPermissions.Posts.Update, L("Permission:Edit"));
posts.AddChild(BloggingPermissions.Posts.Delete, L("Permission:Delete"));

@ -6,15 +6,6 @@ namespace Volo.Blogging
{
public const string GroupName = "Blogging";
public static class Blogs
{
public const string Default = GroupName + ".Blog";
public const string Management = Default + ".Management";
public const string Delete = Default + ".Delete";
public const string Update = Default + ".Update";
public const string Create = Default + ".Create";
}
public static class Posts
{
public const string Default = GroupName + ".Post";

@ -13,11 +13,5 @@ namespace Volo.Blogging.Blogs
Task<BlogDto> GetByShortNameAsync(string shortName);
Task<BlogDto> GetAsync(Guid id);
Task<BlogDto> Create(CreateBlogDto input);
Task<BlogDto> Update(Guid id, UpdateBlogDto input);
Task Delete(Guid id);
}
}

@ -5,10 +5,6 @@
"Permission:Blogs": "Blogy",
"Permission:Posts": "Příspěvky",
"Permission:Tags": "Tagy",
"Permission:Comments": "Komentáře",
"Permission:Management": "Správa",
"Permission:Edit": "Upravit",
"Permission:Create": "Vytvořit",
"Permission:Delete": "Smazat"
"Permission:Comments": "Komentáře"
}
}

@ -3,12 +3,8 @@
"texts": {
"Permission:Blogging": "Blog",
"Permission:Blogs": "Blogs",
"Permission:Posts": "Beiträge",
"Permission:Posts": "Beitr<EFBFBD>ge",
"Permission:Tags": "Tags",
"Permission:Comments": "Kommentare",
"Permission:Management": "Verwaltung",
"Permission:Edit": "Bearbeiten",
"Permission:Create": "Erstellen",
"Permission:Delete": "Löschen"
"Permission:Comments": "Kommentare"
}
}
}

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

Loading…
Cancel
Save