Merge branch 'dev' into new-hosting-model

pull/10928/head
Halil İbrahim Kalkan 4 years ago
commit ae10538981

@ -29,6 +29,7 @@ Here, the list of all available commands before explaining their details:
* **`help`**: Shows help on the usage of the ABP CLI.
* **`new`**: Generates a new solution based on the ABP [startup templates](Startup-Templates/Index.md).
* **`update`**: Automatically updates all ABP related NuGet and NPM packages in a solution.
* **`clean`**: Deletes all `BIN` and `OBJ` folders in the current folder.
* **`add-package`**: Adds an ABP package to a project.
* **`add-module`**: Adds a [multi-package application module](https://docs.abp.io/en/abp/latest/Modules/Index) to a solution.
* **`list-modules`**: Lists names of open-source application modules.
@ -145,6 +146,17 @@ abp update [options]
* `--check-all`: Check the new version of each package separately. Default is `false`.
* `--version` or `-v`: Specifies the version to use for update. If not specified, latest version is used.
### clean
Deletes all `BIN` and `OBJ` folders in the current folder.
Usage:
````bash
abp clean
````
### add-package
Adds an ABP package to a project by,

@ -1,6 +1,6 @@
# ABP Documentation
ABP Framework is a complete **infrastructure** based on the **ASP.NET Core** to create **modern web applications** and **APIs** by following the software development **best practices** and the **latest technologies**.
ABP Framework offers an **opinionated architecture** to build enterprise software solutions with **best practices** on top of the **.NET** and the **ASP.NET Core** platforms. It provides the fundamental infrastructure, production-ready startup templates, modules, themes, tooling, guides and documentation to implement that architecture properly and **automate the details** and repetitive works as much as possible.
## Getting Started
@ -56,13 +56,23 @@ See the [Application Modules](Modules/Index.md) document for all pre-built modul
The [Startup templates](Startup-Templates/Index.md) are pre-built Visual Studio solution templates. You can create your own solution based on these templates to **immediately start your development**.
## Free E-Book: Implementing Domain Driven Design
## Books
### Mastering ABP Framework
![abp-book](images/abp-book.png)
*Mastering ABP Framework* is an ultimate guide to get started and expertise with the ABP Framework. It is authored by Halil İbrahim Kalkan, the creator and the lead developer of the ABP Framework.
**[You can order it from Amazon now](https://www.amazon.com/Mastering-ABP-Framework-maintainable-implementing-dp-1801079242/dp/1801079242)!**
### Free E-Book: Implementing Domain Driven Design
![Implementing Domain Driven Design](images/implementing-domain-driven-design-book.png)
A **practical guide** for implementing Domain Driven Design (DDD). While the implementation details are **based on the ABP Framework** infrastructure, the basic concepts, principles and models can be applied to any solution, even if it is not a .NET solution.
[Click here to get your free copy](https://abp.io/books/implementing-domain-driven-design?ref=doc).
**[Click here to get your free copy](https://abp.io/books/implementing-domain-driven-design?ref=doc).**
## ABP Community

@ -4,4 +4,16 @@
## Upgrading to the latest Blazorise
ABP 5.0 uses the latest version of the [Blazorise](https://blazorise.com/) library. Please upgrade the Blazorise NuGet packages in your solution.
ABP 5.0 uses the latest version of the [Blazorise](https://blazorise.com/) library. Please upgrade the Blazorise NuGet packages in your solution.
## Bootstrap 5
ABP 5.0 now works with Bootstrap 5. For details, please refer to the official [migration guide](https://getbootstrap.com/docs/5.0/migration/) provided by Bootstrap.
Replace `Blazorise.Bootstrap` with `Blazorise.Bootstrap5` package.
Replace `AddBootstrapProviders()` with `AddBootstrap5Providers()`.
## Update Bundle
Use `abp bundle` command to update bundles if you are using Blazor WebAssembly.

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

@ -29,6 +29,7 @@ dotnet tool update -g Volo.Abp.Cli
* **`help`**: 展示ABP CLI的用法帮助信息.
* **`new`**生成基于ABP的[启动模板](Startup-Templates/Index.md).
* **`update`**自动更新的ABP解决方案ABP相关的NuGet和NPM包.
* **`clean`**: 删除当前目录下所有的 `BIN``OBJ` 子目录.
* **`add-package`**: 添加ABP包到项目.
* **`add-module`**: 添加[应用模块](https://docs.abp.io/en/abp/latest/Modules/Index)到解决方案.
* **`generate-proxy`**: 生成客户端代理以使用HTTP API端点.
@ -129,6 +130,16 @@ abp update [options]
* `--check-all`: 分别检查每个包的新版本. 默认是 `false`.
* `--version` or `-v`: 指定用于升级的版本. 如果没有指定,则使用最新版本.
### clean
删除当前目录下所有的 `BIN``OBJ` 子目录.
用法:
````bash
abp clean
````
### add-package
通过以下方式将ABP包添加到项目中

@ -45,7 +45,7 @@ namespace AbpDemo
public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)
{
await _distributedEventBus.PublishAsync(
new StockCountChangedEvent
new StockCountChangedEto
{
ProductId = productId,
NewCount = newCount
@ -299,4 +299,4 @@ namespace AbpDemo
}
````
此示例使用AutoMapper的 `AutoMap` 属性配置的映射. 你可以创建一个配置文件类代替. 请参阅AutoMapper文档了解更多选项.
此示例使用AutoMapper的 `AutoMap` 属性配置的映射. 你可以创建一个配置文件类代替. 请参阅AutoMapper文档了解更多选项.

@ -2,27 +2,10 @@
````json
//[doc-params]
{
"UI": ["MVC","NG"],
"UI": ["MVC","Blazor","BlazorServer","NG"],
"DB": ["EF","Mongo"]
}
````
{{
if UI == "MVC"
UI_Text="mvc"
else if UI == "NG"
UI_Text="angular"
else
UI_Text="?"
end
if DB == "EF"
DB_Text="Entity Framework Core"
else if DB == "Mongo"
DB_Text="MongoDB"
else
DB_Text="?"
end
}}
## 关于本教程
在本系列教程中, 你将构建一个名为 `Acme.BookStore` 的用于管理书籍及其作者列表的基于ABP的应用程序. 它是使用以下技术开发的:
@ -45,16 +28,32 @@ end
## 下载源码
本教程根据你的**UI** 和 **Database**偏好有多个版,我们准备了两种可供下载的源码组合:
本教程根据你的**UI** 和 **数据库**偏好有多个版本,我们准备了几种可供下载的源码组合:
* [MVC (Razor Pages) UI 与 EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Mvc-EfCore)
* [Blazor UI 与 EF Core](https://github.com/abpframework/abp-samples/tree/master/BookStore-Blazor-EfCore)
* [Angular UI 与 MongoDB](https://github.com/abpframework/abp-samples/tree/master/BookStore-Angular-MongoDb)
> 如果你在Windows中遇到 "文件名太长" or "解压错误", 很可能与Windows最大文件路径限制有关. Windows文件路径的最大长度为250字符. 为了解决这个问题,参阅 [在Windows 10中启用长路径](https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later).
> 如果你遇到与Git相关的长路径错误, 尝试使用下面的命令在Windows中启用长路径. 参阅 https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path
> `git config --system core.longpaths true`
{{if UI == "MVC" && DB == "EF"}}
### 视频教程
本章也被录制为视频教程 **<a href="https://www.youtube.com/watch?v=aidRB4YFDLM&list=PLsNclT2aHJcPNaCf7Io3DbMN6yAk_DgWJ&index=4" target="_blank">发布在YouTube</a>**.
{{end}}
## 解决方案中的测试项目
这一部分涵盖了 **服务器端** 测试. 解决方案中有多个测试项目:
![bookstore-test-projects-v2](./images/bookstore-test-projects-{{UI_Text}}.png)
![bookstore-test-projects-v2](./images/bookstore-test-projects-mvc.png)
> 根据你选择的UI和数据库, 测试项目略微有所不同. 例如, 如果选择MongoDB, 那么 `Acme.BookStore.EntityFrameworkCore.Tests` 会变为 `Acme.BookStore.MongoDB.Tests`.
每个项目用于测试相关的应用程序项目.测试项目使用以下库进行测试:
@ -64,11 +63,11 @@ end
{{if DB=="EF"}}
> 测试项目配置为使用 **SQLite内存** 作为数据库. 创建一个单独的数据库实例并使用数据种子系统进行初始化种子数据,为每个测试准备一个新的数据库.
> 测试项目配置为使用 **SQLite内存** 作为数据库. 创建一个单独的数据库实例并使用[数据种子系统](../Data-Seeding.md)初始化种子数据,为每个测试准备一个新的数据库.
{{else if DB=="Mongo"}}
> **[Mongo2Go](https://github.com/Mongo2Go/Mongo2Go)**库用于模拟MongoDB数据库. 创建一个单独的数据库实例并使用数据种子系统进行初始化种子数据,为每个测试准备一个新的数据库.
> **[Mongo2Go](https://github.com/Mongo2Go/Mongo2Go)**库用于模拟MongoDB数据库. 创建一个单独的数据库实例并使用[数据种子系统](../Data-Seeding.md)初始化种子数据,为每个测试准备一个新的数据库.
{{end}}
@ -78,12 +77,15 @@ end
## 测试 BookAppService
`Acme.BookStore.Application.Tests` 项目中创建一个名叫 `BookAppService_Tests` 的测试类:
`Acme.BookStore.Application.Tests` 项目`Books` 命名空间(文件夹)中创建一个名叫 `BookAppService_Tests` 的测试类:
````csharp
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Validation;
using Xunit;
namespace Acme.BookStore.Books
@ -129,7 +131,7 @@ public async Task Should_Create_A_Valid_Book()
{
Name = "New test book 42",
Price = 10,
PublishDate = System.DateTime.Now,
PublishDate = DateTime.Now,
Type = BookType.ScienceFiction
}
);
@ -201,7 +203,7 @@ namespace Acme.BookStore.Books
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(b => b.Name == "1984");
}
[Fact]
public async Task Should_Create_A_Valid_Book()
{
@ -211,7 +213,7 @@ namespace Acme.BookStore.Books
{
Name = "New test book 42",
Price = 10,
PublishDate = System.DateTime.Now,
PublishDate = DateTime.Now,
Type = BookType.ScienceFiction
}
);
@ -220,7 +222,7 @@ namespace Acme.BookStore.Books
result.Id.ShouldNotBe(Guid.Empty);
result.Name.ShouldBe("New test book 42");
}
[Fact]
public async Task Should_Not_Create_A_Book_Without_Name()
{
@ -244,7 +246,7 @@ namespace Acme.BookStore.Books
}
````
打开**测试资源管理器**(测试 -> Windows -> 测试资源管理器)并**执行**所有测试:
打开**测试资源管理器**(测试 -> Windows -> 测试资源管理器)并**执行所有**测试:
![bookstore-appservice-tests](./images/bookstore-appservice-tests.png)
@ -252,4 +254,4 @@ namespace Acme.BookStore.Books
## 下一章
查看本教程的[下一章](Part-5.md).
查看本教程的[下一章](Part-5.md).

@ -1,4 +1,4 @@
using System;
using System;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
@ -32,7 +32,7 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle
}
else
{
RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId, () => hangfireBackgroundWorker.DoWorkAsync(),
RecurringJob.AddOrUpdate(hangfireBackgroundWorker.RecurringJobId,() => hangfireBackgroundWorker.DoWorkAsync(),
hangfireBackgroundWorker.CronExpression);
}
}
@ -42,7 +42,7 @@ public class HangfireBackgroundWorkerManager : IBackgroundWorkerManager, ISingle
if (worker is AsyncPeriodicBackgroundWorkerBase or PeriodicBackgroundWorkerBase)
{
var timer = (AbpTimer)worker.GetType()
var timer = (AbpAsyncTimer) worker.GetType()
.GetProperty("Timer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(worker);
period = timer?.Period;
}

@ -63,6 +63,7 @@ public class AbpCliCoreModule : AbpModule
options.Commands[BundleCommand.Name] = typeof(BundleCommand);
options.Commands[CreateMigrationAndRunMigratorCommand.Name] = typeof(CreateMigrationAndRunMigratorCommand);
options.Commands[InstallLibsCommand.Name] = typeof(InstallLibsCommand);
options.Commands[CleanCommand.Name] = typeof(CleanCommand);
});
Configure<AbpCliServiceProxyOptions>(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.";
}
}

@ -74,6 +74,24 @@ public class CsprojFileManager : XmlFileManagerBase, ICsprojFileManager, ITransi
await SaveXmlDocumentAsync(filePath, document);
}
public async Task AddImportAsync(string filePath, string importFilePath)
{
var document = await GetXmlDocumentAsync(filePath);
var relativeImportFilePath = PathHelper.GetRelativePath(filePath, importFilePath);
var importNode = document.CreateElement("Import");
var projectAttr = document.CreateAttribute("Project");
projectAttr.Value = relativeImportFilePath;
importNode.Attributes.Append(projectAttr);
document["Project"].AppendChild(importNode);
document["Project"].AppendChild(document.CreateWhitespace(Environment.NewLine + " "));
await SaveXmlDocumentAsync(filePath, document);
}
public async Task ConvertPackageReferenceToProjectReferenceAsync(string filePath, string projectToReference)
{
var document = await GetXmlDocumentAsync(filePath);

@ -10,8 +10,11 @@ public interface ICsprojFileManager
Task AddPackageReferenceAsync(string filePath, string packageName, string version);
Task AddImportAsync(string filePath, string importFilePath);
Task ConvertPackageReferenceToProjectReferenceAsync(string filePath, string projectToReference);
Task<string> GetTargetFrameworkAsync(string filePath);
Task<List<PackageDependency>> GetDependencyListAsync(string filePath);

@ -12,6 +12,7 @@ public abstract class ModuleInstallingPipelineBuilderBase
if (context.WithSourceCode)
{
pipeline.Add(new SourceCodeDownloadStep());
pipeline.Add(new CommonPropsStep());
if (context.AddToSolutionFile)
{

@ -0,0 +1,29 @@
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Studio.Packages.Modifying;
namespace Volo.Abp.Studio.ModuleInstalling.Steps;
public class CommonPropsStep : ModuleInstallingPipelineStep
{
public async override Task ExecuteAsync(ModuleInstallingContext context)
{
var moduleFolder = Path.GetDirectoryName(context.TargetModule);
var commonPropsFilePath = Path.Combine(moduleFolder, "common.props");
if (!File.Exists(commonPropsFilePath))
{
return;
}
var _csprojFileManager = context.ServiceProvider.GetRequiredService<ICsprojFileManager>();
var csProjFiles = Directory.GetFiles(context.GetTargetSourceCodeFolder(), "*.csproj", SearchOption.AllDirectories);
foreach (var csProjFile in csProjFiles)
{
await _csprojFileManager.AddImportAsync(csProjFile, commonPropsFilePath);
}
}
}
Loading…
Cancel
Save