Browse Source

Merge pull request #2 from abpframework/master

update
pull/1170/head
Mon 7 years ago
committed by GitHub
parent
commit
5479701d89
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .gitignore
  2. 2
      abp_io/README.md
  3. 2
      abp_io/Volo.AbpWebSite.sln
  4. 2
      abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj
  5. 17
      abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs
  6. 1
      abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml
  7. 2
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml
  8. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/HomePageLayout.cshtml
  9. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Layout.cshtml
  10. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/LayoutEmpty.cshtml
  11. 4
      abp_io/src/Volo.AbpWebSite.Web/Pages/Templates.cshtml
  12. 1
      abp_io/src/Volo.AbpWebSite.Web/Templates/MvcApplicationTemplate.cs
  13. 3
      abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj
  14. 4
      abp_io/src/Volo.AbpWebSite.Web/compilerconfig.json
  15. 1
      abp_io/src/Volo.AbpWebSite.Web/publish-ignore.json
  16. 3
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css
  17. 2
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css
  18. 10
      abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss
  19. 2
      abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj
  20. 20
      abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/ProjectBuildContextExtensions.cs
  21. 17
      abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/ProjectBuildPipelineStep.cs
  22. 39
      abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/NugetReferenceReplaceStep.cs
  23. 2
      abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/RemoveProjectFromSolutionStep.cs
  24. 12
      abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/SwitchEntityFrameworkCoreToMongoDbStep.cs
  25. 5
      build-all.ps1
  26. 2
      common.props
  27. 177
      docs/en/Apps/VoloDocs.md
  28. 8
      docs/en/AspNetCore/Auto-API-Controllers.md
  29. 6
      docs/en/AspNetCore/Bundling-Minification.md
  30. 16
      docs/en/AspNetCore/Client-Side-Package-Management.md
  31. 3
      docs/en/Best-Practices/Application-Services.md
  32. 2
      docs/en/Best-Practices/Entities.md
  33. 2
      docs/en/Contribution/Index.md
  34. 4
      docs/en/Dependency-Injection.md
  35. 10
      docs/en/Entities.md
  36. 6
      docs/en/Exception-Handling.md
  37. 10
      docs/en/Getting-Started-AspNetCore-MVC-Template.md
  38. 2
      docs/en/Microservice-Architecture.md
  39. 2
      docs/en/Module-Development-Basics.md
  40. 7
      docs/en/Modules/Docs.md
  41. 2
      docs/en/Modules/Index.md
  42. 38
      docs/en/Multi-Tenancy.md
  43. 26
      docs/en/Nightly-Builds.md
  44. 4
      docs/en/Repositories.md
  45. 50
      docs/en/Samples/Microservice-Demo.md
  46. 24
      docs/en/Tutorials/AspNetCore-Mvc/Part-I.md
  47. 2
      docs/en/Tutorials/AspNetCore-Mvc/Part-III.md
  48. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png
  49. BIN
      docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png
  50. 4
      docs/en/docs-nav.json
  51. BIN
      docs/en/images/bookstore-visual-studio-solution-v2.png
  52. BIN
      docs/en/images/docs-create-project.jpg
  53. BIN
      docs/en/images/github-access-token-private-repo.jpg
  54. BIN
      docs/en/images/github-access-token-public-repo.jpg
  55. BIN
      docs/en/images/github-myusername.jpg
  56. BIN
      docs/en/images/microservice-sample-diagram-2.png
  57. BIN
      docs/en/images/microservice-sample-update-database-authserver.png
  58. BIN
      docs/en/images/microservice-sample-update-database-products.png
  59. BIN
      docs/en/images/night-build-add-nuget-package.png
  60. BIN
      docs/en/images/night-build-add-nuget-source.png
  61. BIN
      docs/en/images/pcm-update-database-v2.png
  62. BIN
      docs/en/images/volodocs-iis-add-website.png
  63. BIN
      docs/en/images/volodocs-iis-application-pool.png
  64. 174
      docs/zh-Hans/Apps/VoloDocs.md
  65. 46
      docs/zh-Hans/AspNetCore/Bundling-Minification.md
  66. 3
      docs/zh-Hans/Best-Practices/Application-Services.md
  67. 2
      docs/zh-Hans/Best-Practices/Data-Transfer-Objects.md
  68. 4
      docs/zh-Hans/Best-Practices/Entities.md
  69. 54
      docs/zh-Hans/Blog-Posts/2019-02-22/Post.md
  70. BIN
      docs/zh-Hans/Blog-Posts/2019-02-22/scott-and-jon.png
  71. 75
      docs/zh-Hans/Dependency-Injection.md
  72. 33
      docs/zh-Hans/Domain-Driven-Design.md
  73. 56
      docs/zh-Hans/Exception-Handling.md
  74. 26
      docs/zh-Hans/Getting-Started-AspNetCore-Application.md
  75. 10
      docs/zh-Hans/Getting-Started-AspNetCore-MVC-Template.md
  76. 10
      docs/zh-Hans/Module-Development-Basics.md
  77. 36
      docs/zh-Hans/Multi-Tenancy.md
  78. 25
      docs/zh-Hans/Nightly-Builds.md
  79. 1448
      docs/zh-Hans/Samples/Microservice-Demo.md
  80. 70
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md
  81. 20
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md
  82. 3
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md
  83. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png
  84. BIN
      docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png
  85. 20
      docs/zh-Hans/Virtual-File-System.md
  86. 11
      docs/zh-Hans/docs-nav.json
  87. BIN
      docs/zh-Hans/images/bookstore-visual-studio-solution-v2.png
  88. BIN
      docs/zh-Hans/images/docs-create-project.jpg
  89. BIN
      docs/zh-Hans/images/github-access-token-private-repo.jpg
  90. BIN
      docs/zh-Hans/images/github-access-token-public-repo.jpg
  91. BIN
      docs/zh-Hans/images/github-myusername.jpg
  92. BIN
      docs/zh-Hans/images/microservice-sample-authserver-home.png
  93. BIN
      docs/zh-Hans/images/microservice-sample-authserver-login.png
  94. BIN
      docs/zh-Hans/images/microservice-sample-backend-ui-permissions.png
  95. BIN
      docs/zh-Hans/images/microservice-sample-backend-ui.png
  96. BIN
      docs/zh-Hans/images/microservice-sample-blogservice-permission-in-database.png
  97. BIN
      docs/zh-Hans/images/microservice-sample-diagram-2.png
  98. BIN
      docs/zh-Hans/images/microservice-sample-kibana-1.png
  99. BIN
      docs/zh-Hans/images/microservice-sample-kibana-2.png
  100. BIN
      docs/zh-Hans/images/microservice-sample-product-module-in-solution.png

3
.gitignore

@ -267,7 +267,7 @@ framework/test/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo/Logs/*.*
modules/blog/app/Volo.BlogTestApp/Logs/*.*
modules/blogging/app/Volo.BloggingTestApp/Logs/*.*
modules/blogging/app/Volo.BloggingTestApp/wwwroot/files/*.*
modules/docs/app/Volo.DocsTestApp/Logs/*.*
modules/docs/app/VoloDocs.Web/Logs/*.*
samples/BookStore/src/Acme.BookStore.Web/Logs/*.*
templates/module/app/MyCompanyName.MyProjectName.DemoApp/Logs/*.*
templates/mvc/src/MyCompanyName.MyProjectName.Web/Logs/*.*
@ -294,3 +294,4 @@ samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/Logs/logs.txt
samples/MicroserviceDemo/applications/PublicWebSite.Host/Logs/logs.txt
samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/Logs/logs.txt
samples/MicroserviceDemo/microservices/BloggingService.Host/Logs/logs.txt
modules/docs/app/Volo.DocsTestApp/Logs/logs.txt

2
abp_io/README.md

@ -1,2 +1,2 @@
## abp.op
## abp.io
Source code of the official web site: https://abp.io

2
abp_io/Volo.AbpWebSite.sln

@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.AbpWebSite.Application
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.AbpWebSite.EntityFrameworkCore", "src\Volo.AbpWebSite.EntityFrameworkCore\Volo.AbpWebSite.EntityFrameworkCore.csproj", "{028C05DB-61BF-41EF-B9AD-614A43CD0A7F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Utils.SolutionTemplating", "src\Volo.Utils.SolutionTemplating\Volo.Utils.SolutionTemplating.csproj", "{742FCDDD-537C-42CC-AF16-A92C094D4B1D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Utils.SolutionTemplating", "src\Volo.Utils.SolutionTemplating\Volo.Utils.SolutionTemplating.csproj", "{742FCDDD-537C-42CC-AF16-A92C094D4B1D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

2
abp_io/src/Volo.AbpWebSite.Domain/Volo.AbpWebSite.Domain.csproj

@ -12,7 +12,7 @@
<ItemGroup>
<PackageReference Include="Ionic.Zip" Version="1.9.1.8" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="HtmlAgilityPack.NetCore" Version="1.5.0.1" />
</ItemGroup>

17
abp_io/src/Volo.AbpWebSite.Web/AbpWebSiteWebModule.cs

@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@ -14,7 +13,6 @@ using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
@ -69,7 +67,6 @@ namespace Volo.AbpWebSite
Configure<BlogFileOptions>(options =>
{
options.FileUploadLocalFolder = Path.Combine(hostingEnvironment.WebRootPath, "files");
options.FileUploadUrlRoot = "/files/";
});
}
@ -183,18 +180,8 @@ namespace Volo.AbpWebSite
AsyncHelper.RunSync(async () =>
{
await scope.ServiceProvider
.GetRequiredService<IIdentityDataSeeder>()
.SeedAsync(
"1q2w3E*"
);
await scope.ServiceProvider
.GetRequiredService<IPermissionDataSeeder>()
.SeedAsync(
RolePermissionValueProvider.ProviderName,
"admin",
IdentityPermissions.GetAll().Union(BloggingPermissions.GetAll())
);
.GetRequiredService<IDataSeeder>()
.SeedAsync();
});
}
}

1
abp_io/src/Volo.AbpWebSite.Web/Pages/Index.cshtml

@ -1,5 +1,4 @@
@page
@using Volo.AbpWebSite
@model Volo.AbpWebSite.Pages.IndexModel
@{
Layout = "~/Pages/Shared/HomePageLayout.cshtml";

2
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Components/Header/Default.cshtml

@ -23,7 +23,7 @@
<a class="nav-link" href="/blog/abp/">Blog</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/abpframework/abp/" target="_blank">Github</a>
<a class="nav-link" href="https://github.com/abpframework/abp/" target="_blank">GitHub</a>
</li>
<li class="for-mobile">
<button type="button" class="close close-mmenu" aria-label="Close">

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/HomePageLayout.cshtml

@ -17,7 +17,7 @@
<title>@(ViewBag.Title == null ? "abp.io" : ViewBag.Title)</title>
@await Component.InvokeAsync(typeof(StandardMetaViewComponent))
<abp-style-bundle name="@AbpIoBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body>
@ -47,7 +47,7 @@
gtag('config', 'UA-49982725-4');
</script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/Layout.cshtml

@ -17,7 +17,7 @@
<title>@(ViewBag.Title == null ? "abp.io" : ViewBag.Title)</title>
@await Component.InvokeAsync(typeof(StandardMetaViewComponent))
<abp-style-bundle name="@AbpIoBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body>
@ -58,7 +58,7 @@
gtag('config', 'UA-49982725-4');
</script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Shared/LayoutEmpty.cshtml

@ -18,7 +18,7 @@
<title>@(ViewBag.Title == null ? "abp.io" : ViewBag.Title)</title>
@await Component.InvokeAsync(typeof(StandardMetaViewComponent))
<abp-style-bundle name="@StandardBundles.Styles.Global" />
@RenderSection("styles", false)
@await RenderSectionAsync("styles", false)
</head>
<body class="abp-empty-layout">
@ -41,7 +41,7 @@
gtag('config', 'UA-49982725-4');
</script>
@RenderSection("scripts", false)
@await RenderSectionAsync("scripts", false)
</body>
</html>

4
abp_io/src/Volo.AbpWebSite.Web/Pages/Templates.cshtml

@ -14,7 +14,7 @@
@using (Html.BeginForm(FormMethod.Post))
{
<div class="row border">
<div class="col p-5 ">
<div class="col-lg-7 p-5 ">
<h2>
<span class="text-primary">Create</span>
<span class="text-success">New Project</span>
@ -64,7 +64,7 @@
</div>
</div>
<div class="col-md-5 bg-light p-5">
<div class="col-lg-5 bg-light p-5">
<h4>The Startup Project</h4>
<p>See <a href="/documents/abp/latest/Getting-Started-AspNetCore-MVC-Template" target="_blank">the documentation</a> to understand how to run the downloaded project.</p>

1
abp_io/src/Volo.AbpWebSite.Web/Templates/MvcApplicationTemplate.cs

@ -37,6 +37,7 @@ namespace Volo.AbpWebSite.Templates
if (context.Request.DatabaseProvider != DatabaseProvider.EntityFrameworkCore)
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Application.Tests", projectFolderPath: "test/MyCompanyName.MyProjectName.Application.Tests"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Tests", projectFolderPath: "test/MyCompanyName.MyProjectName.Web.Tests"));
}

3
abp_io/src/Volo.AbpWebSite.Web/Volo.AbpWebSite.Web.csproj

@ -9,7 +9,7 @@
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<PreserveCompilationContext>true</PreserveCompilationContext>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
<MvcRazorCompileOnPublish>true</MvcRazorCompileOnPublish>
<UserSecretsId>c140514f-e488-4c99-8b9a-fabee0f53ce0</UserSecretsId>
</PropertyGroup>
@ -54,6 +54,7 @@
<ItemGroup>
<Folder Include="Downloads\" />
<Folder Include="wwwroot\assets\applications\" />
</ItemGroup>
</Project>

4
abp_io/src/Volo.AbpWebSite.Web/compilerconfig.json

@ -2,5 +2,9 @@
{
"outputFile": "wwwroot/scss/vs.css",
"inputFile": "wwwroot/scss/vs.scss"
},
{
"outputFile": "Pages/Applications.css",
"inputFile": "Pages/Applications.scss"
}
]

1
abp_io/src/Volo.AbpWebSite.Web/publish-ignore.json

@ -3,6 +3,7 @@
"TemplateFiles/": {},
"Logs/": {},
"wwwroot/files/": {},
"wwwroot/downloads/": {},
"appsettings.json": {},
"web.config": {}
}

3
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.css

@ -694,3 +694,6 @@ span.code-arrow {
body {
background-size: cover; }
.applications-container .card-body p {
min-height: 7em; }

2
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.min.css

File diff suppressed because one or more lines are too long

10
abp_io/src/Volo.AbpWebSite.Web/wwwroot/scss/vs.scss

@ -19,4 +19,12 @@
body {
background-size: cover;
}
}
.applications-container {
.card-body {
p {
min-height: 7em;
}
}
}

2
abp_io/src/Volo.Utils.SolutionTemplating/Volo.Utils.SolutionTemplating.csproj

@ -15,7 +15,7 @@
<ItemGroup>
<PackageReference Include="Ionic.Zip" Version="1.9.1.8" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="HtmlAgilityPack.NetCore" Version="1.5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<ProjectReference Include="..\..\..\framework\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" />

20
abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/ProjectBuildContextExtensions.cs

@ -0,0 +1,20 @@
using System;
using System.Linq;
using Volo.Utils.SolutionTemplating.Files;
namespace Volo.Utils.SolutionTemplating.Building
{
public static class ProjectBuildContextExtensions
{
public static FileEntry GetFile(this ProjectBuildContext context, string filePath)
{
var file = context.Files.FirstOrDefault(f => f.Name == filePath);
if (file == null)
{
throw new ApplicationException("Could not find file: " + filePath);
}
return file;
}
}
}

17
abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/ProjectBuildPipelineStep.cs

@ -1,22 +1,7 @@
using System;
using System.Linq;
using Volo.Utils.SolutionTemplating.Files;
namespace Volo.Utils.SolutionTemplating.Building
namespace Volo.Utils.SolutionTemplating.Building
{
public abstract class ProjectBuildPipelineStep
{
public abstract void Execute(ProjectBuildContext context);
protected FileEntry GetFile(ProjectBuildContext context, string filePath)
{
var file = context.Files.FirstOrDefault(f => f.Name == filePath);
if (file == null)
{
throw new ApplicationException("Could not find file: " + filePath);
}
return file;
}
}
}

39
abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/NugetReferenceReplaceStep.cs

@ -16,7 +16,8 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
new NugetReferenceReplacer(
context.Files,
"MyCompanyName",
"MyProjectName"
"MyProjectName",
context.Template.Version
).Run();
}
@ -27,12 +28,12 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
private readonly string _projectNamePlaceHolder;
private readonly string _latestNugetPackageVersion;
public NugetReferenceReplacer(List<FileEntry> entries, string companyNamePlaceHolder, string projectNamePlaceHolder)
public NugetReferenceReplacer(List<FileEntry> entries, string companyNamePlaceHolder, string projectNamePlaceHolder, string latestNugetPackageVersion)
{
_entries = entries;
_companyNamePlaceHolder = companyNamePlaceHolder;
_projectNamePlaceHolder = projectNamePlaceHolder;
_latestNugetPackageVersion = GetLatestNugetPackageVersion();
_latestNugetPackageVersion = latestNugetPackageVersion;
}
public void Run()
@ -110,38 +111,6 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
stream.Position = 0;
return stream;
}
private string GetLatestNugetPackageVersion()
{
//TODO: This should get it from the related release! Not always from the master!
var commonPropsUrl = "https://raw.githubusercontent.com/abpframework/abp/master/common.props";
var content = "";
using (var webClient = new WebClient())
{
try
{
content = webClient.DownloadString(commonPropsUrl);
}
catch (Exception)
{
throw new Exception("The Common.pros doesn't exist on github or removed to anywhere else.");
}
}
var doc = new HtmlDocument();
doc.Load(GenerateStreamFromString(content));
try
{
return doc.DocumentNode.SelectNodes("//version").FirstOrDefault().InnerHtml.Trim();
}
catch (Exception e)
{
return "";
}
}
}
}
}

2
abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/RemoveProjectFromSolutionStep.cs

@ -23,7 +23,7 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
public override void Execute(ProjectBuildContext context)
{
context.Files.RemoveAll(file => file.Name.StartsWith(_projectFolderPath));
var solutionFile = GetFile(context, _solutionFilePath);
var solutionFile = context.GetFile(_solutionFilePath);
solutionFile.NormalizeLineEndings();
solutionFile.SetLines(RemoveProject(solutionFile.GetLines().ToList()));
}

12
abp_io/src/Volo.Utils.SolutionTemplating/Volo/Utils/SolutionTemplating/Building/Steps/SwitchEntityFrameworkCoreToMongoDbStep.cs

@ -14,27 +14,27 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
private void ChangeProjectReference(ProjectBuildContext context)
{
var file = GetFile(context, "/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj");
var file = context.GetFile("/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj");
file.NormalizeLineEndings();
var lines = file.GetLines();
for (var i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("ProjectReference") && lines[i].Contains("MyCompanyName.MyProjectName.EntityFrameworkCore"))
if (lines[i].Contains("ProjectReference") && lines[i].Contains("MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations"))
{
lines[i] = lines[i].Replace("EntityFrameworkCore", "MongoDB");
lines[i] = lines[i].Replace("EntityFrameworkCore.DbMigrations", "MongoDB");
file.SetLines(lines);
return;
}
}
throw new ApplicationException("Could not find the 'Default' connection string in appsettings.json file!");
throw new ApplicationException("Could not find the EntityFrameworkCore reference in the MyCompanyName.MyProjectName.Web.csproj!");
}
private void ChangeWebModuleUsage(ProjectBuildContext context)
{
var file = GetFile(context, "/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs");
var file = context.GetFile("/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs");
file.NormalizeLineEndings();
@ -59,7 +59,7 @@ namespace Volo.Utils.SolutionTemplating.Building.Steps
private void ChangeConnectionString(ProjectBuildContext context)
{
var file = GetFile(context, "/src/MyCompanyName.MyProjectName.Web/appsettings.json");
var file = context.GetFile("/src/MyCompanyName.MyProjectName.Web/appsettings.json");
file.NormalizeLineEndings();

5
build-all.ps1

@ -9,6 +9,7 @@ $solutionPaths = (
"modules/users",
"modules/permission-management",
"modules/setting-management",
"modules/feature-management",
"modules/identity",
"modules/identityserver",
"modules/tenant-management",
@ -17,9 +18,9 @@ $solutionPaths = (
"modules/blogging",
"modules/audit-logging",
"modules/background-jobs",
"modules/client-simulation",
"abp_io",
"templates/module",
"templates/service",
"templates/mvc-module",
"templates/mvc",
"samples/MicroserviceDemo"
)

2
common.props

@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>0.14.0</Version>
<Version>0.18.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://abp.io/assets/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>https://abp.io</PackageProjectUrl>

177
docs/en/Apps/VoloDocs.md

@ -0,0 +1,177 @@
# VoloDocs
## What is VoloDocs?
VoloDocs is a cross-platform web application that allows you to easily create beautiful documentation and build developer communities. It simplifies software documentation with the help of GitHub integration. You use the power of GitHub for versioning, hosting of your docs. You let your users to edit a document.
## Main Features
- Serves documents from your GitHub repository.
- Supports Markdown / HTML document formatting.
- Supports versioning (integrated to GitHub releases).
- Supports multiple projects.
- Allows users to edit a document on GitHub.
- Cross-platform; deployable to Windows / Linux / macOS.
## GitHub Repository
It's free & open-source. You can browse VoloDocs source-code and contribute on GitHub:
https://github.com/abpframework/abp/tree/master/modules/docs
## Download
You can download the VoloDocs release from the following links:
http://apps.abp.io/VoloDocs/VoloDocs.win-x64.zip - **Windows 64 bit**
http://apps.abp.io/VoloDocs/VoloDocs.win-x86.zip - **Windows 32 bit**
http://apps.abp.io/VoloDocs/VoloDocs.osx-x64.zip - **MacOS**
http://apps.abp.io/VoloDocs/VoloDocs.linux-x64.zip - **Linux**
Notice that, all installations are self-contained deployments. It means all the required third-party dependencies along with the version of .NET Core is included. So you don't need to install any .NET Core SDK / Runtime.
## Folder Structure
When you extract the `VoloDocs.*.zip` file, you will see a `Web` folder and a `Migrator` folder. The `Web` folder contains the website files and `Migrator` contains the application to build your database. Before publishing your website, you need to create a new database or update your existing database to the latest. If this is the first time you install VoloDocs, `Migrator` will create a new database for you, otherwise it updates to the latest version. The only setting you need to configure, is the `ConnectionString` which is located in the `appsettings.json` file. See the next section to learn how to configure your VoloDocs application.
## Steps by Step Deployment
- ### Database Migration
To update your existing database or create your initial database, go to `Migrator` folder in your VoloDocs directory.
Open `appsettings.json` in your text editor and set your database connection string. If you don't know how to write the connection string for your database system, you can check out https://www.connectionstrings.com/.
After you set your connection string, run `Migrate.bat` for Windows platform and `VoloDocs.Migrator` for other operating systems. That's it now configure your website.
- ### Configuring Website
Go to `Web` folder in your VoloDocs directory. Open `appsettings.json` in your text editor. Set your connection string (same as in the `Migrator`'s `appsettings.json`). Set `title` of your website. This will be written on the left-upper corner of your website. That's it! Now you can publish your website.
If you want to run
- ### Deploying Website
In the previous step, you created or updated your database. Ensure that your database exists on the specified connection string.
- #### Deploying to IIS
- Move `Web` folder to your `wwwroot ` folder.
- Rename `Web` folder to `VoloDocs` (Now you have `C:\inetpub\wwwroot\VoloDocs`).![Add IIS Website](../images/volodocs-iis-add-website.png)
- The `VoloDocs` application pool is being created automatically. Open **Application Pools** and double click `VoloDocs` application pool and set
- **.NET CLR version**: `No Managed Code`
- **Managed pipeline mode**: `Integrated`
![Add IIS Website](../images/volodocs-iis-application-pool.png)
- If you get the below error, it means don't have the hosting bundle installed on the server. See [this document](https://docs.microsoft.com/aspnet/core/host-and-deploy/iis/#install-the-net-core-hosting-bundle) to learn how to install it or [download Hosting Bundle](https://www.microsoft.com/net/permalink/dotnetcore-current-windows-runtime-bundle-installer) and run on your server.
```
Handler "aspNetCore" has a bad module "AspNetCoreModuleV2" in its module list using IIS
```
- Further information about hosting VoloDocs check out [Microsoft's official document for hosting ASP.NET Core application on IIS](https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/iis).
- #### Deploying to Azure
Microsoft has a good document on how to deploy your ASP.NET Core web app to Azure App Service. We recommend you to read this document https://docs.microsoft.com/en-us/azure/app-service/app-service-web-get-started-dotnet.
- #### Running the Application From Command Line
Alternatively you can run the application from command line, navigate to `VoloDocs\Web` folder and run `VoloDocs.Web.exe` for Windows or `VoloDocs.Web` for MacOS / Linux.
- ### First Run
To start the website, navigate to your address (as configured in the previous section).
When you first open the website, you need to create a project.
#### Creating a Project
Go to the following address to create project
- `http://<yourwebsite>/Account/Login?returnUrl=/Docs/Admin/Projects`
##### Default credentials
To login the admin side, use the following credentials:
* **Username**: `admin`
* **Password**: `1q2w3E*`
##### An example project definition
Here's a sample project information that uses GitHub source.
We will configure the VoloDocs to show ABP Framework's documentation that's stored in GitHub.
Here's the link to ABP Framework GitHub docs folder:
https://github.com/abpframework/abp/tree/master/docs/en
* **Name**: `ABP Framework`
* **Short name**: `abp`
* **Format**: `markdown`
* **Default document name**: `Index`
* **Navigation document name**: `docs-nav.json` ([see the sample navigation](https://github.com/abpframework/abp/blob/master/docs/en/docs-nav.json))
* **Minimum version**: *leave empty* *(hides the previous versions)*
* **Main web site URL**: `/`
* **Latest version branch name**: leave empty ()
* **GitHub root URL**: `https://github.com/abpframework/abp/tree/{version}/docs/en/`
* **GitHub access token**: [see how to retrieve GitHub access token](#retrieving-github-access-token)
* **GitHub user agent**: [see how to learn your GitHub username](#learn-your-github-username)
![Creating a new project](../images/docs-create-project.jpg)
##### Retrieving GitHub Access Token
To create a personal access token in GitHub, you need to visit the **Settings** of the user account and under **Developer settings** you will find **Personal access tokens**. Select **Generate new token**, enter in a name as the Token description and enable the repo checkbox. Alternatively, to enter generate new token, browse to https://github.com/settings/tokens/new.
###### Generate Token for Public Repositories
To access public repositories, check `public_repo` under the `repo` section. This will enable VoloDocs to access your public GitHub repositories. Click `Generate Token` button on the bottom of the page.
![Retrieve GitHub Access Token for Public Repo](../images/github-access-token-public-repo.jpg)
###### Generate Token for Private Repositories
To access public repositories, check all items under the `repo` section. This will enable VoloDocs to access your private GitHub repositories. Click `Generate Token` button on the bottom of the page.
![Retrieve GitHub Access Token for Private Repo](../images/github-access-token-private-repo.jpg)
###### Learn Your GitHub Username
To learn your GitHub username, click on your profile picture on the top-right corner of the GitHub page. You will see your username right after the text "Signed in as ..."
![Your GitHub Username](../images/github-myusername.jpg)
After you save the project, go to root website address and you will see your documentation.
`http://<yourwebsite>/documents`
### Any Issues?
If you encounter any problem or issues about installation, usage or report a bug, follow the link:
https://github.com/abpframework/abp/issues/new

8
docs/en/AspNetCore/Auto-API-Controllers.md

@ -1,6 +1,6 @@
# Auto API Controllers
Once you create an [application service](Application-Services.md), you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc.
Once you create an [application service](../Application-Services.md), you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc.
ABP can **automagically** configures your application services as MVC API Controllers by convention. Most of time you don't care about its detailed configuration, but it's possible fully customize it.
@ -80,7 +80,7 @@ Then the route for getting a book will be '**/api/volosoft/book-store/book/{id}*
* Removing '**Async**' postfix. If the method name is 'GetPhonesAsync' then it becomes 'GetPhones'.
* Removing **HTTP method prefix**. 'GetList', 'GetAll', 'Get', 'Put', 'Update', 'Delete', 'Remove', 'Create', 'Add', 'Insert', 'Post' and 'Patch' prefixes are removed based on the selected HTTP method. So, 'GetPhones' becomes 'Phones' since 'Get' prefix is a duplicate for a GET request.
* Converting the result to **camelCase**.
* If the resulting action name is **empty** then it's not added to the route. If it's not empty, it's added to the route (like '/phones'). For 'GetAllAsync' method name it will be empty, for 'GetPhonesAsync' method name is will be 'phones'.
* If the resulting action name is **empty** then it's not added to the route. If it's not empty, it's added to the route (like '/phones'). For 'GetAllAsync' method name it will be empty, for 'GetPhonesAsync' method name it will be 'phones'.
* Normalization can be customized by setting the `UrlActionNameNormalizer` option. It's an action delegate that is called for every method.
* If there is another parameter with 'Id' postfix, then it's also added to the route as the final route segment (like '/phoneId').
@ -106,7 +106,7 @@ public class PersonAppService : ApplicationService
### TypePredicate Option
You can further filter classes to become an API controller by providing the `TypePedicate` option:
You can further filter classes to become an API controller by providing the `TypePredicate` option:
````csharp
services.Configure<AbpAspNetCoreMvcOptions>(options =>
@ -135,4 +135,4 @@ public class PersonAppService : ApplicationService
}
````
Disabled `IsMetadataEnabled` which hides this service from API explorer and it will not be discoverable. However, it still can be usable for the clients know the exact API path/route.
Disabled `IsMetadataEnabled` which hides this service from API explorer and it will not be discoverable. However, it still can be usable for the clients know the exact API path/route.

6
docs/en/AspNetCore/Bundling-Minification.md

@ -194,7 +194,7 @@ services.Configure<BundlingOptions>(options =>
options
.ScriptBundles
.Configure("MyGlobalBundle", bundle => {
bundle.AddContributors(typeof(MyExtensionStyleBundleContributor));
bundle.AddContributors(typeof(MyExtensionGlobalStyleContributor));
});
});
````
@ -279,9 +279,9 @@ public class MyExtensionStyleBundleContributor : BundleContributor
Using the built-in contributors for standard packages;
* Prevents you typing **invalid the resource paths**.
* Prevents you typing **the invalid resource paths**.
* Prevents changing your contributor if the resource **path changes** (the dependant contributor will handle it).
* Prevents multiple modules adding the **duplicate the files**.
* Prevents multiple modules adding the **duplicate files**.
* Manages **dependencies recursively** (adds dependencies of dependencies, if necessary).
#### Volo.Abp.AspNetCore.Mvc.UI.Packages Package

16
docs/en/AspNetCore/Client-Side-Package-Management.md

@ -22,14 +22,14 @@ The benefit of a **standard package** is:
Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example:
{
...
"dependencies": {
"@abp/bootstrap": "^1.0.0"
}
}
````
{
...
"dependencies": {
"@abp/bootstrap": "^1.0.0"
}
}
````
It's suggested to depend on a standard package instead of directly depending on a third-party package.

3
docs/en/Best-Practices/Application-Services.md

@ -203,12 +203,13 @@ This method votes a question and returns the current score of the question.
#### Manipulating / Deleting Entities
* **Do** always get all the related entities from repositories to perform the operations on them.
* **Do** call repository's Update/UpdateAsync method after updating an entity. Because, not all database APIs support change tracking & auto update.
#### Using Other Application Services
* **Do not** use other application services of the same module/application. Instead;
* Use domain layer to perform the required task.
* Extract a new class and share between the application services to accomplish the code reuse when necessary.
* Extract a new class and share between the application services to accomplish the code reuse when necessary. But be careful to don't couple two use cases. They may seem similar at the beginning, but may evolve to different directions by time. So, use code sharing carefully.
* **Can** use application services of others only if;
* They are parts of another module / microservice.
* The current module has only reference to the application contracts of the used module.

2
docs/en/Best-Practices/Entities.md

@ -63,7 +63,7 @@ public class Issue : FullAuditedAggregateRoot<Guid> //Using Guid as the key/iden
protected Issue()
{
/* This conctructor is for ORMs to be used while getting the entity from database.
/* This constructor is for ORMs to be used while getting the entity from database.
* - No need to initialize the Labels collection
since it will be overrided from the database.
- It's protected since proxying and deserialization tools

2
docs/en/Contribution/Index.md

@ -49,4 +49,4 @@ If you decide to create some tutorials or blog posts on ABP, please inform us (b
### Bug Report
If you find any bug, please [create an issue on the Github repository](https://github.com/abpframework/abp/issues/new).
If you find any bug, please [create an issue on the Github repository](https://github.com/abpframework/abp/issues/new).

4
docs/en/Dependency-Injection.md

@ -96,7 +96,7 @@ public class TaxCalculator : ITransientDependency
Another way of configuring a service for dependency injection is to use ``DependencyAttribute``. It has the following properties:
* ``Lifetime``: Lifetime of the registration: ``Singleton``, ``Transient`` or ``Scoped``.
* ``TryRegister``: Set ``true`` to register the service only it's not registered before. Uses TryAdd... extension methods of IServiceCollection.
* ``TryRegister``: Set ``true`` to register the service only if it's not registered before. Uses TryAdd... extension methods of IServiceCollection.
* ``ReplaceServices``: Set ``true`` to replace services if they are already registered before. Uses Replace extension method of IServiceCollection.
Example:
@ -170,7 +170,7 @@ public class BlogModule : AbpModule
There are three common ways of using a service that has already been registered.
### Contructor Injection
### Constructor Injection
This is the most common way of injecting a service into a class. For example:

10
docs/en/Entities.md

@ -22,7 +22,7 @@ public class Person : Entity<int>
}
```
> If you do not want derive your entity from the base `Entity<TKey>` class, you can directly implement `IEntity<TKey>` interface.
> If you do not want to derive your entity from the base `Entity<TKey>` class, you can directly implement `IEntity<TKey>` interface.
`Entity<TKey>` class just defines an `Id` property with the given primary **key type**, which is `int` in the sample above. It can be other types like `string`, `Guid`, `long` or whatever you need.
@ -57,9 +57,9 @@ For the example above, the composite key is composed of `UserId` and `RoleId`. F
Entities with composite keys should implement the `GetKeys()` method as shown above.
Notice that you also need to define keys of the entity in your **object-to-relational mapping** (ORM) configuration.
Notice that you also need to define keys of the entity in your **object-relational mapping** (ORM) configuration.
> Composite primary keys has a restriction with repositories. Since it has not known Id property, you can not use `IRepository<TEntity, TKey>` for these entities. However, you can always use `IRepository<TEntity>`. See repository documentation (TODO: link) for more.
> Composite primary keys has a restriction with repositories. Since it has not known Id property, you can not use `IRepository<TEntity, TKey>` for these entities. However, you can always use `IRepository<TEntity>`. See [repositories documentation](Repositories.md) for more.
### AggregateRoot Class
@ -67,7 +67,7 @@ Notice that you also need to define keys of the entity in your **object-to-relat
`AggregateRoot` class extends the `Entity` class. So, it also has an `Id` property by default.
> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See repository documentation (TODO: link) for more.
> Notice that ABP creates default repositories only for aggregate roots by default. However, it's possible to include all entities. See [repositories documentation](Repositories.md) for more.
ABP does not force you to use aggregate roots, you can in fact use the `Entity` class as defined before. However, if you want to implement DDD and want to create aggregate root classes, there are some best practices you may want to consider:
@ -160,7 +160,7 @@ public class OrderLine : Entity
> If you do not want to derive your aggregate root from the base `AggregateRoot<TKey>` class, you can directly implement the `IAggregateRoot<TKey>` interface.
`Order` is an **aggregate root** with `Guid` type `Id` property. It has a collection of `OrderLine` entities. `OrderLine` is another entity with a composite primary key (`OrderLine` and ` ProductId`).
`Order` is an **aggregate root** with `Guid` type `Id` property. It has a collection of `OrderLine` entities. `OrderLine` is another entity with a composite primary key (`OrderId` and ` ProductId`).
While this example may not implement all the best practices of an aggregate root, it still follows good practices:

6
docs/en/Exception-Handling.md

@ -9,7 +9,7 @@ ABP provides a built-in infrastructure and offers a standard model for handling
### Automatic Exception Handling
`AbpExceptionFilter` handles an exception if **any of the following conditions** are meet:
`AbpExceptionFilter` handles an exception if **any of the following conditions** are met:
* Exception is thrown by a **controller action** which returns an **object result** (not a view result).
* The request is an AJAX request (`X-Requested-With` HTTP header value is `XMLHttpRequest`).
@ -29,7 +29,7 @@ Error Message is an instance of the `RemoteServiceErrorResponse` class. The simp
}
````
There are **optional fields** those can be filled based upon the exception that has occured.
There are **optional fields** those can be filled based upon the exception that has occurred.
##### Error Code
@ -70,7 +70,7 @@ Error **details** in an optional field of the JSON error message. Thrown `Except
"code": "App:010046",
"message": "Your request is not valid, please correct and try again!",
"validationErrors": [{
"message": "Username should be minimum lenght of 3.",
"message": "Username should be minimum length of 3.",
"members": ["userName"]
},
{

10
docs/en/Getting-Started-AspNetCore-MVC-Template.md

@ -19,9 +19,9 @@ The downloaded project requires;
### The Solution Structure
Extract the zip file downloaded and open in **Visual Studio 2017 (15.7.0+)**:
Extract the zip file downloaded and open in **Visual Studio 2017 (15.9.0+)**:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution.png)
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png)
The solution has a layered structure (based on Domain Driven Design) where;
@ -30,6 +30,8 @@ The solution has a layered structure (based on Domain Driven Design) where;
* ``.Web`` is the presentation layer.
* ``.EntityFrameworkCore`` is the EF Core integration package.
EF Core database migrations are separated to a project named `.EntityFrameworkCore.DbMigrations`.
The solution also contains unit & integration test projects properly configured to work with **EF Core** & **SQLite in-memory** database.
### Creating the Database
@ -50,9 +52,9 @@ Right click to the `.Web` project and select **Set as StartUp Project**:
![set-as-startup-project](images/set-as-startup-project.png)
Open the **Package Manager Console**, select `.EntityFrameworkCore` project as the **Default Project** and run the `Update-Database` command:
Open the **Package Manager Console**, select `.EntityFrameworkCore.DbMigrations` project as the **Default Project** and run the `Update-Database` command:
![pcm-update-database](images/pcm-update-database.png)
![pcm-update-database](images/pcm-update-database-v2.png)
This will create a new database based on the configured connection string.

2
docs/en/Microservice-Architecture.md

@ -19,7 +19,7 @@ One of the major goals of the ABP framework is to provide a convenient infrastru
## Microservice for New Applications
One common advise to start a new solution is **always to start with a monolith**, keep it modular and split into microservices once the monolith becomes a problem. This makes your progress fast in the beginning especially if your team is small and you don't want to deal with challanges of the microservice architecture.
One common advise to start a new solution is **always to start with a monolith**, keep it modular and split into microservices once the monolith becomes a problem. This makes your progress fast in the beginning especially if your team is small and you don't want to deal with challenges of the microservice architecture.
However, developing such a well-modular application can be a problem since it is **hard to keep modules isolated** from each other as you would do it for microservices (see [Stefan Tilkov's article](https://martinfowler.com/articles/dont-start-monolith.html) about that). Microservice architecture naturally forces you to develop well isolated services, but in a modular monolithic application it's easy to tight couple modules to each other and design **weak module boundaries** and API contracts.

2
docs/en/Module-Development-Basics.md

@ -112,7 +112,7 @@ Lastly, you can override ``OnApplicationShutdown`` method if you want to execute
## Module Dependencies
In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependcy upon another module, as shown below:
In a modular application, it's not unusual for one module to depend upon another module(s). An Abp module must declare ``[DependsOn]`` attribute if it does have a dependency upon another module, as shown below:
````C#
[DependsOn(typeof(AbpAspNetCoreMvcModule))]

7
docs/en/Modules/Docs.md

@ -472,4 +472,9 @@ The upper sample `JSON` file renders the below navigation menu as `HTML`.
Finally a new Docs Module is added to your project which is feeded with GitHub.
Finally a new Docs Module is added to your project which is feeded with GitHub.
## Next
Docs Module is also available as a standalone application. Check out [VoloDocs](../Apps/VoloDocs).

2
docs/en/Modules/Index.md

@ -21,6 +21,6 @@ There are some **free and open source** application modules developed and mainta
* **Permission Management**: Used to persist permissions.
* **Setting Management**: Used to persist settings.
* **Tenant Management**: Used to manage tenants for a [multi-tenant](../Multi-Tenancy.md) application.
* **Users**: Used the abstract users, so other modules can depend on this instead of the Identity module.
* **Users**: Used to abstract users, so other modules can depend on this instead of the Identity module.
Documenting the modules is in the progress. See [this repository](https://github.com/abpframework/abp/tree/master/modules) for source code of all modules.

38
docs/en/Multi-Tenancy.md

@ -6,17 +6,17 @@ Wikipedia [defines](https://en.wikipedia.org/wiki/Multitenancy) multi-tenancy as
> Software **Multi-tenancy** refers to a software **architecture** in which a **single instance** of a software runs on a server and serves **multiple tenants**. A tenant is a group of users who share a common access with specific privileges to the software instance. With a multitenant architecture, a software application is designed to provide every tenant a **dedicated share of the instance including its data**, configuration, user management, tenant individual functionality and non-functional properties. Multi-tenancy contrasts with multi-instance architectures, where separate software instances operate on behalf of different tenants.
### Volo.Abp.MultiTenancy.Abstractions Package
### Volo.Abp.MultiTenancy Package
Volo.Abp.MultiTenancy.Abstractions package defines fundamental interfaces to make your code "multi-tenancy ready". So, install it to your project using the package manager console (PMC):
Volo.Abp.MultiTenancy package defines fundamental interfaces to make your code "multi-tenancy ready". So, install it to your project using the package manager console (PMC):
````
Install-Package Volo.Abp.MultiTenancy.Abstractions
Install-Package Volo.Abp.MultiTenancy
````
> This package is already installed by default with the startup template. So, most of the time, you don't need to install it manually.
Then you can add **AbpMultiTenancyAbstractionsModule** dependency to your module:
Then you can add **AbpMultiTenancyModule** dependency to your module:
````C#
using Volo.Abp.Modularity;
@ -24,7 +24,7 @@ using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
[DependsOn(typeof(AbpMultiTenancyModule))]
public class MyModule : AbpModule
{
//...
@ -56,7 +56,7 @@ namespace MyCompany.MyProject
}
````
IMultiTenant requires to define a **TenantId** property in the implementing entity (See entity documentation (TODO: link) for more about entities).
IMultiTenant requires to define a **TenantId** property in the implementing entity (See [entity documentation](Entities.md) for more about entities).
#### Obtain Current Tenant's Id
@ -90,32 +90,6 @@ namespace MyCompany.MyProject
TODO: ...
### Volo.Abp.MultiTenancy Package
Volo.Abp.MultiTenancy is the actual package that makes your application multi-tenant. Install it into your project using PMC:
````
Install-Package Volo.Abp.MultiTenancy
````
Then you can add **AbpMultiTenancyAbstractionsModule** dependency to your module:
````C#
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpMultiTenancyModule))]
public class MyModule : AbpModule
{
//...
}
}
````
> If you add AbpMultiTenancyModule dependency to your module, then you don't need to add AbpMultiTenancyAbstractionsModule dependency separately since AbpMultiTenancyModule already depends on it.
#### Determining Current Tenant
The first thing for a multi-tenant application is to determine the current tenant on the runtime. Volo.Abp.MultiTenancy package only provides abstractions (named as tenant resolver) for determining the current tenant, however it does not have any implementation out of the box.

26
docs/en/Nightly-Builds.md

@ -0,0 +1,26 @@
# Nightly Builds
All framework & module packages are deployed to MyGet every night in weekdays. So, you can use or test the latest code without waiting the next release.
## Configure Visual Studio
> Requires Visual Studio 2017+
1. Go to `Tools > Options > NuGet Package Manager > Package Source`.
2. Click the green `+` icon.
3. Set `ABP Nightly` as *Name* and `https://www.myget.org/F/abp-nightly/api/v3/index.json` as the *Source* as shown below:
![night-build-add-nuget-source](images/night-build-add-nuget-source.png)
4. Click the `Update` button.
5. Click the `OK` button to save changes.
## Install Package
Now, you can install preview / nightly packages to your project from Nuget Browser or Package Manager Console.
![night-build-add-nuget-package](images/night-build-add-nuget-package.png)
1. In the nuget browser, select "Include prereleases".
2. Change package source to "All".
3. Search a package. You will see prereleases of the package formatted as `(VERSION)-preview(DATE)` (like *v0.16.0-preview20190401* in this sample).
4. You can click to the `Install` button to add package to your project.

4
docs/en/Repositories.md

@ -48,8 +48,8 @@ In this example;
Generic Repositories provides some standard CRUD features out of the box:
* Providers `Insert` method to save a new entity.
* Providers `Update` and `Delete` methods to update or delete an entity by entity object or it's id.
* Provides `Insert` method to save a new entity.
* Provides `Update` and `Delete` methods to update or delete an entity by entity object or it's id.
* Provides `Delete` method to delete multiple entities by a filter.
* Implements `IQueryable<TEntity>`, so you can use LINQ and extension methods like `FirstOrDefault`, `Where`, `OrderBy`, `ToList` and so on...
* Have **sync** and **async** versions for all methods.

50
docs/en/Samples/Microservice-Demo.md

@ -24,7 +24,7 @@ This sample aims to demonstrate a simple yet complete microservice solution;
The diagram below shows the system:
![microservice-sample-diagram](../images/microservice-sample-diagram.png)
![microservice-sample-diagram-2](../images/microservice-sample-diagram-2.png)
### Source Code
@ -32,7 +32,7 @@ You can get the source code from [the GitHub repository](https://github.com/abpf
### Status
This sample is still in development, not completed yet.
Initial version of this sample has been completed. Additional improvement are still in development.
## Running the Solution
@ -50,6 +50,20 @@ Running as docker containers is easier since all dependencies are pre-configured
- Open a command line in the `samples/MicroserviceDemo` folder of the repository.
- Pull images from Docker Hub:
```
docker-compose -f docker-compose.yml -f docker-compose.migrations.yml pull
```
- If you want to build images locally you may skip the above step and instead use build command:
```
docker-compose -f docker-compose.yml -f docker-compose.migrations.yml build
```
Building images may take a **long time** depending on your machine.
- Restore SQL Server databases:
```
@ -62,8 +76,6 @@ Running as docker containers is easier since all dependencies are pre-configured
docker-compose up -d
```
At the first run, it will take a **long time** because it will build all docker images.
- Add this line to the end of your `hosts` file:
```
@ -104,11 +116,29 @@ To be able to run the solution from source code, following tools should be insta
* Run `dotnet restore` from the command line inside the `samples\MicroserviceDemo` folder.
* Build the solution in Visual Studio.
#### Restore Databases
#### Create Databases
MongoDB database is created dynamically, however you need to create database schemas for SQL server databases. The solution is configured to use Entity Core Code First migrations, so you can easily create databases.
There are two SQL server databases in this solution.
##### MsDemo_Identity Database
Open `MsDemo_Identity.zip` and `MsDemo_ProductManagement.zip` inside the `samples\MicroserviceDemo\databases` folder and restore to the SQL Server.
* Right click to the `AuthServer.Host` project and click to the `Set as startup project`.
* Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console)
* Select `AuthServer.Host` as the **Default project**.
* Run `Update-Database` command.
> Notice that: These databases have EF Core migrations in the solution, however they don't have seed data, especially required for IdentityServer4 configuration. So, restoring the databases is much more easier.
![microservice-sample-update-database-authserver](../images/microservice-sample-update-database-authserver.png)
##### MsDemo_ProductManagement
- Right click to the `ProductService.Host` project and click to the `Set as startup project`.
- Open the **Package Manager Console** (Tools -> Nuget Package Manager -> Package Manager Console)
- Select `ProductService.Host` as the **Default project**.
- Run `Update-Database` command.
![microservice-sample-update-database-products](../images/microservice-sample-update-database-products.png)
#### Run Projects
@ -124,6 +154,8 @@ Run the projects with the following order (right click to each project, set as s
* BackendAdminApp.Host
* PublicWebSite.Host
When you run projects, they will add some initial demo data to their databases.
## A Brief Overview of the Solution
The Visual Studio solution consists of multiple projects each have different roles in the system:
@ -136,7 +168,7 @@ These are the actual applications those have user interfaces to interact to the
- **AuthServer.Host**: Host the IdentityServer4 to provide an authentication service to other services and applications. It is a single-sign server and contains the login page.
- **BackendAdminApp.Host**: This is a backend admin application that host UI for Identity and Product management modules.
- **PubicWebSite.Host**: As public web site that contains a simple product list page and blog module UI.
- **PublicWebSite.Host**: As public web site that contains a simple product list page and blog module UI.
- **ConsoleClientDemo**: A simple console application to demonstrate the usage of services from a C# application.
### Gateways / BFFs (Backend for Frontend)
@ -1439,4 +1471,4 @@ ABP provides automatic audit logging which saves every request in detail (who is
All of the services and applications are configured to write audit logs. Audit logs are saved to the MsDemo_Identity SQL database. So, you can query all audit logs of all applications from a single point.
An Audit Log record has a `CorrelationId` property that can be used to track a request. When a service calls another service in a single web request, they both save audit logs with the same `CorrelationId`. See the `AbpAuditLogs` table in the database.
An Audit Log record has a `CorrelationId` property that can be used to track a request. When a service calls another service in a single web request, they both save audit logs with the same `CorrelationId`. See the `AbpAuditLogs` table in the database.

24
docs/en/Tutorials/AspNetCore-Mvc/Part-I.md

@ -20,7 +20,7 @@ Go to the [startup template page](https://abp.io/Templates) and download a new p
This is the how the layered solution structure looks after it's created from the startup template:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution.png)
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png)
### Create the Book Entity
@ -84,16 +84,28 @@ EF Core requires you to relate entities with your DbContext. The easiest way to
````C#
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<Book> Book { get; set; }
public DbSet<Book> Books { get; set; }
...
}
````
#### Configure Your Book Entity
Open BookStoreDbContextModelCreatingExtensions.cs file from the `Acme.BookStore.EntityFrameworkCore` project, add following code to the end of ConfigureBookStore method to configure Book entity:
````C#
builder.Entity<Book>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);
b.ConfigureExtraProperties();
});
````
#### Add New Migration & Update the Database
The Startup template uses [EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) to create and maintain the database schema. Open the **Package Manager Console (PMC)** (under the *Tools/Nuget Package Manager* menu), select the `Acme.BookStore.EntityFrameworkCore` as the **default project** and execute the following command:
The Startup template uses [EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) to create and maintain the database schema. Open the **Package Manager Console (PMC)** (under the *Tools/Nuget Package Manager* menu), select the `Acme.BookStore.EntityFrameworkCore.DbMigrations` as the **default project** and execute the following command:
![bookstore-pmc-add-book-migration](images/bookstore-pmc-add-book-migration.png)
![bookstore-pmc-add-book-migration](images/bookstore-pmc-add-book-migration-v2.png)
This will create a new migration class inside the `Migrations` folder. Then execute the `Update-Database` command to update the database schema:
@ -139,7 +151,7 @@ namespace Acme.BookStore
* **DTO** classes are used to **transfer data** between the *presentation layer* and the *application layer*. See the [Data Transfer Objects document](../../Data-Transfer-Objects.md) for more details.
* `BookDto` is used to transfer book data to the presentation layer in order to show the book information on the UI.
* `BookDto` is derived from the `AuditedEntityDto<Guid>` which has audit properties just like the `Book` class defined above.
* `[AutoMapFrom(typeof(Book))]` is used to create AutoMapper mapping from the `Book` class to the `BookDto` class. In this way, you get automatic convertion of `Book` objects to `BookDto` objects (instead of manually copy all properties).
* `[AutoMapFrom(typeof(Book))]` is used to create AutoMapper mapping from the `Book` class to the `BookDto` class. In this way, you get automatic conversion of `Book` objects to `BookDto` objects (instead of manually copy all properties).
#### CreateUpdateBookDto
@ -413,7 +425,7 @@ $(function () {
````
* `abp.libs.datatables.createAjax` is a helper function to adapt ABP's dynamic JavaScript API proxies to Datatable's format.
* `abp.libs.datatables.normalizeConfiguration` is another helper function. There's no requirment to use it, but it simplifies the datatables configuration by providing conventional values for missing options.
* `abp.libs.datatables.normalizeConfiguration` is another helper function. There's no requirement to use it, but it simplifies the datatables configuration by providing conventional values for missing options.
* `acme.bookStore.book.getList` is the function to get list of books (you have seen it before).
* See [Datatable's documentation](https://datatables.net/manual/) for more configuration options.

2
docs/en/Tutorials/AspNetCore-Mvc/Part-III.md

@ -14,8 +14,6 @@ You can download the **source code** of the application [from here](https://gith
There are two test projects in the solution:
![bookstore-test-projects](images/bookstore-test-projects.png)
* `Acme.BookStore.Application.Tests` is for unit & integration tests. You can write tests for application service methods. It uses **EF Core SQLite in-memory** database.
* `Acme.BookStore.Web.Tests` is for full stack integration tests including the web layer. So, you can write tests for UI pages too.

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
docs/en/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

4
docs/en/docs-nav.json

@ -276,6 +276,10 @@
{
"text": "Testing"
},
{
"text": "Nightly Builds",
"path": "Nightly-Builds.md"
},
{
"text": "Contribution Guide",
"path": "Contribution/Index.md"

BIN
docs/en/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
docs/en/images/docs-create-project.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/en/images/github-access-token-private-repo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
docs/en/images/github-access-token-public-repo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

BIN
docs/en/images/github-myusername.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
docs/en/images/microservice-sample-diagram-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
docs/en/images/microservice-sample-update-database-authserver.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
docs/en/images/microservice-sample-update-database-products.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
docs/en/images/night-build-add-nuget-package.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
docs/en/images/night-build-add-nuget-source.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/en/images/pcm-update-database-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
docs/en/images/volodocs-iis-add-website.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/en/images/volodocs-iis-application-pool.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

174
docs/zh-Hans/Apps/VoloDocs.md

@ -0,0 +1,174 @@
# VoloDocs
## 什么是VoloDocs?
VoloDocs是一个跨平台的应用程序,帮助你简单的创建良好的文档与构建开发人员社区. 它借助Github集成简化了软件文档. 使用Github的强大功能进行版本控制,托管文档,并允许用户编译文档.
## 主要功能
- 集成Github从仓库提供文档.
- 支持Markdown/HTML文档格式.
- 支持版本控制 (集成Github release).
- 支持多个项目.
- 允许用户在Github上编辑文档.
- 跨平台,可部署到Windows/Linux/macOS.
## Github源码仓库
它是免费并且开源的. 你可以查看VoloDocs源码,我们也欢迎PR:
https://github.com/abpframework/abp/tree/master/modules/docs
## 下载
你可以在下面的链接下载VoloDocs release版:
http://apps.abp.io/VoloDocs/VoloDocs.win-x64.zip - **Windows 64 bit**
http://apps.abp.io/VoloDocs/VoloDocs.win-x86.zip - **Windows 32 bit**
http://apps.abp.io/VoloDocs/VoloDocs.osx-x64.zip - **MacOS**
http://apps.abp.io/VoloDocs/VoloDocs.linux-x64.zip - **Linux**
上面所有的release都是自包含运行时的部署文件. 包含所有的第三方依赖与.Net Core Runtime,所以你不需要安装任何.Net Core SDK/Runtime.
## 目录结构
解压 `VoloDocs.*.zip` 文件, 你会得到一个 `Web` 文件夹和 `Migrator` 文件夹. `Web` 文件夹中包含网站文件, `Migrator` 文件夹中包含构建数据库的应用程序. 在发布网站之前需要创建数据库或将现有的数据库更新到最新迁移. 如果这是你第一次安装VoloDocs, `Migrator` 会创建一个新数据库. 如果是升级已有的VoloDocs则会将数据库升级到最新的迁移. 使用 `Migrator` 你需要在 `appsettings.json` 文件中更改 `ConnectionString`. 参阅下一节了解如何配置VoloDocs应用程序.
## 逐步部署
- ### 数据库迁移
进入 `Migrator` 目录中创建或更新数据库.
打开 `appsettings.json` 文件设置连接字符串,如果你不清楚如何编写连接字符串,可以查看 https://www.connectionstrings.com/.
设置连接字符串后运行 `Migrate.bat` 如果是Linux或MacOS运行 `DotNet VoloDocs.Migrator.dll` 命令.
- ### 配置网站
进入 `Web` 目录下的VoloDocs文件夹. 打开 `appsettings.json` 文件设置连接字符串(与 `Migrator``appsettings.json` 相同). 你也可以为网站设置你想要的 `title`,它会显示在网站的左上角. 做完这些现在可以发布网站了.
- ### 部署网站
在上一步我们创建/更新了数据库(确保数据库链接字符串正确).
- #### 部署到IIS
- 移动 `Web` 文件夹到你的 `wwwroot ` 文件夹中.
- 重命名 `Web` 文件夹为 `VoloDocs` (现在我们有了 `C:\inetpub\wwwroot\VoloDocs`).![Add IIS Website](../images/volodocs-iis-add-website.png)
- 创建网站 `VoloDocs` 会自动创建相同名称的应用程序池. 打开 **应用程序池** 并双击 `VoloDocs` 应用程序池做以下设置
- **.NET CLR 版本**: `无托管代码`
- **托管管道模式**: `集成`
![Add IIS Website](../images/volodocs-iis-application-pool.png)
- 如果发生发生发现错误,表示未在服务器安装托管捆绑包. 请参阅文档 [this document](https://docs.microsoft.com/aspnet/core/host-and-deploy/iis/#install-the-net-core-hosting-bundle) 了解如何安装或[下载托管捆绑包](https://www.microsoft.com/net/permalink/dotnetcore-current-windows-runtime-bundle-installer).
```
Handler "aspNetCore" has a bad module "AspNetCoreModuleV2" in its module list using IIS
```
- 关于托管VoloDocs的更多信息,请参阅 [在IIS上托管ASP.NET Core应用程序的微软官方文档](https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/iis).
- #### 部署到Azure
微软有一篇关于将ASP.NET Core应用程序部署到Azure App Service的文档. 我们建议你此[文档](https://docs.microsoft.com/en-us/azure/app-service/app-service-web-get-started-dotnet).
- #### 使用命令行运行应用程序
你可以从命令行运行应用程序,进入 `VoloDocs\Web` 文件夹并运行 `VoloDocs.Web.exe`,如果是Linux或MacOS运行 `DotNet VoloDocs.Web.dll` 命令.
- ### 首次运行
打开浏览器导航到你的网址.
首次运行网站,我们需要创建一个项目.
#### 创建项目
跳转到以下网址创建项目
- `http://<yourwebsite>/Account/Login?returnUrl=/Docs/Admin/Projects`
##### 默认凭据
使用管理员身份登陆到管理后台,用户名密码如下:
* **用户名**: `admin`
* **密码**: `1q2w3E*`
##### 示例项目的定义
以下是一个使用了Github源的示例项目信息.
配置VoloDocs展示存储在Github仓库中ABP Framework的文档.
这是ABP Framework文档在Github的链接:
https://github.com/abpframework/abp/tree/master/docs/zh-Hans
* **名称**: `ABP Framework`
* **简称**: `abp`
* **格式**: `markdown`
* **默认文档名称**: `Index`
* **文档导航名称**: `docs-nav.json` ([参见示例](https://github.com/abpframework/abp/blob/master/docs/zh-Hans/docs-nav.json))
* **最小版本**: *留空* *(隐藏之前的版本)*
* **主网站网址**: `/`
* **最新版本分支名称**: 留空
* **GitHub链接**: `https://github.com/abpframework/abp/tree/{version}/docs/zh-Hans/`
* **GitHub访问令牌**: [参见如何创建Github访问令牌](#retrieving-github-access-token)
* **GitHub用户名称**: [参见如何找到自己的Github用户名称](#learn-your-github-username)
![Creating a new project](../images/docs-create-project.jpg)
##### 创建访问令牌
在Github页右上角找到 `Settings`,然后在左侧导航中点击 `Developer Settings`,在这里选择 `Personal access tokens`. 点击创建新token,输入名称与描述并勾选repo复选框. 如果已有访问令牌但已经忘记,可以选择[重新生成](https://github.com/settings/tokens/new).
###### 创建仅授权访问公共仓库的token
想要仅授权访问公共仓库,仅勾选 `public_repo` 就可以了,然后点击页面底部的 `Generate Token` 按钮完成操作.
![Retrieve GitHub Access Token for Public Repo](../images/github-access-token-public-repo.jpg)
###### 创建可访问私有仓库的token
想要授权访问私有仓库,勾选 `repo` 下的所有选项. 然后点击页面底部的 `Generate Token` 按钮完成操作.
![Retrieve GitHub Access Token for Private Repo](../images/github-access-token-private-repo.jpg)
###### 查看你的Github用户名称
在Github页面右上角点击头像图片,"Signed in as ..." 后面就是你的用户名称
![Your GitHub Username](../images/github-myusername.jpg)
保存项目后转到网站根地址,你会看到文档已经正常显示.
`http://<yourwebsite>/documents`
### 发现问题?
如果你在安装,使用时遇到问题或者发现bug,请发起issues与我们联系:
https://github.com/abpframework/abp/issues/new

46
docs/zh-Hans/AspNetCore/Bundling-Minification.md

@ -196,7 +196,7 @@ services.Configure<BundlingOptions>(options =>
options
.ScriptBundles
.Configure("MyGlobalBundle", bundle => {
bundle.AddContributors(typeof(MyExtensionStyleBundleContributor));
bundle.AddContributors(typeof(MyExtensionGlobalStyleContributor));
});
});
````
@ -214,7 +214,7 @@ services.Configure<BundlingOptions>(options =>
`abp-style`和`abp-script`标签可以使用`type`属性(而不是`src`属性), 如本示例所示. 添加bundle贡献者时, 其依赖关系也会自动添加到bundle中.
#### Contributor Dependencies
#### 贡献者依赖关系
bundle贡献者可以与其他贡献者具有一个或多个依赖关系.
例如:
@ -227,9 +227,39 @@ public class MyExtensionStyleBundleContributor : BundleContributor
}
````
添加bundle贡献者时,其依赖关系将 **自动并递归** 添加. **依赖顺序** 通过阻止 **重复** 添加的依赖关系. 即使它们处于分离的中,也会阻止重复. ABP在页面中组织所有bundle并消除重复.
添加bundle贡献者时,其依赖关系将 **自动并递归** 添加. **依赖顺序** 通过阻止 **重复** 添加的依赖关系. 即使它们处于分离的bundle中,也会阻止重复. ABP在页面中组织所有bundle并消除重复.
创建贡献者和定义依赖关系是一种跨不同模块组织包创建的方法.
创建贡献者和定义依赖关系是一种跨不同模块组织bundle创建的方法.
#### 贡献者扩展
在某些高级应用场景中, 当用到一个bundle贡献者时,你可能想做一些额外的配置. 贡献者扩展可以和被扩展的贡献者无缝衔接.
下面的示例为 prism.js 脚本库添加一些样式:
````csharp
public class MyPrismjsStyleExtension : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/prismjs/plugins/toolbar/prism-toolbar.css");
}
}
````
然后你可以配置 `BundleContributorOptions` 去扩展已存在的 `PrismjsStyleBundleContributor`.
````csharp
Configure<BundleContributorOptions>(options =>
{
options
.Extensions<PrismjsStyleBundleContributor>()
.Add<MyPrismjsStyleExtension>();
});
````
任何时候当 `PrismjsStyleBundleContributor` 被添加到bundle中时, `MyPrismjsStyleExtension` 也会被自动添加.
#### 访问 IServiceProvider
@ -239,7 +269,7 @@ public class MyExtensionStyleBundleContributor : BundleContributor
将特定的NPM包资源(js,css文件)添加到包中对于该包非常简单. 例如, 你总是为bootstrap NPM包添加`bootstrap.css`文件.
所有[标准NPM包](Client-Side-Package-Management.md)都有内置的贡献者. 例如,如果你的贡献者依赖于引导程序,你可以声明它,而不是自己添加bootstrap.css.
所有[标准NPM包](Client-Side-Package-Management.md)都有内置的贡献者. 例如,如果你的贡献者依赖于bootstrap,你可以声明它,而不是自己添加bootstrap.css.
````C#
[DependsOn(typeof(BootstrapStyleContributor))] //Define the bootstrap style dependency
@ -261,7 +291,7 @@ public class MyExtensionStyleBundleContributor : BundleContributor
> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它.
标准包贡献者在`Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet包中定义.
安装到你的项目中:
将它安装到你的项目中:
````
install-package Volo.Abp.AspNetCore.Mvc.UI.Packages
@ -283,9 +313,9 @@ namespace MyCompany.MyProject
}
````
#### Bundle Inheritance
#### Bundle 继承
在某些特定情况下, 可能需要从其他bundle创建一个 **新** bundle **继承**, 从bundle继承(递归)继承该bundle的所有文件/贡献者. 然后派生的bundle可以添加或修改文件/贡献者**而无需修改**原始.
在某些特定情况下, 可能需要从其他bundle创建一个 **新** bundle **继承**, 从bundle继承(递归)继承该bundle的所有文件/贡献者. 然后派生的bundle可以添加或修改文件/贡献者**而无需修改**原始bundle.
例如:
````c#

3
docs/zh-Hans/Best-Practices/Application-Services.md

@ -202,12 +202,13 @@ Task<int> VoteAsync(Guid id, VoteType type);
#### 操作/删除 实体
* **推荐** 总是从数据库中获取所有的相关实体以对他们执行操作.
* **推荐** 更新实体后调用存储的Update/UpdateAsync方法.因为并非所有数据库API都支持更改跟踪和自动更新.
#### 使用其他应用服务
* **不推荐** 使用相同 **模块/应用程序** 的其他应用服务. 相反;
* 使用领域层执行所需的任务.
* 提取新类并在应用程序服务之间共享, 在必要时代码重用.
* 提取新类并在应用程序服务之间共享, 在必要时代码重用. 但要小心不要结合两个用例. 它们在开始时可能看起来相似, 但可能会随时间演变为不同的方向. 请谨慎使用代码共享.
* **可以** 在以下情况下使用其他应用服务;
* 它们是另一个模块/微服务的一部分.
* 当前模块仅引用已使用模块的application contracts.

2
docs/zh-Hans/Best-Practices/Data-Transfer-Objects.md

@ -5,4 +5,4 @@
* **推荐** 定义 **public getter 和 setter** 的DTO成员 .
* **推荐** 使用 **data annotations** **验证** service输入DTO的属性.
* **不推荐** 在DTO中添加任何 **逻辑**, 在必要的时候可以实现 `IValidatableObject` 接口.
* **推荐** 为所有的DTO标记 **[Serializable]** Attribute. 因为它们已经是可序列化的, 开发员可能会希望进行二进制序列化.
* **推荐** 为所有的DTO标记 **[Serializable]** Attribute. 因为它们已经是可序列化的, 开发员可能会希望进行二进制序列化.

4
docs/zh-Hans/Best-Practices/Entities.md

@ -64,7 +64,7 @@ public class Issue : FullAuditedAggregateRoot<Guid> //使用Guid作为键/标识
protected Issue()
{
/* 此构造函数是提供给ORM用来从数据库中获取实体.
* - 无需初始化Lanels集合
* - 无需初始化Labels集合
因为它会被来自数据库的值覆盖.
- It's protected since proxying and deserialization tools
可能不适用于私有构造函数.
@ -150,4 +150,4 @@ public class IssueLabel : Entity
### 参考文献
* Effective Aggregate Design by Vaughn Vernon
http://dddcommunity.org/library/vernon_2011
http://dddcommunity.org/library/vernon_2011

54
docs/zh-Hans/Blog-Posts/2019-02-22/Post.md

@ -0,0 +1,54 @@
# 微服务演示,项目状态和路线图
在ABP vNext上的[第一个公告](https://cn.abp.io/blog/abp/Abp-vNext-Announcement)之后,我们对代码库进行了很多改进([GitHub存储库](https://github.com/abpframework/abp)上的1100多次提交).我们已经创建了功能,示例,文档等等.在这篇文章中,我想告诉你一些新闻和项目的状态.
## 微服务演示解决方案
ABP框架的主要目标之一是提供[创建微服务解决方案的便利基础设施](https://cn.abp.io/documents/abp/latest/Microservice-Architecture).
我们一直在努力开发微服务解决方案演示.初始版本已完成并[文档化](https://cn.abp.io/documents/abp/latest/Samples/Microservice-Demo).该示例解决方案旨在演示一个简单而完整的微服务解决方案;
- 具有多个独立的,可自我部署的**微服务**.
- 多个**Web应用程序**,每个都使用不同的API网关.
- 使用[Ocelot](https://github.com/ThreeMammals/Ocelot)库开发了多个**网关** / BFF(后端为前端(Backend for Frontends)).
- 使用[IdentityServer](https://identityserver.io/)框架开发**身份验证服务**.它也是一个带有必要UI的SSO(单点登录)应用程序.
- 有**多个数据库**.一些微服务有自己的数据库,而一些服务/应用程序共享一个数据库(以演示不同的用例).
- 具有不同类型的数据库:**SQL Server**(使用**Entity Framework Core** ORM)和**MongoDB**.
- 有一个**控制台应用程序**来显示通过身份验证使用服务的最简单方法.
- 使用[Redis](https://redis.io/)进行**分布式缓存**.
- 使用[RabbitMQ](https://www.rabbitmq.com/)进行服务到服务(service-to-service)的**消息传递**.
- 使用[Docker](https://www.docker.com/)和[Kubernates](https://kubernetes.io/)**部署**并运行所有服务和应用程序.
- 使用[Elasticsearch](https://www.elastic.co/products/elasticsearch)和[Kibana](https://www.elastic.co/products/kibana)存储和可视化日志(使用[Serilog](https://serilog.net/)编写).
有关解决方案的详细说明,请参阅[其文档](https://cn.abp.io/documents/abp/latest/Samples/Microservice-Demo).
## 改进/功能
我们已经开发了许多功能,包括**分布式事件总线**(与RabbitMQ集成),**IdentityServer4集成**以及几乎所有功能的增强.我们不断重构和添加测试,以使框架更稳定和生产就绪.它正在[快速增长](https://github.com/abpframework/abp/graphs/contributors).
## 路线图
在第一个稳定版本(v1.0)之前还有很多工作要做.您可以在GitHub仓库上看到[优先的积压项目](https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+milestone%3ABacklog).
根据我们的估计,我们计划在2019年第二季度(可能在五月或六月)发布v1.0.所以,不用等待太长时间了.我们也对第一个稳定版本感到非常兴奋.
我们还将完善[文档](https://cn.abp.io/documents/abp/latest),因为它现在还远未完成.
第一个版本可能不包含SPA模板.但是,如果可能的话,我们想要准备一个简单些的.SPA框架还没有确定下来.备选有:**Angular,React和Blazor**.请将您的想法写为对此帖的评论.
## 中文网
中国有一个大型的ABP社区.他们创建了一个中文版的abp.io网站:https://cn.abp.io/. 他们一直在保持更新.感谢中国的开发人员,特别是[Liming Ma](https://github.com/maliming).
## NDC {London} 2019
很高兴作为合作伙伴参加[NDC {London}](https://ndc-london.com/)2019 .我们已经与许多开发人员讨论过当前的ASP.NET Boilerplate和ABP vNext,我们得到了很好的反馈.
我们还有机会与[Scott Hanselman](https://twitter.com/shanselman)和[Jon Galloway](https://twitter.com/jongalloway)交谈.他们参观了我们的展位,我们谈到了ABP vNext的想法.他们喜欢新的ABP框架的功能,方法和目标.在twitter上查看一些照片和评论:
![scott-and-jon](scott-and-jon.png)
## 跟上步伐
* 您可以标星并关注**GitHub**存储库:https://github.com/abpframework/abp
* 您可以关注官方**Twitter**帐户获取新闻:https://twitter.com/abpframework

BIN
docs/zh-Hans/Blog-Posts/2019-02-22/scott-and-jon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

75
docs/zh-Hans/Dependency-Injection.md

@ -2,9 +2,11 @@
ABP的依赖注入系统是基于Microsoft的[依赖注入扩展](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection)库(Microsoft.Extensions.DependencyInjection nuget包)开发的.因此,它的文档在ABP中也是有效的.
> 虽然ABP框架没有对任何第三方DI提供程序的核心依赖, 但它必须使用一个提供程序来支持动态代理(dynamic proxying)和一些高级特性以便ABP特性能正常工作.启动模板中已安装了Autofac. 更多信息请参阅 [Autofac 集成](Autofac-Integration.md) 文档.
### 模块化
由于ABP是一个模块化框架,因此每个模块都通过依赖注入定义它自己的服务并通过它自己的单独[模块类](Module-Development-Basics.md)进行注册.例:
由于ABP是一个模块化框架,因此每个模块都定义它自己的服务并在它自己的单独[模块类](Module-Development-Basics.md)中通过依赖注入进行注册.例:
````C#
public class BlogModule : AbpModule
@ -69,15 +71,15 @@ public class BlogPostAppService : ApplicationService
}
````
``BlogPostAppService`` 由于它是从已知的基类派生的,因此会自动注册transient.
``BlogPostAppService`` 由于它是从已知的基类派生的,因此会自动注册transient生命周期.
#### 依赖接口
如果实现这些接口,则会自动将类注册到依赖注入:
* ``ITransientDependency`` 注册为transient.
* ``ISingletonDependency`` 注册为singleton.
* ``IScopedDependency`` 注册为scoped.
* ``ITransientDependency`` 注册为transient生命周期.
* ``ISingletonDependency`` 注册为singleton生命周期.
* ``IScopedDependency`` 注册为scoped生命周期.
示例:
@ -87,9 +89,9 @@ public class TaxCalculator : ITransientDependency
}
````
``TaxCalculator``因为实现了``ITransientDependency``,所以它会自动注册为transient.
``TaxCalculator``因为实现了``ITransientDependency``,所以它会自动注册为transient生命周期.
#### Dependency
#### Dependency
配置依赖注入服务的另一种方法是使用``DependencyAttribute``.它具有以下属性:
@ -108,9 +110,9 @@ public class TaxCalculator
````
``Dependency``如果定义``Lifetime``属性,则具有比其他依赖接口更高的优先级.
如果定义``Lifetime``属性,则``Dependency``特性具有比其他依赖接口更高的优先级.
#### ExposeServices
#### ExposeServices
``ExposeServicesAttribute``用于控制相关类提供了什么服务.例:
@ -133,7 +135,7 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie
#### 组合到一起
只要有意义,就可以组合属性和接口.
只要有意义,特性和接口是可以组合在一起使用的.
````C#
[Dependency(ReplaceServices = true)]
@ -189,7 +191,7 @@ public class TaxAppService : ApplicationService
``TaxAppService``在构造方法中得到``ITaxCalculator``.依赖注入系统在运行时自动提供所请求的服务.
构造方法注入是将依赖项注入类的优先方式.这样,除非提供了所有构造方法注入的依赖项,否则无法构造类.因此,该类明确的声明了它必需的服务.
构造方法注入是将依赖项注入类的首选方式.这样,除非提供了所有构造方法注入的依赖项,否则无法构造类.因此,该类明确的声明了它必需的服务.
#### 属性注入
@ -266,6 +268,55 @@ using (var scope = _serviceProvider.CreateScope())
两个服务在创建的scope被处理时(在using块的末尾)释放.
## 高级特性
### IServiceCollection.OnRegistred 事件
你可能想在注册到依赖注入的每个服务上执行一个操作, 在你的模块的 `PreConfigureServices` 方法中, 使用 `OnRegistred` 方法注册一个回调(callback) , 如下所示:
````csharp
public class AppModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(ctx =>
{
var type = ctx.ImplementationType;
//...
});
}
}
````
`ImplementationType` 提供了服务类型. 该回调(callback)通常用于向服务添加拦截器. 例如:
````csharp
public class AppModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.OnRegistred(ctx =>
{
if (ctx.ImplementationType.IsDefined(typeof(MyLogAttribute), true))
{
ctx.Interceptors.TryAdd<MyLogInterceptor>();
}
});
}
}
````
这个示例判断一个服务类是否具有 `MyLogAttribute` 特性, 如果有的话就添加一个 `MyLogInterceptor` 到拦截器集合中.
> 注意, 如果服务类公开了多于一个服务或接口, `OnRegistred` 回调(callback)可能被同一服务类多次调用. 因此, 较安全的方法是使用 `Interceptors.TryAdd` 方法而不是 `Interceptors.Add` 方法. 请参阅动态代理(dynamic proxying)/拦截器 [文档](Dynamic-Proxying-Interceptors.md).
## 第三方提供程序
虽然ABP框架没有对任何第三方DI提供程序的核心依赖, 但它必须使用一个提供程序来支持动态代理(dynamic proxying)和一些高级特性以便ABP特性能正常工作.
启动模板中已安装了Autofac. 更多信息请参阅 [Autofac 集成](Autofac-Integration.md) 文档.
### 请参阅
* [ASP.NET Core依赖注入最佳实践,提示和技巧](https://medium.com/volosoft/asp-net-core-dependency-injection-best-practices-tips-tricks-c6e9c67f9d96)
* [ASP.NET Core依赖注入最佳实践,提示和技巧](https://cn.abp.io/blog/Abp/asp-net-core-dependency-injection-best-practices-tips-tricks)

33
docs/zh-Hans/Domain-Driven-Design.md

@ -0,0 +1,33 @@
# 领取驱动设计
## 什么是DDD?
ABP框架提供了**基础设施**使基础**DDD**的开发更易实现. DDD在[维基百科中的定义](https://zh.wikipedia.org/wiki/%E5%9F%9F%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91)如下:
> **领域驱动设计(DDD)** 是一种通过将实现连接到持续进化的模型来满足复杂需求的软件开发方法. 领域驱动设计的前提是:
>
> - 把项目的主要重点放在核心领域和领域逻辑上
> - 把复杂的设计放在领域模型上
> - 发起技术专家和领域专家之间的创造性协作,以迭代方式完善解决特定领域问题的概念模型
### 分层
ABP框架遵循DDD原则和模式去实现分层应用程序模型,该模型由四个基本层组成:
- **表示层**: 为用户提供接口. 使用*应用层*实现与用户交互.
- **应用层**: 表示层与领域层的中介,编排业务对象执行特定的应用程序任务. 使用应用程序逻辑实现用例.
- **领域层**: 包含业务对象以及业务规则. 是应用程序的核心.
- **基础设施层**: 提供通用的技术功能,支持更高的层,主要使用第三方类库.
## 内容
* **领域层**
* [实体与聚合根](Entities.md)
* 值对象
* [仓储](Repositories.md)
* 领域服务
* 规约
* **应用层**
* [应用服务](Application-Services.md)
* [数据传输对象(DTO)](Data-Transfer-Objects.md)
* 工作单元

56
docs/zh-Hans/Exception-Handling.md

@ -11,15 +11,15 @@ ABP提供了用于处理Web应用程序异常的标准模型.
当满足下面**任意一个条件**时,`AbpExceptionFilter` 会处理此异常:
* 当**controller action**方法返回类型是**object**(不是view)并有异常抛出时.
* 当一个请求为AJAX(Http请求头中`X-Requested-With`为`XMLHttpRequest`)时.
* 当**controller action**方法返回类型是**object result**(不是view result)并有异常抛出时.
* 当一个请求为AJAX(Http请求头中`X-Requested-With`为`XMLHttpRequest`)时.
* 当客户端接受的返回类型为`application/json`(Http请求头中`accept` 为`application/json`)时.
如果异常被处理过,则会自动**记录日志**并将格式化的**JSON消息**返回给客户端.
#### 异常消息格式
#### 错误消息格式
每个异常消息都是`RemoteServiceErrorResponse` 类的实例.下面是一个只有 **Message** 属性的错误JSON:
每个错误消息都是`RemoteServiceErrorResponse` 类的实例.最简单的错误JSON只有一个 **Message** 属性,如下所示:
````json
{
@ -29,11 +29,11 @@ ABP提供了用于处理Web应用程序异常的标准模型.
}
````
当异常发生时,会自动填充到这些**可选字段**.
其它**可选字段**可以根据已发生的异常来填充.
##### 错误代码
错误**Code** 是字符串类型,并要求唯一的可选属性.如果抛出的异常包含 **Code** 属性,那么应该实现`IHasErrorCode` 接口,来填充这个字段.示例JSON如下:
错误 **代码(code)** 是异常信息中一个有唯一值并可选的字符串值.抛出的异常应实现`IHasErrorCode` 接口来填充该字段.示例JSON如下:
````json
{
@ -44,11 +44,11 @@ ABP提供了用于处理Web应用程序异常的标准模型.
}
````
错误 **Code** 同样可用于异常的本地化及自定义HTTP状态代码(请参阅下面的相关部分).
错误代码同样可用于异常信息的本地化及自定义HTTP状态代码(请参阅下面的相关部分).
##### 错误详细信息
错误的 **Details** 是可选属性.抛出的异常应该实现`IHasErrorDetails` 接口来填充这个字段.示例JSON如下:
错误的 **详细信息(Details)** 是可选属性.抛出的异常应实现`IHasErrorDetails` 接口来填充该字段.示例JSON如下:
```json
{
@ -62,7 +62,7 @@ ABP提供了用于处理Web应用程序异常的标准模型.
##### 验证错误
当抛出的异常继承至`IHasValidationErrors` 接口时,返回错误对象会包含一个可选属性**validationErrors** .示例JSON如下:
当抛出的异常实现`IHasValidationErrors` 接口时,**validationErrors**是一个可被填充的标准字段.示例JSON如下:
````json
{
@ -70,7 +70,7 @@ ABP提供了用于处理Web应用程序异常的标准模型.
"code": "App:010046",
"message": "Your request is not valid, please correct and try again!",
"validationErrors": [{
"message": "Username should be minimum lenght of 3.",
"message": "Username should be minimum length of 3.",
"members": ["userName"]
},
{
@ -85,7 +85,7 @@ ABP提供了用于处理Web应用程序异常的标准模型.
#### 日志
自动记录捕获异常的日志.
被捕获的异常会被自动记录到日志中.
##### 日志级别
@ -102,7 +102,7 @@ public class MyException : Exception, IHasLogLevel
##### 异常自定义日志
某些异常类型可能需要记录额外日志信息.可以通过实现`IExceptionWithSelfLogging` 来记录指定日志,例如:
某些异常类型可能需要记录额外日志信息.可以通过实现`IExceptionWithSelfLogging` 接口来记录指定日志,例如:
````C#
public class MyException : Exception, IExceptionWithSelfLogging
@ -114,7 +114,7 @@ public class MyException : Exception, IExceptionWithSelfLogging
}
````
> 扩展方法`ILogger.LogException` 用来记录日志. 在需要时可以使用相同的扩展方法.
> 扩展方法`ILogger.LogException` 用来记录异常日志. 在需要时可以使用相同的扩展方法.
### 业务异常
@ -140,9 +140,9 @@ throw new BusinessException(QaErrorCodes.CanNotVoteYourOwnAnswer);
Volo.Qa:010002
````
`Volo.Qa`在这是作为`code-namespace`. `code-namespace` 同样可以在异常 **本地化**使用.
`Volo.Qa`在这是作为`code-namespace`. `code-namespace` 同样可以在 **本地化** 异常信息时使用.
* 你可以直接抛出一个 `BusinessException` 异常或者自定义的异常.
* 你可以直接抛出一个 `BusinessException` 异常,或者需要时可以从该类派生你自己的Exception类型.
* 对于`BusinessException` 类型,其所有属性都是可选的.但是通常会设置`ErrorCode`或`Message`属性.
### 异常本地化
@ -153,7 +153,7 @@ Volo.Qa:010002
如果异常实现了 `IUserFriendlyException` 接口,那么ABP不会修改 `Message`和`Details`属性,而直接将它发送给客户端.
`UserFriendlyException`默认实现了 `IUserFriendlyException` 接口,示例如下:
`UserFriendlyException`是内建的 `IUserFriendlyException` 接口的实现,示例如下:
````C#
throw new UserFriendlyException(
@ -167,7 +167,7 @@ throw new UserFriendlyException(
throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage"]);
````
再在本地化资源的语言中添加对应的定义.例如:
再在本地化资源中为每种语言添加对应的定义.例如:
````json
{
@ -178,7 +178,7 @@ throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage"
}
````
**string localizer** 支持格式化参数.例如
**string localizer** 支持参数化信息.例如
````C#
throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage", "john"]);
@ -192,12 +192,12 @@ throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage"
* `IUserFriendlyException`接口派生自`IBusinessException`,而 `UserFriendlyException `类派生自`BusinessException`类.
#### 错误代码
#### 使用错误代码
`UserFriendlyException`很好用,但是在一些高级用法里面,它存在以下问题:
* 在抛出异常的地方必须注入**string localizer** 来实现本地化 .
* 但是,在某些情况下,**可能注入不了string localizer**(比如,静态方法或实体中)
* 但是,在某些情况下,**可能注入不了string localizer**(比如,在静态上下文或实体方法中)
那么这时就可以通过使用 **错误代码** 的方式来处理本地化,而不是在抛出异常的时候.
@ -210,7 +210,7 @@ services.Configure<ExceptionLocalizationOptions>(options =>
});
````
再使用本地化资源,来本地化`Volo.Qa`命名空间下的所有异常. 本地化资源中应包含对应错误代码的文本. 例如:
然后`Volo.Qa`命名空间下的所有异常都将被对应的本地化资源进行本地化处理. 本地化资源中应包含对应错误代码的文本. 例如:
````json
{
@ -227,12 +227,12 @@ services.Configure<ExceptionLocalizationOptions>(options =>
throw new BusinessException(QaDomainErrorCodes.CanNotVoteYourOwnAnswer);
````
* 所有实现`IHasErrorCode` 接口的异常都具有相同的行为.因此,对错误代码的本地化,并不是`BusinessException`类所特有的.
* 错误消息的本地化文本的并不是必须. 如果未定义,ABP会将默认的错误消息发送给客户端. 而并不是发送异常的`Message`属性. 如果你想要发送异常的`Message`,使用`UserFriendlyException`(或使用实现`IUserFriendlyException`接口的异常类型)
* 抛出所有实现`IHasErrorCode` 接口的异常都具有相同的行为.因此,对错误代码的本地化,并不是`BusinessException`类所特有的.
* 为错误消息定义本地化文本并不是必须的. 如果未定义,ABP会将默认的错误消息发送给客户端. 而不使用异常的`Message`属性. 如果你想要发送异常的`Message`,使用`UserFriendlyException`(或使用实现`IUserFriendlyException`接口的异常类型)
##### 使用消息的格式化参数
如果错误消息包含格式化参数时,则可以使用异常的`Data`属性进行设置.例如:
如果有参数化的错误消息,则可以使用异常的`Data`属性进行设置.例如:
````C#
throw new BusinessException("App:010046")
@ -263,9 +263,9 @@ throw new BusinessException("App:010046")
}
````
* `WithData` 支持链式调用 (如`.WithData(...).WithData(...)`).
* `WithData` 支持有多个参数的链式调用 (如`.WithData(...).WithData(...)`).
### HTTP状态代码 映射
### HTTP状态代码映射
ABP尝试按照以下规则,自动映射常见的异常类型的HTTP状态代码:
@ -297,6 +297,6 @@ services.Configure<ExceptionHttpStatusCodeOptions>(options =>
- 当用户没有权限执行操作时,会抛出 `AbpAuthorizationException` 异常. 有关更多信息,请参阅授权文档(TODO:link).
- 如果当前请求的输入无效,则抛出`AbpValidationException 异常`. 有关更多信息,请参阅授权文档(TODO:link).
- 如果请求的实体不存在,则抛出`EntityNotFoundException` 异常. 此异常由 [repositories](Repositories.md) 抛出.
- 如果请求的实体不存在,则抛出`EntityNotFoundException` 异常. 此异常大多数由 [repositories](Repositories.md) 抛出.
你同样可以在代码中抛出这些类型的异常(虽然只在很少时候)
你同样可以在代码中抛出这些类型的异常(虽然很少需要这样做)

26
docs/zh-Hans/Getting-Started-AspNetCore-Application.md

@ -77,11 +77,11 @@ namespace BasicAspNetCoreApplication
{
public class Startup
{
public IServiceProvider ConfigureServices(ServiceConfigurationContext context)
public IServiceProvider ConfigureServices(IServiceCollection services)
{
context.Services.AddApplication<AppModule>();
services.AddApplication<AppModule>();
return context.Services.BuildServiceProviderFromFactory();
return services.BuildServiceProviderFromFactory();
}
public void Configure(IApplicationBuilder app)
@ -156,6 +156,26 @@ services.AddApplication<AppModule>(options =>
});
````
4. 更新 `Program.cs`代码, 不再使用`WebHost.CreateDefaultBuilder()`方法(因为它使用默认的DI容器):
````csharp
public class Program
{
public static void Main(string[] args)
{
BuildWebHostInternal(args).Run();
}
public static IWebHost BuildWebHostInternal(string[] args) =>
new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
}
````
### 源码
从[此处](../samples/BasicAspNetCoreApplication)获取本教程中创建的示例项目的源代码.

10
docs/zh-Hans/Getting-Started-AspNetCore-MVC-Template.md

@ -12,14 +12,14 @@
下载的项目需要:
* [Visual Studio 2017 (v15.7.0+)](https://visualstudio.microsoft.com/tr/downloads/)
* [Visual Studio 2017 (v15.9.0+)](https://visualstudio.microsoft.com/tr/downloads/)
* [.NET Core 2.1.1+](https://www.microsoft.com/net/download/dotnet-core/)
### 解决方案结构
下载后解压文件并在 **Visual Studio 2017(15.7.0 +)** 中打开:
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution.png)
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png)
该解决方案具有分层结构(基于域驱动设计), 其中:
@ -28,6 +28,8 @@
* ``.Web`` 为是表示层.
* ``.EntityFrameworkCore`` 是EF Core集成.
EF Core 数据库迁移被分离到名为`.EntityFrameworkCore.DbMigrations`项目中.
解决方案还包含配置好的的单元&集成测试项目, 以便与 **EF Core****SQLite内存中** 数据库配合使用.
### 创建数据库
@ -48,9 +50,9 @@
![set-as-startup-project](images/set-as-startup-project.png)
打开**包管理器控制台(Package Manager Console)**, 选择`.EntityFrameworkCore`项目作为**默认项目**并运行`Update-Database`命令:
打开**包管理器控制台(Package Manager Console)**, 选择`.EntityFrameworkCore.DbMigrations`项目作为**默认项目**并运行`Update-Database`命令:
![pcm-update-database](images/pcm-update-database.png)
![pcm-update-database](images/pcm-update-database-v2.png)
这将基于配置的连接字符串创建新数据库.

10
docs/zh-Hans/Module-Development-Basics.md

@ -2,7 +2,7 @@
### 介绍
ABP本身是一个模块化框架.它还提供了一个基础架构和架构模型来开发你自己的模块.
ABP本身是一个包含许多nuget包的模块化框架.它还提供了一个完整的基础架构来开发你自己的具有实体, 服务, 数据库集成, API, UI组件等等功能的应用程序模块.
### 模块类
@ -111,7 +111,7 @@ public class AppModule : AbpModule
### 模块依赖
在模块化应用程序中,一个模块依赖于另一个模块并不罕见.如果一个Abp模块依赖于另一个模块,它必须声明``[DependsOn]``性,如下所示:
在模块化应用程序中,一个模块依赖于另一个或几个模块并不罕见.如果一个Abp模块依赖于另一个模块,它必须声明``[DependsOn]``性,如下所示:
````C#
[DependsOn(typeof(AbpAspNetCoreMvcModule))]
@ -122,7 +122,7 @@ public class BlogModule
}
````
你可以根据需要使用多个``DependsOn``属性或将多个模块类型传递给单个``DependsOn``属性.
你可以根据需要使用多个``DependsOn``特性或将多个模块类型传递给单个``DependsOn``特性.
依赖模块可能依赖于另一个模块,但你只需要定义直接依赖项.ABP在启动时会调查应用程序的依赖关系,并以正确的顺序初始化/关闭模块.
@ -130,5 +130,5 @@ public class BlogModule
**模块分为两种类型.** 这两种类型并没有任何结构上的区别,只是按功能和用途分类:
- **框架模块**: 这些是**框架的核心模块** 如缓存, 邮件, 主题, 安全, 序列化, 验证, EF Core集成, MongoDB集成... 等. 它们没有应用/业务功能,它们提供了日常开发经常用到的基础设施,集成和抽象.
- **应用程序模块**: 这些模块实现了 **特定的应用/业务功能** 像博客, 文档管理, 身份管理, 租房管理... 等等. 它们通过有自己的实体,服务,API和UI组件. 请参阅 [预构建的应用程序模块](Modules/Index.md).
- **框架模块**: 这些是**框架的核心模块** 如缓存, 邮件, 主题, 安全, 序列化, 验证, EF Core集成, MongoDB集成... 等. 它们没有应用/业务功能,它们提供了日常开发经常用到的通用基础设施,集成和抽象.
- **应用程序模块**: 这些模块实现了 **特定的应用/业务功能** 像博客, 文档管理, 身份管理, 租户管理... 等等. 它们通常有自己的实体,服务,API和UI组件. 请参阅 [预构建的应用程序模块](Modules/Index.md).

36
docs/zh-Hans/Multi-Tenancy.md

@ -6,17 +6,17 @@ ABP的多租户模块提供了创建多租户应用程序的基本功能.
> 软件多租户技术指的是一种软件架构,这种架构可以使用软件的单实例运行并为多个租户提供服务.租户是通过软件实例的特定权限共享通用访问的一组用户.使用多租户架构,软件应用为每个租户提供实例的专用共享,包括实例的数据、配置、用户管理、租户的私有功能和非功能属性.多租户与多实例架构形成对比,将软件实例的行为根据不同的租户分割开来.
### Volo.Abp.MultiTenancy.Abstractions
### Volo.Abp.MultiTenancy
Volo.Abp.MultiTenancy.Abstractions定义了一些基础接口让你的代码"multi-tenancy ready",使用包管理器控制台(PMC)将它安装到你的项目中:
Volo.Abp.MultiTenancy"multi-tenancy ready",使用包管理器控制台(PMC)将它安装到你的项目中:
````
Install-Package Volo.Abp.MultiTenancy.Abstractions
Install-Package Volo.Abp.MultiTenancy
````
> 这个包默认安装在了快速启动模板中.所以,大多数情况下,你不需要手动安装它.
然后你可以添加 **AbpMultiTenancyAbstractionsModule** 依赖到你的模块:
然后你可以添加 **AbpMultiTenancyModule** 依赖到你的模块:
````C#
using Volo.Abp.Modularity;
@ -24,7 +24,7 @@ using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
[DependsOn(typeof(AbpMultiTenancyModule))]
public class MyModule : AbpModule
{
//...
@ -90,32 +90,6 @@ namespace MyCompany.MyProject
TODO: ...
### Volo.Abp.MultiTenancy
Volo.Abp.MultiTenancy 才是让你的程序实现多租户的真正的包.使用PMC将它安装到你的项目中:
````
Install-Package Volo.Abp.MultiTenancy
````
然后添加 **AbpMultiTenancyAbstractionsModule** 依赖到你的模块中:
````C#
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
namespace MyCompany.MyProject
{
[DependsOn(typeof(AbpMultiTenancyModule))]
public class MyModule : AbpModule
{
//...
}
}
````
> 如果你添加了AbpMultiTenancyModule依赖,就不需要再另外添加AbpMultiTenancyAbstractionsModule依赖了,因为AbpMultiTenancyModule已经依赖它了.
#### 确定当前租户
多租户的应用程序运行的时候首先要做的就是确定当前租户.

25
docs/zh-Hans/Nightly-Builds.md

@ -0,0 +1,25 @@
# 每日构建
所有框架和模块包都每晚都部署到MyGet. 因此你可以使用或测试最新的代码,而无需等待下一个版本.
## 在Visual Studio配置
> 需要Visual Studio 2017以上
1. 在VS中打开: `工具 > 选项 > NuGet 包管理器 > 程序包源`
2. 单击绿色的`+`图标
3. 在底部输入名称(ABP Nightly)和并粘贴URL(`https://www.myget.org/F/abp-nightly/api/v3/index.json`)到源上.
![night-build-add-nuget-source](images/night-build-add-nuget-source.png)
3. 单击`更新`按钮
4. 点击`确定`按钮保存
## 安装包
现在, 你可以从**管理NuGet包** 或 **程序包管理器控制台** 将预览/夜间程序包安装到你的项目中.
![night-build-add-nuget-package](images/night-build-add-nuget-package.png)
1. 在nuget浏览中,选择"包括预发行版".
2. 将包源更改为`全部`.
3. 搜索nuget包. 你将看到包的预发布格式为`(VERSION)-preview(DATE)` (如本示例中的**v0.16.0-preview20190401**).
4. 你可以单击`安装`按钮将包添加到项目中.

1448
docs/zh-Hans/Samples/Microservice-Demo.md

File diff suppressed because it is too large

70
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md

@ -20,11 +20,11 @@
下面的图片展示了从启动模板创建的项目是如何分层的.
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution.png)
![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution-v2.png)
### 创建Book实体
**领域层** 定义[实体](../../Entities.md)(`Acme.BookStore.Domain` 中).这个项目最主要的实体就是`Book`:
**领域层** 定义[实体](../../Entities.md)(`Acme.BookStore.Domain` 项目中).这个项目最主要的实体就是`Book`:
````C#
using System;
@ -50,14 +50,14 @@ namespace Acme.BookStore
}
````
* ABP有两个基本的实体基类: `AggregateRoot``Entity`.**Aggregate Root**是 **领域驱动设计(DDD)** 的概念.查看[实体](../../Entities.md)的更多信息和最佳实践.
* `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了(`CreationTime`, `CreatorId`, `LastModificationTime`... 等.)审计属性.
* `Book`实体的主键类型是`Guid`类型.
* ABP有两个基本的实体基类: `AggregateRoot``Entity`.**Aggregate Root**是 **领域驱动设计(DDD)** 的概念之一.更多信息和最佳实践请查看[实体文档](../../Entities.md).
* `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了一些审计属性(`CreationTime`, `CreatorId`, `LastModificationTime`... 等.).
* `Guid`是`Book`实体的主键类型.
* 使用 **数据注解** 为EF Core添加映射.或者你也可以使用 EF Core 自带的[fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling).
#### BookType枚举
下面是所有要用到的`BookType`枚举:
上面所用到的`BookType`枚举定义如下:
````C#
namespace Acme.BookStore
@ -79,21 +79,33 @@ namespace Acme.BookStore
#### 将Book实体添加到DbContext中
EF Core需要你将实体和DbContext建立关联.最简单的做法是在`Acme.BookStore.EntityFrameworkCore`项目的`BookStoreDbContext`类中添加`DbSet`属性.如:
EF Core需要你将实体和DbContext建立关联.最简单的做法是在`Acme.BookStore.EntityFrameworkCore`项目的`BookStoreDbContext`类中添加`DbSet`属性.如下所示:
````C#
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<Book> Book { get; set; }
public DbSet<Book> Books { get; set; }
...
}
````
#### 配置你的Book实体
从`Acme.BookStore.EntityFrameworkCore` 项目中打开 BookStoreDbContextModelCreatingExtensions.cs 文件, 在 ConfigureBookStore 方法最后添加如下代码来配置Book实体:
````C#
builder.Entity<Book>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Books", BookStoreConsts.DbSchema);
b.ConfigureExtraProperties();
});
````
#### 添加新的Migration并更新数据库
这个启动模板使用了[EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/)来创建并维护数据库结构.打开 **Package Manager Console (PMC)** (工具/Nuget包管理器菜单),选择 `Acme.BookStore.EntityFrameworkCore`作为默认的项目然后执行下面的命令:
这个启动模板使用了[EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/)来创建并维护数据库结构.打开 **程序包管理器控制台(Package Manager Console) (PMC)** (工具/Nuget包管理器菜单),选择 `Acme.BookStore.EntityFrameworkCore.DbMigrations`作为默认的项目然后执行下面的命令:
![bookstore-pmc-add-book-migration](images/bookstore-pmc-add-book-migration.png)
![bookstore-pmc-add-book-migration](images/bookstore-pmc-add-book-migration-v2.png)
这样就会在`Migrations`文件夹中创建一个新的migration类.然后执行`Update-Database`命令更新数据库结构.
@ -136,10 +148,10 @@ namespace Acme.BookStore
}
````
* **DTO**类被用来在 **基础设施层****应用层** **传递数据**.查看[DTO文档](../../Data-Transfer-Objects.md)查看更多信息.
* 为了在页面上展示书籍信息,`BookDto`被用来将书籍数据传递到基础设施层.
* **DTO**类被用来在 **表示层****应用层** **传递数据**.查看[DTO文档](../../Data-Transfer-Objects.md)查看更多信息.
* 为了在页面上展示书籍信息,`BookDto`被用来将书籍数据传递到表示层.
* `BookDto`继承自 `AuditedEntityDto<Guid>`.跟上面定义的`Book`类一样具有一些审计属性.
* `[AutoMapFrom(typeof(Book))]`用来创建从`Book`类到`BookDto`的映射.使用这种方法.你可以将`Book`对象自动转换成`BookDto`对象(而不是手动复制所有的属性).
* `[AutoMapFrom(typeof(Book))]`用来创建从`Book`类到`BookDto`的AutoMapper映射.使用这种方法.你可以将`Book`对象自动转换成`BookDto`对象(而不是手动复制所有的属性).
#### CreateUpdateBookDto
@ -171,7 +183,7 @@ namespace Acme.BookStore
}
````
* 这个DTO类在创建和更新书籍的时候被使用,用来从页面获取图书信息.
* 这个DTO类被用于在创建或更新书籍的时候从用户界面获取图书信息.
* 类中的属性定义了数据注解(如`[Required]`)用来定义有效性验证.ABP会自动校验DTO的数据有效性.
#### IBookAppService
@ -191,14 +203,14 @@ namespace Acme.BookStore
Guid, //Book实体的主键
PagedAndSortedResultRequestDto, //获取书籍的时候用于分页和排序
CreateUpdateBookDto, //用于创建书籍
CreateUpdateBookDto> //用更新书籍
CreateUpdateBookDto> //用更新书籍
{
}
}
````
* 为应用服务定义接口不是必须的,不过,我们推荐这么做.
* 为应用服务定义接口不是必须的,不过,这是推荐的最佳实践.
* `IAsyncCrudAppService`中定义了基础的 **CRUD**方法:`GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync``DeleteAsync`.不需要扩展它.取而代之,你可以继承空的`IApplicationService`接口定义你自己的方法.
* `IAsyncCrudAppService`有一些变体,你可以为每一个方法使用单个或者多个的DTO.(译者注:意思是类似EntityDto和UpdateEntityDto可以用同一个,也可以分别单独指定
)
@ -231,14 +243,14 @@ namespace Acme.BookStore
````
* `BookAppService`继承了`AsyncCrudAppService<...>`.`AsyncCrudAppService<...>`实现了上面定义的CRUD方法.
* `BookAppService`注入了`IRepository<Book, Guid>`,`IRepository<Book, Guid>`是默认为`Book`创建的仓储.ABP会自动为每一个聚合根(或实体)创建仓储.参考[仓储](../../Repositories.md).
* `BookAppService`使用了 `IObjectMapper` 将`Book`转换成`BookDto`,将`CreateUpdateBookDto`转换成`Book`.启动模板中使用了[AutoMapper](http://automapper.org/)作为映射工具.你可以像上面那样使用`AutoMapFrom` 和 `AutoMapTo`定义映射.查看[AutoMapper继承](../../AutoMapper-Integration.md)获取更多信息.
* `BookAppService`注入了`IRepository<Book, Guid>`,`IRepository<Book, Guid>`是默认为`Book`创建的仓储.ABP会自动为每一个聚合根(或实体)创建仓储.参考[仓储文档](../../Repositories.md).
* `BookAppService`使用了 `IObjectMapper` 将`Book`转换成`BookDto`,将`CreateUpdateBookDto`转换成`Book`.启动模板中使用了[AutoMapper](http://automapper.org/)作为对象映射提供程序.你可以像上面那样使用`AutoMapFrom` 和 `AutoMapTo`定义映射.查看[AutoMapper集成文档](../../AutoMapper-Integration.md)获取更多信息.
### 自动生成API Controllers
你通常需要创建 **Controllers** 将应用服务暴露为 **HTTP API**.这样浏览器或第三方客户端可以通过AJAX的方式访问它们.
ABP可以 **自动地** (../../AspNetCore/Auto-API-Controllers.md)将应用服务转换成MVC API Controllers.
ABP可以通过约定[**自动**](../../AspNetCore/Auto-API-Controllers.md)将应用服务转换成MVC API Controllers.
#### Swagger UI
@ -250,13 +262,13 @@ ABP可以 **自动地** (../../AspNetCore/Auto-API-Controllers.md)将应用服
### 动态JavaScript代理
通过AJAX的方式调用HTTP API接口是很常见的,你可以使用`$.ajax`或这其他的工具来调用接口.当然,ABP中提供了更好的方式.
在Javascript端通过AJAX的方式调用HTTP API接口是很常见的,你可以使用`$.ajax`或这其他的工具来调用接口.当然,ABP中提供了更好的方式.
ABP **自动** 为所有的API接口创建了JavaScript **代理**.因此,你可以像调用 **JavaScript function**一样调用任何接口.
#### 在浏览器的开发者控制台中测试接口
你可以使用你爱的浏览器的 **开发者控制台** 中轻松测试JavaScript代理.运行程序,并打开浏览器的 **开发者工具**(快捷键:F12),切换到 **Console**,输入下面的代码并回车:
你可以使用你爱的浏览器的 **开发者控制台** 中轻松测试JavaScript代理.运行程序,并打开浏览器的 **开发者工具**(快捷键:F12),切换到 **Console** 标签,输入下面的代码并回车:
````js
acme.bookStore.book.getList({}).done(function (result) { console.log(result); });
@ -265,14 +277,14 @@ acme.bookStore.book.getList({}).done(function (result) { console.log(result); })
* `acme.bookStore`是`BookAppService`的命名空间,转换成了[驼峰命名](https://en.wikipedia.org/wiki/Camel_case).
* `book`是`BookAppService`转换后的名字(去除了AppService后缀并转成了驼峰命名).
* `getList`是定义在`AsyncCrudAppService`基类中的`GetListAsync`方法转换后的名字(去除了Async后缀并转成了驼峰命名).
* `{}`参数用来传递一个空的对象给`GetListAsync`方法.GetListAsync期望的参数是`PagedAndSortedResultRequestDto`类型,`PagedAndSortedResultRequestDto`类型中定义了分页和排序.
* `{}`参数用来传递一个空的对象给`GetListAsync`方法.GetListAsync期望的参数是`PagedAndSortedResultRequestDto`类型的对象,`PagedAndSortedResultRequestDto`类型中定义了分页和排序选项.
* `getList`方法返回了一个`promise`.因此,你可以传递一个回调函数到`done`(或者`then`)方法中来获取服务返回的结果.
运行这段代码会产生下面的输出:
![bookstore-test-js-proxy-getlist](images/bookstore-test-js-proxy-getlist.png)
你可以看到服务器返回的 **book list**.你还可以切换到开发者工具的 **network** 查看客户端和服务器的连接:
你可以看到服务器返回的 **book list**.你还可以切换到开发者工具的 **network** 查看客户端到服务器端的通讯信息:
![bookstore-test-js-proxy-getlist-network](images/bookstore-test-js-proxy-getlist-network.png)
@ -292,10 +304,10 @@ successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7
### 创建书籍页面
现在我们来创建一些可见的可用的东西,我们使用[Razor Pages UI](https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start)代替经典的MVC.微软也推荐使用Razor Pages UI
现在我们来创建一些可见和可用的东西,取代经典的MVC,我们使用微软推荐的[Razor Pages UI](https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start).
`Acme.BookStore.Web`项目的`Pages`文件夹下创建一个新的文件夹叫`Books`并添加一个名`Index.cshtml`的Razor Page.
`Acme.BookStore.Web`项目的`Pages`文件夹下创建一个新的文件夹叫`Books`并添加一个名`Index.cshtml`的Razor Page.
![bookstore-add-index-page](images/bookstore-add-index-page.png)
@ -310,7 +322,7 @@ successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7
<h2>Books</h2>
````
* 改变Razor View Page Model默认的继承,使页面的 **inherits** 来自`BookStorePageBase`类(代替`PageModel`).`BookStorePageBase`类来自启动模板并提供了一些公开的属性/方法,这些属性/方法可以被所有的页面使用.
* 修改Razor View Page Model的默认继承,使页面 **继承** 自`BookStorePageBase`类(代替`PageModel`).`BookStorePageBase`类来自于启动模板,它提供了一些公开的可以被所有的页面使用的属性/方法.
#### 将Books页面添加到主菜单
@ -349,11 +361,11 @@ context.Menu.AddItem(
![bookstore-menu-items](images/bookstore-menu-items.png)
点击菜单就会调转到新增书籍的页面.
点击Books菜单项就会跳转到新增的书籍页面.
#### 书籍列表
我们会在页面上使用JQuery插件[Datatables.net](https://datatables.net/)来展示列表.Datatables可以完全通过AJAX工作,所以它很快而且有良好的用户体验.启动模板中已经配置好了Datatables,因此你可以在你的页面中直接使用,不需要引用样式和脚本文件.
我们会在页面上使用JQuery插件[Datatables.net](https://datatables.net/)来展示列表.Datatables可以完全通过AJAX工作,所以它很快而且有良好的用户体验.启动模板中已经配置好了Datatables插件,因此你可以在你的页面中直接使用,不需要引用样式和脚本文件.
##### 修改Index.cshtml
@ -388,7 +400,7 @@ context.Menu.AddItem(
</abp-card>
````
* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro)可以将添加外部的 **scripts**添加到页面中.它比标准的`script`标签多了很多额外的功能.它可以处理 **最小化**和 **版本**.查看[bundling & minification 文档](../../AspNetCore/Bundling-Minification.md)获取更多信息.
* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro)用于将外部的 **脚本** 添加到页面中.它比标准的`script`标签多了很多额外的功能.它可以处理 **最小化**和 **版本**.查看[捆绑 & 压缩文档](../../AspNetCore/Bundling-Minification.md)获取更多信息.
* `abp-card``abp-table` 是为Twitter Bootstrap的[card component](http://getbootstrap.com/docs/4.1/components/card/)封装的 **tag helpers**.ABP中有很多tag helpers,可以很方便的使用大多数[bootstrap](https://getbootstrap.com/)组件.你也可以使用原生的HTML标签代替tag helpers.使用tag helper可以通过智能提示和编译时类型检查减少HTML代码并防止错误.查看[tag helpers 文档](../../AspNetCore/Tag-Helpers.md).
* 你可以像上面本地化菜单一样 **本地化** 列名.

20
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md

@ -53,9 +53,9 @@ namespace Acme.BookStore.Pages.Books
}
````
* 这个类继承了 `BookStorePageModelBase` 而非默认的 `PageModel`. `BookStorePageModelBase` 继承了 `PageModel` 并且添加了一些Razor页面模型通用的属性和方法.
* 该类在 `Book` 属性上标记`[BindProperty]` 特性绑定了post请求提交上来的数据.
* 该类通过构造函数注入了 `IBookAppService` 应用服务,并且在 `OnPostAsync` 方法中调用了服务的 `CreateAsync` 方法.
* 该类派生于 `BookStorePageModelBase` 而非默认的 `PageModel`. `BookStorePageModelBase` 继承了 `PageModel` 并且添加了一些可以被你的page model类使用的通用属性和方法.
* `Book` 属性上的 `[BindProperty]` 特性将post请求提交上来的数据绑定到该属性上.
* 该类通过构造函数注入了 `IBookAppService` 应用服务,并且在 `OnPostAsync` 处理程序中调用了服务的 `CreateAsync` 方法.
##### CreateModal.cshtml
@ -82,7 +82,7 @@ namespace Acme.BookStore.Pages.Books
* 这个 modal 使用 `abp-dynamic-form` Tag Helper 根据 `CreateBookViewModel` 类自动构建了表单.
* `abp-model` 指定了 `Book` 属性为模型对象.
* `data-ajaxForm` 设置了表单通过AJAX提交.
* `data-ajaxForm` 设置了表单通过AJAX提交,而不是经典的页面回发.
* `abp-form-content` tag helper 作为表单控件渲染位置的占位符 (这是可选的,只有你在 `abp-dynamic-form` 中像本示例这样添加了其他内容才需要).
#### 添加 "New book" 按钮
@ -211,7 +211,7 @@ namespace Acme.BookStore
}
````
* 仅仅是添加 `[AutoMapFrom(typeof(BookDto))]` 特性就可以创建上述映射关系.
* 仅添加 `[AutoMapFrom(typeof(BookDto))]` 特性就可以创建上述映射关系.
#### EditModal.cshtml
@ -238,9 +238,9 @@ namespace Acme.BookStore
</abp-dynamic-form>
````
除了以下几点,这个页面内容和 `CreateModal.cshtml` 非常相似:
这个页面内容和 `CreateModal.cshtml` 非常相似,除了以下几点:
* 此页面包含了一个 `abp-input` 以保存所编辑book实体的 `Id` 属性.
* 此页面包含了一个 `abp-input` 以保存所编辑book实体的 `Id` 属性.
* 此页面指定的post地址是 `Books/EditModal` ,并用文本 *Update* 作为 modal 标题.
#### 为表格添加 "操作(Actions)" 下拉菜单
@ -325,8 +325,8 @@ $(function () {
````
* 通过 `abp.localization.getResource('BookStore')` 可以在客户端使用服务器端定义的相同的本地化语言文本.
* 定义 `editModal` `ModalManager` 来打开编辑用的 modal 对话框.
* 在 `columnDefs` 起始处新增一列作为 "Actions" 下拉按钮.
* 添加了一个名为 `editModal` 的新的 `ModalManager` 来打开编辑用的 modal 对话框.
* 在 `columnDefs` 起始处新增一列用于显示 "Actions" 下拉按钮.
* "Edit" 操作只是简单调用 `editModal.open` 来打开编辑对话框.
现在,你可以运行程序,通过编辑操作来更新任一个book实体.
@ -354,7 +354,7 @@ $(function () {
* `confirmMessage` 用来在实际执行 `action` 之前向用户进行确认.
* 通过javascript代理方法 `acme.bookStore.book.delete` 执行一个AJAX请求来删除一个book实体.
* `abp.notify.info` 用来提示用户操作成功.
* `abp.notify.info` 用来在执行删除操作后显示一个toastr通知信息.
最终的 `index.js` 文件内容如下所示:

3
docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md

@ -14,7 +14,6 @@
本解决方案中有两个测试项目:
![bookstore-test-projects](images/bookstore-test-projects.png)
* `Acme.BookStore.Application.Tests` 项目用于单元测试和集成测试.你可以在这个项目中为Application Service方法写测试代码.这个项目使用了 **EF Core SQLite in-memory** 数据库.
* `Acme.BookStore.Web.Tests` 项目用于包含Web层的完整集成测试.所以,你也可以在这里写关于UI页面的测试.
@ -59,7 +58,7 @@ namespace Acme.BookStore
}
````
* 这里直接使用了identity模块实现的 `IIdentityDataSeeder` 接口,创建了一个admin角色和admin用户.你同样可以在你的测试代码中直接使用这些代码.
* 这里直接使用了identity模块实现的 `IIdentityDataSeeder` 接口,创建了一个admin角色和admin用户.你可以在测试代码中使用它们.
* 你可以在 `BuildInternalAsync` 方法中添加你自己的测试数据.
按下方所示修改 `BookStoreTestDataBuilder` 类:

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-pmc-add-book-migration-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
docs/zh-Hans/Tutorials/AspNetCore-Mvc/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

20
docs/zh-Hans/Virtual-File-System.md

@ -1,6 +1,6 @@
## 虚拟文件系统
虚拟文件系统可以管理文件系统(磁盘)上实际上不存在的文件. 它主要用于将(js, css, image, cshtml ...)文件嵌入到程序集中, 并在运行时将它们用作物理文件.
虚拟文件系统使得管理物理上不存在于文件系统中(磁盘)的文件成为可能. 它主要用于将(js, css, image, cshtml ...)文件嵌入到程序集中, 并在运行时将它们象物理文件一样使用.
### Volo.Abp.VirtualFileSystem nuget包
@ -30,12 +30,12 @@ namespace MyCompany.MyProject
#### 注册嵌入式文件
首先需要把文件标记为嵌入式资源将文件嵌入到程序集中. 最简单的方式是在 **解决方案管理器** 中选择文件, 然后找到 **"属性"** 窗口将 **"生成操作"** 设置为 **"嵌入式资源"**.
要将文件嵌入到程序集中, 首先需要把文件标记为嵌入式资源. 最简单的方式是在 **解决方案管理器** 中选择文件, 然后找到 **"属性"** 窗口将 **"生成操作"** 设置为 **"嵌入式资源"**.
例如:
![build-action-embedded-resource-sample](images/build-action-embedded-resource-sample.png)
如果需要添加多个文件, 这会很乏味. 这时可以直接编辑 **.csproj** 文件:
如果需要添加多个文件, 这样做会很乏味. 作为选择, 你可以直接编辑 **.csproj** 文件:
````C#
<ItemGroup>
@ -45,7 +45,7 @@ namespace MyCompany.MyProject
此配置以递归方式添加项目的 **MyResources** 文件夹下的所有文件(包括将来新添加的文件).
然后应该使用 `VirtualFileSystemOptions` 来配置模块, 以便将嵌入式文件注册到虚拟文件系统. 例如:
然后需要使用 `VirtualFileSystemOptions` 来配置模块, 以便将嵌入式文件注册到虚拟文件系统. 例如:
````C#
using Microsoft.Extensions.DependencyInjection;
@ -105,9 +105,9 @@ public class MyService
#### 在开发过程中处理嵌入式文件
通过引用程序集(或添加nuget包)将文件嵌入模块程序集并从另一个项目中使用它对于创建可重用模块非常有价值. 但是, 这使得开发模块本身变得有点困难.
将文件嵌入到模块程序集中并能够通过引用程序集(或添加nuget包)在另一个项目中使用它对于创建可重用模块非常有价值. 但是, 这使得开发模块本身变得有点困难.
假设你正在开发一个包含嵌入式JavaScript文件的模块. 当你更改文件时, 你必须重新编译项目, 重新启动应用程序并刷新浏览器页面以进行更改. 显然, 这是非常耗时和乏味的.
假设你正在开发一个包含嵌入式JavaScript文件的模块. 当你更改文件时, 你必须重新编译项目, 重新启动应用程序并刷新浏览器页面以使更改生效. 显然, 这是非常耗时和乏味的.
我们需要的是应用程序在开发时直接使用物理文件的能力, 让浏览器刷新时同步JavaScript文件的任何更改. `ReplaceEmbeddedByPhysical` 方法使其成为可能.
@ -145,7 +145,7 @@ public class MyWebAppModule : AbpModule
* 虚拟文件可以像Web应用程序上的物理(静态)文件一样使用.
* Razor Views, Razor Pages, js, css, 图像文件和所有其他Web内容可以嵌入到程序集中并像物理文件一样使用.
* 应用程序(或其他模块)可以覆盖模块的虚拟文件, 就像将具有同名和扩展名文件放入虚拟文件的同一文件夹中一样.
* 应用程序(或其他模块)可以覆盖模块的虚拟文件, 就像将具有同名和扩展名文件放入虚拟文件的同一文件夹中一样.
#### 虚拟文件中间件
@ -155,12 +155,12 @@ public class MyWebAppModule : AbpModule
app.UseVirtualFiles();
````
在静态文件中间件之后添加虚拟文件中间件, 可以通过放置在同一位置,使用物理文件来覆盖虚拟文件.
在静态文件中间件之后添加虚拟文件中间件, 使得通过在虚拟文件相同的位置放置物理文件, 从而用物理文件覆盖虚拟文件成为可能.
> 虚拟文件中间件只是像静态文件一样提供虚拟wwwroot文件夹内容.
> 虚拟文件中间件可以虚拟wwwroot文件夹中的内容 - 就像静态文件一样.
#### Views & Pages
无需任何配置即可在应用程序中使用嵌入式的 razor Views/pages. 只需要将它们放入模块开发中的标准 Views/Pages 虚拟文件夹即可.
无需任何配置即可在应用程序中使用嵌入式的 razor Views/pages. 只需要将它们放置在要开发的模块中的标准 Views/Pages 虚拟文件夹即可.
如果模块/应用程序将新文件放置同一位置, 则会覆盖嵌入式的 Views/Pages.

11
docs/zh-Hans/docs-nav.json

@ -67,8 +67,7 @@
"path": "Exception-Handling.md"
},
{
"text": "验证",
"path": "Validation.md"
"text": "验证"
},
{
"text": "授权"
@ -145,6 +144,7 @@
},
{
"text": "领域驱动设计",
"path": "Domain-Driven-Design.md",
"items": [
{
"text": "领域层",
@ -180,8 +180,7 @@
"text": "数据传输对象(DTO)"
},
{
"text": "工作单元",
"path": "Unit-Of-Work.md"
"text": "工作单元"
}
]
}
@ -278,6 +277,10 @@
{
"text": "测试"
},
{
"text": "每日构建",
"path": "Nightly-Builds.md"
},
{
"text": "贡献指南",
"path": "Contribution/Index.md"

BIN
docs/zh-Hans/images/bookstore-visual-studio-solution-v2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

BIN
docs/zh-Hans/images/docs-create-project.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/zh-Hans/images/github-access-token-private-repo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
docs/zh-Hans/images/github-access-token-public-repo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

BIN
docs/zh-Hans/images/github-myusername.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
docs/zh-Hans/images/microservice-sample-authserver-home.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
docs/zh-Hans/images/microservice-sample-authserver-login.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/zh-Hans/images/microservice-sample-backend-ui-permissions.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/zh-Hans/images/microservice-sample-backend-ui.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
docs/zh-Hans/images/microservice-sample-blogservice-permission-in-database.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
docs/zh-Hans/images/microservice-sample-diagram-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
docs/zh-Hans/images/microservice-sample-kibana-1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
docs/zh-Hans/images/microservice-sample-kibana-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
docs/zh-Hans/images/microservice-sample-product-module-in-solution.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

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

Loading…
Cancel
Save