@ -0,0 +1,321 @@ |
|||
# Integrating the Syncfusion MVC Components to the ABP MVC UI |
|||
|
|||
## Introduction |
|||
|
|||
In this article we will see how we can integrate the Syncfusion MVC Components into our ABP application. |
|||
|
|||
## Source Code |
|||
|
|||
You can find the source code of the application at https://github.com/EngincanV/ABP-Syncfusion-Components-Demo. |
|||
|
|||
## Prerequisites |
|||
|
|||
* [.NET 6](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) |
|||
|
|||
* In this article, we will create a new startup template in v5.0.0-rc.2 and if you follow this article from top to bottom and create a new startup template with me, you need to install the [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) before starting. |
|||
|
|||
**NOTE:** ABP v5.X stable version has been released. You can replace v5.0.0-rc.2 with the latest stable version in your steps. |
|||
|
|||
Also, you need to update your ABP CLI to the v5.0.0-rc.2, you can use the command below to update your CLI version: |
|||
|
|||
```bash |
|||
dotnet tool update Volo.Abp.Cli -g --version 5.0.0-rc.2 |
|||
``` |
|||
|
|||
or install it if you haven't installed it before: |
|||
|
|||
```bash |
|||
dotnet tool install Volo.Abp.Cli -g --version 5.0.0-rc.2 |
|||
``` |
|||
|
|||
## Creating the Solution |
|||
|
|||
In this article, we will create a new startup template with EF Core as a database provider and MVC for the UI framework. But if you already have a project with MVC UI, you don't need to create a new startup template, you can directly implement the following steps to your existing project. |
|||
|
|||
> If you already have a project with MVC/Razor Pages UI, you can skip this section. |
|||
|
|||
We can create a new startup template by using the [ABP CLI](https://docs.abp.io/en/abp/latest/CLI): |
|||
|
|||
```bash |
|||
abp new SyncfusionComponentsDemo -t app --preview |
|||
``` |
|||
|
|||
Our project boilerplate will be ready after the download is finished. Then, we can open the solution and start developing. |
|||
|
|||
## Starting the Development |
|||
|
|||
### Pre-requisite |
|||
|
|||
> If you've already had a license from Syncfusion, you can skip this section. |
|||
|
|||
* The first thing we need to do is create an account to be able to get a license from Syncfusion. |
|||
|
|||
* So, let's navigate to https://www.syncfusion.com/aspnet-core-ui-controls and click the "Download Free Trial" button. |
|||
|
|||
* Then fill the form and start your 30-day free trial. |
|||
|
|||
* After that, navigate to https://www.syncfusion.com/account/manage-trials/downloads to get our license key that will be used in our application. |
|||
|
|||
 |
|||
|
|||
Click the "Get License Key" link for "ASP.NET Core (Essential JS 2)". |
|||
|
|||
 |
|||
|
|||
Then a modal will be opened like in the above image, select a version and click the "Get License Key" button. |
|||
|
|||
 |
|||
|
|||
Lastly, copy the generated license key value. |
|||
|
|||
In order to use the relevant components, Syncfusion needs to check this license key to know that our license is valid. |
|||
|
|||
### Configurations |
|||
|
|||
After providing a license key from Syncfusion, we can start with the configuration that needs to be done in our application. |
|||
|
|||
#### 1-) Install the Syncfusion.EJ2.AspNet.Core package |
|||
|
|||
We need to install the `Syncfusion.EJ2.AspNet.Core` Nuget package to our Web project (*.Web). |
|||
|
|||
We can install it via **Visual Studio's Nuget Package Manager**: |
|||
|
|||
 |
|||
|
|||
or via dotnet cli: |
|||
|
|||
```bash |
|||
dotnet add package Syncfusion.EJ2.AspNet.Core --version 19.3.0.57 |
|||
``` |
|||
|
|||
> In this article, I've used the package in version 19.3.0.57. |
|||
|
|||
#### 2-) Register the License Key |
|||
|
|||
* After installing the package, we need to register our license key to be able to use the Syncfusion Components. |
|||
|
|||
* To register the license key, open your web module class and update the `ConfigureServices` method as follows: |
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
//Register Syncfusion license |
|||
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(licenseKey: configuration["Syncfusion:LicenseKey"].ToString()); |
|||
|
|||
ConfigureUrls(configuration); |
|||
ConfigureBundles(); |
|||
ConfigureAuthentication(context, configuration); |
|||
ConfigureAutoMapper(); |
|||
ConfigureVirtualFileSystem(hostingEnvironment); |
|||
ConfigureLocalizationServices(); |
|||
ConfigureNavigationServices(); |
|||
ConfigureAutoApiControllers(); |
|||
ConfigureSwaggerServices(context.Services); |
|||
} |
|||
``` |
|||
|
|||
Instead of writing the license key directly in here we can define it in the **appsettings.json** file and use it here by using the Configuration system of .NET. |
|||
|
|||
|
|||
* Open your **appsettings.json** file and add a new section named "Syncfusion" as below: |
|||
|
|||
```json |
|||
{ |
|||
//... |
|||
|
|||
"Syncfusion": { |
|||
"LicenseKey": "<your-license-key>" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
> Replace the `<your-license-key> part with your license key that we've obtained in the previous section.` |
|||
|
|||
* To be able to use the Syncfusion Components we need to define them in our **_ViewImports.cshtml** file. By doing that we can use the Syncfusion components everywhere in our application. |
|||
|
|||
* Open your **/Pages/_ViewImports.cshtml** file and add a new tag helper: |
|||
|
|||
```cshtml |
|||
@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 *, Syncfusion.EJ2 //use Syncfusion components |
|||
``` |
|||
|
|||
#### 3-) Adding Syncfusion styles and scripts to our application |
|||
|
|||
Firstly, let's install the `@syncfusion/ej2` package from **npm**. |
|||
|
|||
* Open your **package.json** file and add the `@syncfusion/ej2` package with version **19.3.57**: |
|||
|
|||
```json |
|||
{ |
|||
"version": "1.0.0", |
|||
"name": "my-app", |
|||
"private": true, |
|||
"dependencies": { |
|||
"@abp/aspnetcore.mvc.ui.theme.basic": "^5.0.0-rc.2", |
|||
"@syncfusion/ej2": "^19.3.57" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
* Then, open the **abp.resourcemapping.js** file and update the **mappings** section: |
|||
|
|||
```js |
|||
module.exports = { |
|||
aliases: { |
|||
|
|||
}, |
|||
mappings: { |
|||
"@node_modules/@syncfusion/ej2/dist/ej2.min.js": "@libs/syncfusion/", |
|||
"@node_modules/@syncfusion/ej2/material.css": "@libs/syncfusion/" |
|||
} |
|||
}; |
|||
``` |
|||
|
|||
> ABP copies related packages from **node_modules** folder to the **libs** folder by examining this file. You can read this [document](docs.abp.io/en/abp/latest/UI/AspNetCore/Client-Side-Package-Management#mapping-the-library-resources) for more info. |
|||
|
|||
* Then run the `abp install-libs` to install the dependencies and copy them into the libs folder by your mappings configuration. After running this command, in your **libs** folder it should be a folder named **syncfusion** folder. |
|||
|
|||
 |
|||
|
|||
The last thing we need to do is, add some style and script files provided by Syncfusion, between our head-body tags. |
|||
|
|||
* We can do this by creating two view components (one for Styles and the other for Scripts). Let's do that. |
|||
|
|||
First, create a folder structure as shown below under the **Components** folder. |
|||
|
|||
 |
|||
|
|||
Then open the related files and add the following codes to each of these files. |
|||
|
|||
* **Default.cshtml** (/Components/Syncfusion/Script/Default.cshtml) |
|||
|
|||
```cshtml |
|||
@addTagHelper *, Syncfusion.EJ2 //add this line |
|||
|
|||
<!-- Syncfusion Essential JS 2 Scripts --> |
|||
<script src="/libs/syncfusion/ej2.min.js"></script> |
|||
|
|||
<!-- Syncfusion Essential JS 2 ScriptManager --> |
|||
<ejs-scripts></ejs-scripts> |
|||
``` |
|||
|
|||
* **SyncfusionScriptComponent.cs** |
|||
|
|||
```csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace SyncfusionComponentsDemo.Web.Components.Syncfusion.Script |
|||
{ |
|||
public class SyncfusionScriptComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View("~/Components/Syncfusion/Script/Default.cshtml"); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
* **Default.cshtml** (/Components/Syncfusion/Style/Default.cshtml) |
|||
|
|||
```cshtml |
|||
<!-- Syncfusion Essential JS 2 Styles --> |
|||
<link rel="stylesheet" href="/libs/syncfusion/material.css"> |
|||
``` |
|||
|
|||
* SyncfusionStyleComponent.cs |
|||
|
|||
```csharp |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace SyncfusionComponentsDemo.Web.Components.Syncfusion.Style |
|||
{ |
|||
public class SyncfusionStyleComponent : AbpViewComponent |
|||
{ |
|||
public IViewComponentResult Invoke() |
|||
{ |
|||
return View("~/Components/Syncfusion/Style/Default.cshtml"); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
After creating these two components, we can use the [**Layout Hooks**](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Layout-Hooks) system of ABP to inject these two components between head and script tags. |
|||
|
|||
To do this, open your web module class and update the `ConfigureServices` method as below: |
|||
|
|||
|
|||
```csharp |
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
|||
var configuration = context.Services.GetConfiguration(); |
|||
|
|||
//Register Syncfusion license |
|||
var licenseKey = configuration["Syncfusion:LicenseKey"].ToString(); |
|||
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(licenseKey: licenseKey); |
|||
|
|||
Configure<AbpLayoutHookOptions>(options => |
|||
{ |
|||
//Now, the SyncfusionStyleComponent code will be inserted in the head of the page as the last item. |
|||
options.Add(LayoutHooks.Head.Last, typeof(SyncfusionStyleComponent)); |
|||
|
|||
//the SyncfusionScriptComponent will be inserted in the body of the page as the last item. |
|||
options.Add(LayoutHooks.Body.Last, typeof(SyncfusionScriptComponent)); |
|||
}); |
|||
|
|||
ConfigureUrls(configuration); |
|||
ConfigureBundles(); |
|||
ConfigureAuthentication(context, configuration); |
|||
ConfigureAutoMapper(); |
|||
ConfigureVirtualFileSystem(hostingEnvironment); |
|||
ConfigureLocalizationServices(); |
|||
ConfigureNavigationServices(); |
|||
ConfigureAutoApiControllers(); |
|||
ConfigureSwaggerServices(context.Services); |
|||
} |
|||
``` |
|||
|
|||
After injecting the Syncfusion style and script into our application, our configurations have been completed. We can try with a simple component to see if it works as we expected. |
|||
|
|||
* Let's try with the [Calendar](https://www.syncfusion.com/aspnet-core-ui-controls/calendar) component. Open your **Index.cshtml** file and update with the below content: |
|||
|
|||
```cshtml |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using SyncfusionComponentsDemo.Localization |
|||
@using Volo.Abp.Users |
|||
@model SyncfusionComponentsDemo.Web.Pages.IndexModel |
|||
|
|||
@section styles { |
|||
<abp-style src="/Pages/Index.css" /> |
|||
} |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/Index.js" /> |
|||
} |
|||
|
|||
<div class="container"> |
|||
<h2>Syncfusion - Calendar Component</h2> |
|||
<ejs-calendar id="calendar"></ejs-calendar> |
|||
</div> |
|||
``` |
|||
|
|||
* Then when we run the application, we need to see the relevant calendar component as below. |
|||
|
|||
 |
|||
|
|||
### Conclusion |
|||
|
|||
In this article, we've explained how to integrate the **Syncfusion Components** into our applications. After following this article, you can use the Syncfusion components in your application. |
|||
|
|||
Thanks for reading the article, I hope you've found it useful :) |
|||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 76 KiB |
@ -1 +1,173 @@ |
|||
TODO... |
|||
# 身份服务器模块 |
|||
|
|||
身份服务器模块提供了一个 [IdentityServer](https://github.com/IdentityServer/IdentityServer4) (IDS) 的完全集成,该框架提供高级身份验证功能,如单点登录和API访问控制.此模块将客户端,资源以及其他 IDS 相关的对象保存到数据库中. |
|||
|
|||
## 如何安装 |
|||
|
|||
当你使用 ABP 框架 [创建一个新的解决方案](https://abp.io/get-started) 时,此模块将被预安装(作为 NuGet/NPM 包).你可以继续用其作为包并轻松地获取更新,也可以将其源代码包含在解决方案中(请参阅 `get-source` [CLI](../CLI.md))以开发自定义模块. |
|||
|
|||
### 源代码 |
|||
|
|||
可以 [在此处](https://github.com/abpframework/abp/tree/dev/modules/identityserver) 访问源代码.源代码使用 [MIT](https://choosealicense.com/licenses/mit/) 许可,所以你可以免费使用和自定义它. |
|||
|
|||
## 用户界面 |
|||
|
|||
此模块使用了领域逻辑和数据库集成,但没有提供任何 UI.如果你需要动态添加客户端和资源, 管理 UI 是非常有用的.在这种情况下,你可以自己构建管理 UI,或者考虑购买为此模块提供了管理 UI 的 [ABP 商业版](https://commercial.abp.io/). |
|||
|
|||
## 与其他模块的关系 |
|||
|
|||
此模块基于 [身份模块](Identity.md) 并且[账户模块](Account.md) 有一个 [集成包](https://www.nuget.org/packages/Volo.Abp.Account.Web.IdentityServer). |
|||
|
|||
## 选项 |
|||
|
|||
### AbpIdentityServerBuilderOptions |
|||
|
|||
`AbpIdentityServerBuilderOptions` 在你的身份服务器 [模块](https://docs.abp.io/en/abp/latest/Module-Development-Basics) 中的 `PreConfigureServices` 方法中配置.例如: |
|||
|
|||
````csharp |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<AbpIdentityServerBuilderOptions>(builder => |
|||
{ |
|||
//Set options here... |
|||
}); |
|||
} |
|||
```` |
|||
|
|||
`AbpIdentityServerBuilderOptions` 属性: |
|||
|
|||
* `UpdateJwtSecurityTokenHandlerDefaultInboundClaimTypeMap` (默认值:true):更新 `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap` 使其与身份服务器声明兼容. |
|||
* `UpdateAbpClaimTypes` (默认值:true):更新 `AbpClaimTypes` 与身份服务器声明兼容. |
|||
* `IntegrateToAspNetIdentity` (默认值:true):集成到 ASP.NET Identity. |
|||
* `AddDeveloperSigningCredential` (默认值:true):设置为 false 禁止调用 IIdentityServerBuilder 中的 `AddDeveloperSigningCredential()`. |
|||
|
|||
`IIdentityServerBuilder` 可以在你的身份服务器 [模块](https://docs.abp.io/en/abp/latest/Module-Development-Basics) 中的 `PreConfigureServices` 方法中配置.例如: |
|||
|
|||
````csharp |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IIdentityServerBuilder>(builder => |
|||
{ |
|||
builder.AddSigningCredential(...); |
|||
}); |
|||
} |
|||
```` |
|||
|
|||
## 内部结构 |
|||
|
|||
### 领域层 |
|||
|
|||
#### 聚合 |
|||
|
|||
##### API 资源 |
|||
|
|||
需要 API 资源来允许客户端请求访问令牌. |
|||
|
|||
* `ApiResource` (聚合根):表示系统中的 API 资源. |
|||
* `ApiSecret` (集合):API 资源的密钥. |
|||
* `ApiScope` (集合):API 资源的作用域. |
|||
* `ApiResourceClaim` (集合):API 资源的声明. |
|||
|
|||
##### 客户端 |
|||
|
|||
客户端表示可以从你的身份服务器请求令牌的应用程序. |
|||
|
|||
* `Client` (聚合根):表示一个身份服务器的客户端应用程序. |
|||
* `ClientScope` (集合):客户端的作用域. |
|||
* `ClientSecret` (集合):客户端的密钥. |
|||
* `ClientGrantType` (集合):客户端的授权类型. |
|||
* `ClientCorsOrigin` (集合):客户端的 CORS 源. |
|||
* `ClientRedirectUri` (集合):客户端的重定向 URIs. |
|||
* `ClientPostLogoutRedirectUri` (集合):客户端的登出重定向 URIs. |
|||
* `ClientIdPRestriction` (集合):客户端的提供程序约束. |
|||
* `ClientClaim` (集合):客户端的声明. |
|||
* `ClientProperty` (集合):客户端的自定义属性. |
|||
|
|||
##### 持续化授权 |
|||
|
|||
持续化授权存储了授权码,刷新令牌和用户准许. |
|||
|
|||
* `PersistedGrant` (聚合根):表示为身份服务器持续化授权. |
|||
|
|||
##### 身份资源 |
|||
|
|||
身份资源是用户的用户 ID ,名称或邮件地址等数据. |
|||
|
|||
* `IdentityResource` (聚合根):表示与身份服务器的身份资源. |
|||
* `IdentityClaim` (集合):身份资源的声明. |
|||
|
|||
#### 仓储 |
|||
|
|||
为此模块定义了以下自定义仓储: |
|||
|
|||
* `IApiResourceRepository` |
|||
* `IClientRepository` |
|||
* `IPersistentGrantRepository` |
|||
* `IIdentityResourceRepository` |
|||
|
|||
#### 领域服务 |
|||
|
|||
此模块不包含任何领域服务,但重写了下面的服务; |
|||
|
|||
* `AbpProfileService` (当 `AbpIdentityServerBuilderOptions.IntegrateToAspNetIdentity` 为 true 时使用) |
|||
* `AbpClaimsService` |
|||
* `AbpCorsPolicyService` |
|||
|
|||
### 设置 |
|||
|
|||
此模块未定义任何设置. |
|||
|
|||
### 应用层 |
|||
|
|||
#### 应用服务 |
|||
|
|||
* `ApiResourceAppService` (实现 `IApiResourceAppService`):实现了 API 资源管理 UI 的用例. |
|||
* `IdentityServerClaimTypeAppService` (实现 `IIdentityServerClaimTypeAppService`):用于获取声明列表. |
|||
* `ApiResourceAppService` (实现 `IApiResourceAppService`):实现了 API 管理资源 UI 的用例. |
|||
* `IdentityResourceAppService` (实现 `IIdentityResourceAppService`):实现了身份资源管理 UI 的用例. |
|||
|
|||
### 数据库提供程序 |
|||
|
|||
#### 公共 |
|||
|
|||
##### 表/集合 前缀 & 架构 |
|||
|
|||
所有表/集合都使用 `IdentityServer` 作为默认前缀.如果你需要改变表的前缀或设置一个架构名称(如果你的数据库提供程序支持),请设置 `AbpIdentityServerDbProperties` 类的静态属性. |
|||
|
|||
##### 连接字符串 |
|||
|
|||
此模块使用 `AbpIdentityServer` 作为连接字符串的名称.如果你没有用这个名称定义连接字符串,它将回退到 `Default` 连接字符串. |
|||
|
|||
有关详细信息,请参阅 [连接字符串](https://docs.abp.io/en/abp/latest/Connection-Strings) 文档. |
|||
|
|||
#### EF Core |
|||
|
|||
##### 表 |
|||
|
|||
* **IdentityServerApiResources** |
|||
* IdentityServerApiSecrets |
|||
* IdentityServerApiScopes |
|||
* IdentityServerApiScopeClaims |
|||
* IdentityServerApiClaims |
|||
* **IdentityServerClients** |
|||
* IdentityServerClientScopes |
|||
* IdentityServerClientSecrets |
|||
* IdentityServerClientGrantTypes |
|||
* IdentityServerClientCorsOrigins |
|||
* IdentityServerClientRedirectUris |
|||
* IdentityServerClientPostLogoutRedirectUris |
|||
* IdentityServerClientIdPRestrictions |
|||
* IdentityServerClientClaims |
|||
* IdentityServerClientProperties |
|||
* **IdentityServerPersistedGrants** |
|||
* **IdentityServerIdentityResources** |
|||
* IdentityServerIdentityClaims |
|||
|
|||
#### MongoDB |
|||
|
|||
##### 集合 |
|||
|
|||
* **IdentityServerApiResources** |
|||
* **IdentityServerClients** |
|||
* **IdentityServerPersistedGrants** |
|||
* **IdentityServerIdentityResources** |
|||
|
|||
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,112 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Microsoft.AspNetCore.Hosting.Server; |
|||
using Microsoft.AspNetCore.Routing; |
|||
using Microsoft.AspNetCore.TestHost; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.AspNetCore.TestBase; |
|||
|
|||
public class AbpAspNetCoreAsyncIntegratedTestBase<TModule> |
|||
where TModule : IAbpModule |
|||
{ |
|||
protected WebApplication WebApplication { get; set; } |
|||
|
|||
protected TestServer Server { get; set; } |
|||
|
|||
protected HttpClient Client { get; set; } |
|||
|
|||
protected IServiceProvider ServiceProvider { get; set; } |
|||
|
|||
protected virtual T GetService<T>() |
|||
{ |
|||
return ServiceProvider.GetService<T>(); |
|||
} |
|||
|
|||
protected virtual T GetRequiredService<T>() |
|||
{ |
|||
return ServiceProvider.GetRequiredService<T>(); |
|||
} |
|||
|
|||
public virtual async Task InitializeAsync() |
|||
{ |
|||
var builder = WebApplication.CreateBuilder(); |
|||
builder.Host.ConfigureServices(services => |
|||
{ |
|||
services.AddSingleton<IHostLifetime, TestNoopHostLifetime>(); |
|||
services.AddSingleton<IServer, TestServer>(); |
|||
}) |
|||
.UseAutofac(); |
|||
|
|||
await builder.Services.AddApplicationAsync<TModule>(options => |
|||
{ |
|||
options.Services.ReplaceConfiguration(builder.Configuration); |
|||
}); |
|||
|
|||
await ConfigureServicesAsync(builder.Services); |
|||
WebApplication = builder.Build(); |
|||
await WebApplication.InitializeApplicationAsync(); |
|||
await WebApplication.StartAsync(); |
|||
|
|||
Server = WebApplication.Services.GetRequiredService<IHost>().GetTestServer(); |
|||
Client = Server.CreateClient(); |
|||
|
|||
ServiceProvider = Server.Services; |
|||
ServiceProvider.GetRequiredService<ITestServerAccessor>().Server = Server; |
|||
} |
|||
|
|||
public virtual async Task DisposeAsync() |
|||
{ |
|||
await WebApplication.DisposeAsync(); |
|||
} |
|||
|
|||
protected virtual Task ConfigureServicesAsync(IServiceCollection services) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
#region GetUrl
|
|||
|
|||
/// <summary>
|
|||
/// Gets default URL for given controller type.
|
|||
/// </summary>
|
|||
/// <typeparam name="TController">The type of the controller.</typeparam>
|
|||
protected virtual string GetUrl<TController>() |
|||
{ |
|||
return "/" + typeof(TController).Name.RemovePostFix("Controller", "AppService", "ApplicationService", "Service"); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets default URL for given controller type's given action.
|
|||
/// </summary>
|
|||
/// <typeparam name="TController">The type of the controller.</typeparam>
|
|||
protected virtual string GetUrl<TController>(string actionName) |
|||
{ |
|||
return GetUrl<TController>() + "/" + actionName; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets default URL for given controller type's given action with query string parameters (as anonymous object).
|
|||
/// </summary>
|
|||
/// <typeparam name="TController">The type of the controller.</typeparam>
|
|||
protected virtual string GetUrl<TController>(string actionName, object queryStringParamsAsAnonymousObject) |
|||
{ |
|||
var url = GetUrl<TController>(actionName); |
|||
|
|||
var dictionary = new RouteValueDictionary(queryStringParamsAsAnonymousObject); |
|||
if (dictionary.Any()) |
|||
{ |
|||
url += "?" + dictionary.Select(d => $"{d.Key}={d.Value}").JoinAsString("&"); |
|||
} |
|||
|
|||
return url; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Hosting; |
|||
|
|||
namespace Volo.Abp.AspNetCore.TestBase; |
|||
|
|||
public class TestNoopHostLifetime : IHostLifetime |
|||
{ |
|||
public Task StopAsync(CancellationToken cancellationToken) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public Task WaitForStartAsync(CancellationToken cancellationToken) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using Microsoft.AspNetCore.Hosting; |
|||
using Microsoft.Extensions.FileProviders; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection; |
|||
|
|||
internal class EmptyHostingEnvironment : IWebHostEnvironment |
|||
{ |
|||
public string EnvironmentName { get; set; } |
|||
|
|||
public string ApplicationName { get; set; } |
|||
|
|||
public string WebRootPath { get; set; } |
|||
|
|||
public IFileProvider WebRootFileProvider { get; set; } |
|||
|
|||
public string ContentRootPath { get; set; } |
|||
|
|||
public IFileProvider ContentRootFileProvider { get; set; } |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.AspNetCore.Builder; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Microsoft.Extensions.DependencyInjection; |
|||
|
|||
public static class WebApplicationBuilderExtensions |
|||
{ |
|||
public async static Task<IAbpApplicationWithExternalServiceProvider> AddApplicationAsync<TStartupModule>( |
|||
[NotNull] this WebApplicationBuilder builder, |
|||
[CanBeNull] Action<AbpApplicationCreationOptions> optionsAction = null) |
|||
where TStartupModule : IAbpModule |
|||
{ |
|||
return await builder.Services.AddApplicationAsync<TStartupModule>(options => |
|||
{ |
|||
options.Services.ReplaceConfiguration(builder.Configuration); |
|||
optionsAction?.Invoke(options); |
|||
}); |
|||
} |
|||
|
|||
public async static Task<IAbpApplicationWithExternalServiceProvider> AddApplicationAsync( |
|||
[NotNull] this WebApplicationBuilder builder, |
|||
[NotNull] Type startupModuleType, |
|||
[CanBeNull] Action<AbpApplicationCreationOptions> optionsAction = null) |
|||
{ |
|||
return await builder.Services.AddApplicationAsync(startupModuleType, options => |
|||
{ |
|||
options.Services.ReplaceConfiguration(builder.Configuration); |
|||
optionsAction?.Invoke(options); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Cli.Args; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands; |
|||
|
|||
public class CleanCommand : IConsoleCommand, ITransientDependency |
|||
{ |
|||
public const string Name = "clean"; |
|||
|
|||
public ILogger<CleanCommand> Logger { get; set; } |
|||
|
|||
public CleanCommand() |
|||
{ |
|||
Logger = NullLogger<CleanCommand>.Instance; |
|||
} |
|||
|
|||
public Task ExecuteAsync(CommandLineArgs commandLineArgs) |
|||
{ |
|||
var binEntries = Directory.EnumerateDirectories(Directory.GetCurrentDirectory(), "bin", SearchOption.AllDirectories); |
|||
var objEntries = Directory.EnumerateDirectories(Directory.GetCurrentDirectory(), "obj", SearchOption.AllDirectories); |
|||
|
|||
foreach (var path in binEntries.Concat(objEntries)) |
|||
{ |
|||
if (path.IndexOf("node_modules", StringComparison.OrdinalIgnoreCase) > 0) |
|||
{ |
|||
Logger.LogInformation($"Skipping: {path}"); |
|||
} |
|||
else |
|||
{ |
|||
Logger.LogInformation($"Deleting: {path}"); |
|||
Directory.Delete(path, true); |
|||
} |
|||
} |
|||
|
|||
Logger.LogInformation($"BIN and OBJ folders have been successfully deleted!"); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public string GetUsageInfo() |
|||
{ |
|||
var sb = new StringBuilder(); |
|||
|
|||
sb.AppendLine(""); |
|||
sb.AppendLine("Usage:"); |
|||
sb.AppendLine(" abp clean"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); |
|||
|
|||
return sb.ToString(); |
|||
} |
|||
|
|||
public string GetShortDescription() |
|||
{ |
|||
return "Delete all BIN and OBJ folders in current folder."; |
|||
} |
|||
} |
|||
@ -1,8 +1,11 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp; |
|||
|
|||
public interface IOnApplicationInitialization |
|||
{ |
|||
Task OnApplicationInitializationAsync([NotNull] ApplicationInitializationContext context); |
|||
|
|||
void OnApplicationInitialization([NotNull] ApplicationInitializationContext context); |
|||
} |
|||
|
|||
@ -1,8 +1,11 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp; |
|||
|
|||
public interface IOnApplicationShutdown |
|||
{ |
|||
Task OnApplicationShutdownAsync([NotNull] ApplicationShutdownContext context); |
|||
|
|||
void OnApplicationShutdown([NotNull] ApplicationShutdownContext context); |
|||
} |
|||
|
|||
@ -1,6 +1,10 @@ |
|||
namespace Volo.Abp.Modularity; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IAbpModule |
|||
{ |
|||
Task ConfigureServicesAsync(ServiceConfigurationContext context); |
|||
|
|||
void ConfigureServices(ServiceConfigurationContext context); |
|||
} |
|||
|
|||
@ -1,11 +1,16 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IModuleLifecycleContributor : ITransientDependency |
|||
{ |
|||
Task InitializeAsync([NotNull] ApplicationInitializationContext context, [NotNull] IAbpModule module); |
|||
|
|||
void Initialize([NotNull] ApplicationInitializationContext context, [NotNull] IAbpModule module); |
|||
|
|||
Task ShutdownAsync([NotNull] ApplicationShutdownContext context, [NotNull] IAbpModule module); |
|||
|
|||
void Shutdown([NotNull] ApplicationShutdownContext context, [NotNull] IAbpModule module); |
|||
} |
|||
|
|||
@ -1,10 +1,15 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IModuleManager |
|||
{ |
|||
Task InitializeModulesAsync([NotNull] ApplicationInitializationContext context); |
|||
|
|||
void InitializeModules([NotNull] ApplicationInitializationContext context); |
|||
|
|||
Task ShutdownModulesAsync([NotNull] ApplicationShutdownContext context); |
|||
|
|||
void ShutdownModules([NotNull] ApplicationShutdownContext context); |
|||
} |
|||
|
|||
@ -1,8 +1,11 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IOnPostApplicationInitialization |
|||
{ |
|||
Task OnPostApplicationInitializationAsync([NotNull] ApplicationInitializationContext context); |
|||
|
|||
void OnPostApplicationInitialization([NotNull] ApplicationInitializationContext context); |
|||
} |
|||
|
|||
@ -1,8 +1,11 @@ |
|||
using JetBrains.Annotations; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IOnPreApplicationInitialization |
|||
{ |
|||
Task OnPreApplicationInitializationAsync([NotNull] ApplicationInitializationContext context); |
|||
|
|||
void OnPreApplicationInitialization([NotNull] ApplicationInitializationContext context); |
|||
} |
|||
|
|||
@ -1,8 +1,10 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IPostConfigureServices |
|||
{ |
|||
Task PostConfigureServicesAsync(ServiceConfigurationContext context); |
|||
|
|||
void PostConfigureServices(ServiceConfigurationContext context); |
|||
} |
|||
|
|||
@ -1,8 +1,10 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Modularity; |
|||
|
|||
public interface IPreConfigureServices |
|||
{ |
|||
Task PreConfigureServicesAsync(ServiceConfigurationContext context); |
|||
|
|||
void PreConfigureServices(ServiceConfigurationContext context); |
|||
} |
|||
|
|||