Merge remote-tracking branch 'origin/dev' into cms-kit/contents-as-markdown

pull/8191/head
enisn 5 years ago
commit ee0b7e7ade

@ -196,6 +196,7 @@
"MultipleDBOptionsExplanation": "The framework can work with any data source, while the following providers are officially developed and supported;",
"SelectLanguage": "Select language",
"LatestArticleOnCommunity": "Latest Article on ABP Community",
"Register": "Register"
"Register": "Register",
"IsDownloadable": "Is downloadable"
}
}

@ -0,0 +1,93 @@
# ABP Framework 4.3 RC Has Been Published
We are super excited to announce the ABP Framework 4.3 RC (Release Candidate). Here, a list of highlights for this release;
* **CMS Kit** module initial release.
* **Blazor UI server-side** support.
* **Module extensibility** system for the Blazor UI.
* Angular UI **resource owner password** flow comes back.
* **Volo.Abp.EntityFrameworkCore.Oracle** package is now compatible with .NET 5.
* CLI support to easily add the **Basic Theme** into the solution.
* New **IInitLogger** service to write logs before dependency injection phase completed.
* Infrastructure for **multi-lingual entities**.
Beside the new features above, we've done many performance improvements, enhancements and bug fixes on the current features. See the [4.3 milestone](https://github.com/abpframework/abp/milestone/49) on GitHub for all changes made on this version.
This version was a big development journey for us; [150+ issues](https://github.com/abpframework/abp/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.3-preview) resolved, [260+ PRs](https://github.com/abpframework/abp/pulls?q=is%3Aopen+is%3Apr+milestone%3A4.3-preview) merged and 1,600+ commits done only in the [main framework repository](https://github.com/abpframework/abp). **Thanks to the ABP Framework team and all the contributors.**
## The Migration Guide
We normally don't make breaking changes in minor versions. However, this version has some small breaking changes, mostly related to Blazor UI WebAssembly & Server separation. **Please check the [migration guide](https://docs.abp.io/en/abp/4.3/Migration-Guides/Abp-4_3) before starting with the version 4.3**.
## Get Started With The 4.3 RC
If you want to try the version 4.3 today, follow the steps below;
1) **Upgrade** the ABP CLI to the version `4.3.0-rc.1` using a command line terminal:
````bash
dotnet tool update Volo.Abp.Cli -g --version 4.3.0-rc.1
````
**or install** if you haven't installed before:
````bash
dotnet tool install Volo.Abp.Cli -g --version 4.3.0-rc.1
````
2) Create a **new application** with the `--preview` option:
````bash
abp new BookStore --preview
````
See the [ABP CLI documentation](https://docs.abp.io/en/abp/4.3/CLI) for all the available options.
> You can also use the *Direct Download* tab on the [Get Started](https://abp.io/get-started) page by selecting the **Preview checkbox**.
## What's New With The ABP Framework 4.3
### CMS Kit
TODO
### Blazor Server Side
TODO
### Blazor UI Module Extensibility
TODO
### Angular UI Resource Owner Password Flow
TODO
### Volo.Abp.EntityFrameworkCore.Oracle Package
TODO
### Add Basic Theme Into Your Solution
TODO
### IInitLogger
TODO
### Multi-Lingual Entities
TODO
### Other News
* [#7423](https://github.com/abpframework/abp/issues/7423) MongoDB repository base aggregation API.
* [#8163](https://github.com/abpframework/abp/issues/8163) Ignoring files on minification for MVC UI.
* [#7799](https://github.com/abpframework/abp/pull/7799) Added `RequiredPermissionName` to `ApplicationMenuItem` for MVC & Blazor UI to easily show/hide menu items based on user permissions. Also added `RequiredPermissionName` to `ToolbarItem` for the MVC UI for the same purpose.
* [#7523](https://github.com/abpframework/abp/pull/7523) Add more bundle methods to the distributed cache.
See the [4.3 milestone](https://github.com/abpframework/abp/milestone/49) on GitHub for all changes made on this version.
## Feedback
Please check out the ABP Framework 4.3 RC and [provide feedback](https://github.com/abpframework/abp/issues/new) to help us to release a more stable version. **The planned release date for the [4.3.0 final](https://github.com/abpframework/abp/milestone/50) version is April 15, 2021**.

@ -0,0 +1,3 @@
# ABP Framework 4.x to 4.3 Migration Guide
TODO

@ -35,11 +35,16 @@ namespace Volo.Abp.Cli.Commands
}
var version = commandLineArgs.Options.GetOrNull(Options.Version.Short, Options.Version.Long);
var withSourceCode =commandLineArgs.Options.ContainsKey(Options.SourceCode.Long);
var addSourceCodeToSolutionFile = withSourceCode && commandLineArgs.Options.ContainsKey("add-to-solution-file");
await ProjectNugetPackageAdder.AddAsync(
GetProjectFile(commandLineArgs),
commandLineArgs.Target,
version
version,
true,
withSourceCode,
addSourceCodeToSolutionFile
);
}
@ -128,6 +133,11 @@ namespace Volo.Abp.Cli.Commands
public const string Short = "v";
public const string Long = "version";
}
public static class SourceCode
{
public const string Long = "with-source-code";
}
}
}
}

@ -59,7 +59,7 @@ namespace Volo.Abp.Cli.Commands
commandLineArgs.Options.Add(CliConsts.Command, commandLineArgs.Command);
await _sourceCodeDownloadService.DownloadAsync(
await _sourceCodeDownloadService.DownloadModuleAsync(
commandLineArgs.Target, outputFolder, version, gitHubAbpLocalRepositoryPath, gitHubVoloLocalRepositoryPath, commandLineArgs.Options);
}

@ -17,15 +17,17 @@ namespace Volo.Abp.Cli.Commands.Services
public class SourceCodeDownloadService : ITransientDependency
{
public ModuleProjectBuilder ModuleProjectBuilder { get; }
public PackageProjectBuilder PackageProjectBuilder { get; }
public ILogger<SourceCodeDownloadService> Logger { get; set; }
public SourceCodeDownloadService(ModuleProjectBuilder moduleProjectBuilder)
public SourceCodeDownloadService(ModuleProjectBuilder moduleProjectBuilder, PackageProjectBuilder packageProjectBuilder)
{
ModuleProjectBuilder = moduleProjectBuilder;
PackageProjectBuilder = packageProjectBuilder;
Logger = NullLogger<SourceCodeDownloadService>.Instance;
}
public async Task DownloadAsync(string moduleName, string outputFolder, string version, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath, AbpCommandLineOptions options)
public async Task DownloadModuleAsync(string moduleName, string outputFolder, string version, string gitHubAbpLocalRepositoryPath, string gitHubVoloLocalRepositoryPath, AbpCommandLineOptions options)
{
Logger.LogInformation("Downloading source code of " + moduleName);
Logger.LogInformation("Version: " + version);
@ -90,6 +92,62 @@ namespace Volo.Abp.Cli.Commands.Services
Logger.LogInformation($"'{moduleName}' has been successfully downloaded to '{outputFolder}'");
}
public async Task DownloadPackageAsync(string packageName, string outputFolder, string version)
{
Logger.LogInformation("Downloading source code of " + packageName);
Logger.LogInformation("Version: " + version);
Logger.LogInformation("Output folder: " + outputFolder);
var result = await PackageProjectBuilder.BuildAsync(
new ProjectBuildArgs(
SolutionName.Parse(packageName),
packageName,
version
)
);
using (var templateFileStream = new MemoryStream(result.ZipContent))
{
using (var zipInputStream = new ZipInputStream(templateFileStream))
{
var zipEntry = zipInputStream.GetNextEntry();
while (zipEntry != null)
{
if (IsAngularTestFile(zipEntry.Name))
{
zipEntry = zipInputStream.GetNextEntry();
continue;
}
var fullZipToPath = Path.Combine(outputFolder, zipEntry.Name);
var directoryName = Path.GetDirectoryName(fullZipToPath);
if (!string.IsNullOrEmpty(directoryName))
{
Directory.CreateDirectory(directoryName);
}
var fileName = Path.GetFileName(fullZipToPath);
if (fileName.Length == 0)
{
zipEntry = zipInputStream.GetNextEntry();
continue;
}
var buffer = new byte[4096]; // 4K is optimum
using (var streamWriter = File.Create(fullZipToPath))
{
StreamUtils.Copy(zipInputStream, streamWriter, buffer);
}
zipEntry = zipInputStream.GetNextEntry();
}
}
}
Logger.LogInformation($"'{packageName}' has been successfully downloaded to '{outputFolder}'");
}
private bool IsAngularTestFile(string zipEntryName)
{
if (string.IsNullOrEmpty(zipEntryName))

@ -159,6 +159,11 @@ namespace Volo.Abp.Cli.ProjectBuilding
private async Task<string> GetTemplateNugetVersionAsync(string name, string type, string version)
{
if (type != SourceCodeTypes.Template)
{
return null;
}
try
{
var url = $"{CliUrls.WwwAbpIo}api/download/{type}/get-nuget-version/";

@ -0,0 +1,21 @@
using Volo.Abp.Cli.ProjectBuilding.Building.Steps;
using Volo.Abp.Cli.ProjectBuilding.Templates;
namespace Volo.Abp.Cli.ProjectBuilding.Building
{
public static class PackageProjectBuildPipelineBuilder
{
public static ProjectBuildPipeline Build(ProjectBuildContext context)
{
var pipeline = new ProjectBuildPipeline(context);
pipeline.Steps.Add(new FileEntryListReadStep());
pipeline.Steps.Add(new ProjectReferenceReplaceStep());
pipeline.Steps.Add(new ReplaceCommonPropsStep());
pipeline.Steps.Add(new ReplaceConfigureAwaitPropsStep());
pipeline.Steps.Add(new CreateProjectResultZipStep());
return pipeline;
}
}
}

@ -1,5 +1,7 @@
using JetBrains.Annotations;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Cli.ProjectBuilding.Files;
using Volo.Abp.Cli.ProjectModification;
namespace Volo.Abp.Cli.ProjectBuilding.Building
{
@ -15,22 +17,29 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building
public ModuleInfo Module { get; }
public NugetPackageInfo Package { get; }
public FileEntryList Files { get; set; }
public ProjectResult Result { get; set; }
public List<string> Symbols { get; } //TODO: Fill the symbols, like "UI-Angular", "CMS-KIT"!
public ProjectBuildContext(
TemplateInfo template,
ModuleInfo module,
NugetPackageInfo package,
[NotNull] TemplateFile templateFile,
[NotNull] ProjectBuildArgs buildArgs)
{
Template = template;
Module = module;
Package = package;
TemplateFile = Check.NotNull(templateFile, nameof(templateFile));
BuildArgs = Check.NotNull(buildArgs, nameof(buildArgs));
Symbols = new List<string>();
Result = new ProjectResult();
}
}
}
}

@ -1,22 +0,0 @@
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class RemoveCmsKitStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
var commonFiles = context.Files.Where(f =>
f.Name.EndsWith(".csproj") ||
f.Name.EndsWith(".cs") ||
f.Name.EndsWith(".json") ||
f.Name.EndsWith(".cshtml"));
foreach (var file in commonFiles)
{
file.RemoveTemplateCodeIfNot("CMS-KIT");
}
}
}
}

@ -1,19 +0,0 @@
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class RemoveEfCoreRelatedCodeStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
foreach (var file in context.Files)
{
if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".json"))
{
file.RemoveTemplateCodeIfNot("EFCORE");
}
}
}
}
}

@ -1,21 +0,0 @@
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class RemoveGlobalFeaturesPackageStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
var commonFiles = context.Files.Where(f =>
f.Name.EndsWith(".csproj") ||
f.Name.EndsWith(".cs") ||
f.Name.EndsWith(".cshtml"));
foreach (var file in commonFiles)
{
file.RemoveTemplateCodeIf("CMS-KIT");
}
}
}
}

@ -1,20 +0,0 @@
using System;
using System.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class RemovePublicRedisStep : ProjectBuildPipelineStep
{
public override void Execute(ProjectBuildContext context)
{
foreach (var file in context.Files)
{
if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".json"))
{
file.RemoveTemplateCodeIfNot("PUBLIC-REDIS");
}
}
}
}
}

@ -10,7 +10,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
if (file.Name.EndsWith(".cs") || file.Name.EndsWith(".csproj") || file.Name.EndsWith(".cshtml") || file.Name.EndsWith(".json"))
{
file.RemoveTemplateCode();
file.RemoveTemplateCode(context.Symbols);
file.RemoveTemplateCodeMarkers();
}
}

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Volo.Abp.Cli.ProjectBuilding.Files
{
@ -11,19 +13,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files
return file;
}
public static void RemoveTemplateCode(this FileEntry file)
public static void RemoveTemplateCode(this FileEntry file, List<string> symbols)
{
RemoveMarkedTemplateCode(file, "<TEMPLATE-REMOVE>");
}
public static void RemoveTemplateCodeIf(this FileEntry file, string condition)
{
RemoveByCondition(file, "IF", condition);
}
public static void RemoveTemplateCodeIfNot(this FileEntry file, string condition)
{
RemoveByCondition(file, "IF-NOT", condition);
RemoveMarkedTemplateCode(file, symbols);
}
public static void RemoveTemplateCodeMarkers(this FileEntry file)
@ -57,12 +49,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files
file.SetLines(newLines);
}
private static void RemoveByCondition(this FileEntry file, string conditionName, string condition)
{
RemoveMarkedTemplateCode(file, $"<TEMPLATE-REMOVE {conditionName}='{condition}'>");
}
private static void RemoveMarkedTemplateCode(this FileEntry file, string beginMark)
private static void RemoveMarkedTemplateCode(this FileEntry file, List<string> symbols)
{
if (!file.Content.Contains("</TEMPLATE-REMOVE>"))
{
@ -76,8 +63,40 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains(beginMark))
if (lines[i].Contains("<TEMPLATE-REMOVE"))
{
var parsedMarker = ParseTemplateRemoveMarker(lines[i]);
bool sectionShouldBeRemoved = false;
if (!parsedMarker.Symbols.Any())
{
sectionShouldBeRemoved = true;
}
else if(parsedMarker.Symbols.Count == 1)
{
sectionShouldBeRemoved = !parsedMarker.IsNegativeCondition
? symbols.Contains(parsedMarker.Symbols[0], StringComparer.InvariantCultureIgnoreCase)
: !symbols.Contains(parsedMarker.Symbols[0], StringComparer.InvariantCultureIgnoreCase);
}
else if (parsedMarker.Operator == Operator.And)
{
sectionShouldBeRemoved = parsedMarker.Symbols.Any(s => !parsedMarker.IsNegativeCondition
? symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase)
: !symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase));
}
else if (parsedMarker.Operator == Operator.Or)
{
sectionShouldBeRemoved = !parsedMarker.Symbols.All(s => !parsedMarker.IsNegativeCondition
? symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase)
: !symbols.Contains(s, StringComparer.InvariantCultureIgnoreCase) == false);
}
if (!sectionShouldBeRemoved)
{
continue;
}
while (i < lines.Length && !lines[i].Contains("</TEMPLATE-REMOVE>"))
{
++i;
@ -94,5 +113,65 @@ namespace Volo.Abp.Cli.ProjectBuilding.Files
file.SetLines(newLines);
}
private static TemplateRemoveMarkerParseResult ParseTemplateRemoveMarker(string marker)
{
var result = new TemplateRemoveMarkerParseResult();
var condition = marker.Trim()
.RemovePreFix("//").Trim()
.RemovePreFix("@*").Trim()
.RemovePreFix("<!--").Trim()
.RemovePreFix("<TEMPLATE-REMOVE").Trim()
.RemovePostFix("*@").Trim()
.RemovePostFix("-->").Trim()
.RemovePostFix(">").Trim();
if (string.IsNullOrWhiteSpace(condition))
{
return result;
}
var conditionSplitted = condition.Split("=");
result.IsNegativeCondition = conditionSplitted[0] == "IF-NOT";
var conditionContent = string.Join("=", conditionSplitted.Skip(1))
.RemovePostFix("\"").RemovePreFix("\"")
.RemovePostFix("'").RemovePreFix("'");
if (conditionContent.Contains("&&"))
{
result.Operator = Operator.And;
result.Symbols = conditionContent.Split("&&").ToList();
}
else if(conditionContent.Contains("||"))
{
result.Operator = Operator.Or;
result.Symbols = conditionContent.Split("||").ToList();
}
else
{
result.Symbols.Add(conditionContent);
}
return result;
}
private class TemplateRemoveMarkerParseResult
{
public List<string> Symbols { get; set; } = new List<string>();
public Operator Operator { get; set; } = Operator.None;
public bool IsNegativeCondition { get; set; }
}
private enum Operator
{
None,
And,
Or
}
}
}

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Volo.Abp.Cli.ProjectModification;
namespace Volo.Abp.Cli.ProjectBuilding
{
public interface INugetPackageInfoProvider
{
Task<NugetPackageInfo> GetAsync(string name);
}
}

@ -67,6 +67,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
var context = new ProjectBuildContext(
null,
moduleInfo,
null,
templateFile,
args
);

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Json;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.ProjectModification;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.Cli.ProjectBuilding
{
public class NugetPackageInfoProvider : INugetPackageInfoProvider, ITransientDependency
{
public IJsonSerializer JsonSerializer { get; }
public ICancellationTokenProvider CancellationTokenProvider { get; }
public IRemoteServiceExceptionHandler RemoteServiceExceptionHandler { get; }
private readonly CliHttpClientFactory _cliHttpClientFactory;
public NugetPackageInfoProvider(
IJsonSerializer jsonSerializer,
ICancellationTokenProvider cancellationTokenProvider,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
CliHttpClientFactory cliHttpClientFactory)
{
JsonSerializer = jsonSerializer;
CancellationTokenProvider = cancellationTokenProvider;
RemoteServiceExceptionHandler = remoteServiceExceptionHandler;
_cliHttpClientFactory = cliHttpClientFactory;
}
public async Task<NugetPackageInfo> GetAsync(string name)
{
var packageList = await GetPackageListInternalAsync();
var package = packageList.FirstOrDefault(m => m.Name == name);
if (package == null)
{
throw new Exception("Package is not found or downloadable!");
}
return package;
}
private async Task<List<NugetPackageInfo>> GetPackageListInternalAsync()
{
var client = _cliHttpClientFactory.CreateClient();
using (var responseMessage = await client.GetAsync(
$"{CliUrls.WwwAbpIo}api/download/packages/",
CancellationTokenProvider.Token
))
{
await RemoteServiceExceptionHandler.EnsureSuccessfulHttpResponseAsync(responseMessage);
var result = await responseMessage.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<List<NugetPackageInfo>>(result);
}
}
}
}

@ -0,0 +1,109 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Licensing;
using Volo.Abp.Cli.ProjectBuilding.Analyticses;
using Volo.Abp.Cli.ProjectBuilding.Building;
using Volo.Abp.Cli.ProjectModification;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Json;
namespace Volo.Abp.Cli.ProjectBuilding
{
public class PackageProjectBuilder : IProjectBuilder, ITransientDependency
{
public ILogger<PackageProjectBuilder> Logger { get; set; }
protected ISourceCodeStore SourceCodeStore { get; }
protected INugetPackageInfoProvider NugetPackageInfoProvider { get; }
protected ICliAnalyticsCollect CliAnalyticsCollect { get; }
protected AbpCliOptions Options { get; }
protected IJsonSerializer JsonSerializer { get; }
protected IApiKeyService ApiKeyService { get; }
public PackageProjectBuilder(ISourceCodeStore sourceCodeStore,
INugetPackageInfoProvider nugetPackageInfoProvider,
ICliAnalyticsCollect cliAnalyticsCollect,
IOptions<AbpCliOptions> options,
IJsonSerializer jsonSerializer,
IApiKeyService apiKeyService)
{
SourceCodeStore = sourceCodeStore;
NugetPackageInfoProvider = nugetPackageInfoProvider;
CliAnalyticsCollect = cliAnalyticsCollect;
Options = options.Value;
JsonSerializer = jsonSerializer;
ApiKeyService = apiKeyService;
Logger = NullLogger<PackageProjectBuilder>.Instance;
}
public async Task<ProjectBuildResult> BuildAsync(ProjectBuildArgs args)
{
var packageInfo = await GetPackageInfoAsync(args);
var templateFile = await SourceCodeStore.GetAsync(
args.TemplateName,
SourceCodeTypes.Package,
args.Version,
null,
args.ExtraProperties.ContainsKey(GetSourceCommand.Options.Preview.Long)
);
var apiKeyResult = await ApiKeyService.GetApiKeyOrNullAsync();
if (apiKeyResult?.ApiKey != null)
{
args.ExtraProperties["api-key"] = apiKeyResult.ApiKey;
}
if (apiKeyResult?.LicenseCode != null)
{
args.ExtraProperties["license-code"] = apiKeyResult.LicenseCode;
}
var context = new ProjectBuildContext(
null,
null,
packageInfo,
templateFile,
args
);
PackageProjectBuildPipelineBuilder.Build(context).Execute();
// Exclude unwanted or known options.
var options = args.ExtraProperties
.Where(x => !x.Key.Equals(CliConsts.Command, StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.Key.Equals(NewCommand.Options.OutputFolder.Long, StringComparison.InvariantCultureIgnoreCase) &&
!x.Key.Equals(NewCommand.Options.OutputFolder.Short, StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.Key.Equals(NewCommand.Options.Version.Long, StringComparison.InvariantCultureIgnoreCase) &&
!x.Key.Equals(NewCommand.Options.Version.Short, StringComparison.InvariantCultureIgnoreCase))
.Where(x => !x.Key.Equals(NewCommand.Options.TemplateSource.Short, StringComparison.InvariantCultureIgnoreCase) &&
!x.Key.Equals(NewCommand.Options.TemplateSource.Long, StringComparison.InvariantCultureIgnoreCase))
.Select(x => x.Key).ToList();
await CliAnalyticsCollect.CollectAsync(new CliAnalyticsCollectInputDto
{
Tool = Options.ToolName,
Command = args.ExtraProperties.ContainsKey(CliConsts.Command) ? args.ExtraProperties[CliConsts.Command] : "",
DatabaseProvider = null,
IsTiered = null,
UiFramework = null,
Options = JsonSerializer.Serialize(options),
ProjectName = null,
TemplateName = args.TemplateName,
TemplateVersion = templateFile.Version
});
return new ProjectBuildResult(context.Result.ZipContent, args.TemplateName);
}
private async Task<NugetPackageInfo> GetPackageInfoAsync(ProjectBuildArgs args)
{
return await NugetPackageInfoProvider.GetAsync(args.TemplateName);
}
}
}

@ -5,5 +5,7 @@
public const string Template = "template";
public const string Module = "module";
public const string Package = "package";
}
}

@ -105,6 +105,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
var context = new ProjectBuildContext(
templateInfo,
null,
null,
templateFile,
args
);

@ -28,6 +28,7 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
SwitchDatabaseProvider(context, steps);
DeleteUnrelatedProjects(context, steps);
RemoveMigrations(context, steps);
ConfigureTieredArchitecture(context, steps);
ConfigurePublicWebSite(context, steps);
RemoveUnnecessaryPorts(context, steps);
RandomizeSslPorts(context, steps);
@ -64,7 +65,10 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.EntityFrameworkCore.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.EntityFrameworkCore.Tests"));
steps.Add(new RemoveEfCoreRelatedCodeStep());
}
else
{
context.Symbols.Add("EFCORE");
}
if (context.BuildArgs.DatabaseProvider != DatabaseProvider.MongoDb)
@ -144,14 +148,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
{
if (!context.BuildArgs.PublicWebSite)
{
if (!context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) &&
!context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server"))
if (context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) ||
context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server"))
{
steps.Add(new RemovePublicRedisStep());
context.Symbols.Add("PUBLIC-REDIS");
}
steps.Add(new RemoveCmsKitStep());
return;
}
else
{
context.Symbols.Add("public-website");
}
if (context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) || context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server"))
@ -164,14 +169,9 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
steps.Add(new ChangePublicAuthPortStep());
}
// We disabled cms-kit for v4.2 release.
if (true || context.BuildArgs.ExtraProperties.ContainsKey("without-cms-kit"))
{
steps.Add(new RemoveCmsKitStep());
}
else
if (!context.BuildArgs.ExtraProperties.ContainsKey("without-cms-kit"))
{
steps.Add(new RemoveGlobalFeaturesPackageStep());
context.Symbols.Add("CMS-KIT");
}
}
@ -197,6 +197,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
private static void ConfigureWithBlazorUi(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
context.Symbols.Add("ui:blazor");
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Host"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests"));
@ -218,6 +220,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
private static void ConfigureWithBlazorServerUi(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
context.Symbols.Add("ui:blazor-server");
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Blazor"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Host"));
@ -242,6 +246,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
private static void ConfigureWithMvcUi(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
context.Symbols.Add("ui:mvc");
if (context.BuildArgs.ExtraProperties.ContainsKey("tiered"))
{
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web"));
@ -262,6 +268,8 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
private static void ConfigureWithAngularUi(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
context.Symbols.Add("ui:angular");
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Host"));
steps.Add(new RemoveProjectFromSolutionStep("MyCompanyName.MyProjectName.Web.Tests", projectFolderPath: "/aspnet-core/test/MyCompanyName.MyProjectName.Web.Tests"));
@ -312,6 +320,15 @@ namespace Volo.Abp.Cli.ProjectBuilding.Templates.App
);
}
private void ConfigureTieredArchitecture(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
if (context.BuildArgs.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long) ||
context.BuildArgs.ExtraProperties.ContainsKey("separate-identity-server"))
{
context.Symbols.Add("tiered");
}
}
private static void RandomizeStringEncryption(ProjectBuildContext context, List<ProjectBuildPipelineStep> steps)
{
steps.Add(new RandomizeStringEncryptionStep());

@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Cli.Args;
using Volo.Abp.Cli.Commands;
using Volo.Abp.Cli.Commands.Services;
using Volo.Abp.Cli.Http;
using Volo.Abp.Cli.ProjectBuilding;
using Volo.Abp.Cli.Utils;
@ -22,6 +23,8 @@ namespace Volo.Abp.Cli.ProjectModification
{
public ILogger<ProjectNugetPackageAdder> Logger { get; set; }
public BundleCommand BundleCommand { get; }
public SourceCodeDownloadService SourceCodeDownloadService { get; }
public SolutionFileModifier SolutionFileModifier { get; }
protected IJsonSerializer JsonSerializer { get; }
protected ProjectNpmPackageAdder NpmPackageAdder { get; }
@ -38,7 +41,9 @@ namespace Volo.Abp.Cli.ProjectModification
ModuleClassDependcyAdder moduleClassDependcyAdder,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
BundleCommand bundleCommand,
CliHttpClientFactory cliHttpClientFactory)
CliHttpClientFactory cliHttpClientFactory,
SourceCodeDownloadService sourceCodeDownloadService,
SolutionFileModifier solutionFileModifier)
{
JsonSerializer = jsonSerializer;
NpmPackageAdder = npmPackageAdder;
@ -46,32 +51,162 @@ namespace Volo.Abp.Cli.ProjectModification
ModuleClassDependcyAdder = moduleClassDependcyAdder;
RemoteServiceExceptionHandler = remoteServiceExceptionHandler;
BundleCommand = bundleCommand;
SourceCodeDownloadService = sourceCodeDownloadService;
SolutionFileModifier = solutionFileModifier;
_cliHttpClientFactory = cliHttpClientFactory;
Logger = NullLogger<ProjectNugetPackageAdder>.Instance;
}
public async Task AddAsync(string projectFile, string packageName, string version = null)
public async Task AddAsync(
string projectFile,
string packageName,
string version = null,
bool useDotnetCliToInstall = true,
bool withSourceCode = false,
bool addSourceCodeToSolutionFile = false)
{
await AddAsync(
projectFile,
await FindNugetPackageInfoAsync(packageName),
version
version,
useDotnetCliToInstall,
withSourceCode,
addSourceCodeToSolutionFile
);
}
public async Task AddAsync(string projectFile, NugetPackageInfo package, string version = null,
bool useDotnetCliToInstall = true)
public async Task AddAsync(
string projectFile,
NugetPackageInfo package,
string version = null,
bool useDotnetCliToInstall = true,
bool withSourceCode = false,
bool addSourceCodeToSolutionFile = false)
{
var projectFileContent = File.ReadAllText(projectFile);
if (version == null)
{
version = GetAbpVersionOrNull(projectFile);
}
if (projectFileContent.Contains($"\"{package.Name}\""))
await AddAsPackageReference(projectFile, package, version, useDotnetCliToInstall);
if (withSourceCode)
{
await AddSourceCode(projectFile, package, version);
await ConvertPackageReferenceToProjectReference(projectFile, package);
if (addSourceCodeToSolutionFile)
{
await SolutionFileModifier.AddPackageToSolutionFileAsync(package, FindSolutionFile(projectFile));
}
}
}
private async Task ConvertPackageReferenceToProjectReference(string projectFile, NugetPackageInfo package)
{
var content = File.ReadAllText(projectFile);
var doc = new XmlDocument() {PreserveWhitespace = true};
doc.Load(StreamHelper.GenerateStreamFromString(content));
var nodes = doc.SelectNodes(
$"/Project/ItemGroup/PackageReference[starts-with(@Include, '{package.Name}')]");
if (nodes == null)
{
return;
}
if (version == null)
var downloadedProjectPath = FindRelativeFolderToDownloadPackage(projectFile, package);
var oldNodeIncludeValue = nodes[0]?.Attributes?["Include"]?.Value;
if (package.Name == oldNodeIncludeValue)
{
var referenceProjectPath = $"{downloadedProjectPath}\\{package.Name}.csproj";
var newNode = doc.CreateElement("ProjectReference");
var includeAttr = doc.CreateAttribute("Include");
includeAttr.Value = referenceProjectPath;
newNode.Attributes.Append(includeAttr);
nodes[0]?.ParentNode?.ReplaceChild(newNode, nodes[0]);
}
File.WriteAllText(projectFile, doc.OuterXml);
}
private async Task AddSourceCode(string projectFile, NugetPackageInfo package, string version = null)
{
var targetFolder = FindFolderToDownloadPackage(projectFile, package);
if (Directory.Exists(targetFolder))
{
Directory.Delete(targetFolder, true);
}
await DownloadSourceCode(targetFolder, package, version);
}
private string FindFolderToDownloadPackage(string projectFile, NugetPackageInfo package)
{
return Path.Combine(FindSolutionFolder(projectFile), "packages", package.Name);
}
private string FindRelativeFolderToDownloadPackage(string projectFile, NugetPackageInfo package)
{
var folder = Path.Combine(FindSolutionFolder(projectFile), "packages", package.Name);
return new Uri(projectFile).MakeRelativeUri(new Uri(folder)).ToString().Replace("/", "\\");
}
private async Task DownloadSourceCode(string targetFolder, NugetPackageInfo package, string version = null)
{
await SourceCodeDownloadService.DownloadPackageAsync(
package.Name,
targetFolder,
version
);
}
private string FindSolutionFile(string projectFile)
{
var folder = FindSolutionFolder(projectFile);
return Directory.GetFiles(folder, "*.sln", SearchOption.TopDirectoryOnly).FirstOrDefault();
}
private string FindSolutionFolder(string projectFile)
{
var targetFolder = Path.GetDirectoryName(projectFile);
do
{
if (Directory.GetParent(targetFolder) != null)
{
targetFolder = Directory.GetParent(targetFolder).FullName;
}
else
{
return Path.GetDirectoryName(projectFile);
}
if (Directory.GetFiles(targetFolder, "*.sln", SearchOption.TopDirectoryOnly).Any())
{
break;
}
} while (targetFolder != null);
return targetFolder;
}
private async Task AddAsPackageReference(string projectFile, NugetPackageInfo package, string version,
bool useDotnetCliToInstall)
{
var projectFileContent = File.ReadAllText(projectFile);
if (projectFileContent.Contains($"\"{package.Name}\""))
{
version = GetAbpVersionOrNull(projectFileContent);
return;
}
using (DirectoryHelper.ChangeCurrentDirectory(Path.GetDirectoryName(projectFile)))
@ -105,7 +240,9 @@ namespace Volo.Abp.Cli.ProjectModification
ModuleClassDependcyAdder.Add(moduleFiles.First(), package.ModuleClass);
}
if (useDotnetCliToInstall && (package.Target == NuGetPackageTarget.Blazor || package.Target == NuGetPackageTarget.BlazorServer || package.Target == NuGetPackageTarget.BlazorWebAssembly))
if (useDotnetCliToInstall && (package.Target == NuGetPackageTarget.Blazor ||
package.Target == NuGetPackageTarget.BlazorServer ||
package.Target == NuGetPackageTarget.BlazorWebAssembly))
{
await RunBundleForBlazorAsync(projectFile);
}
@ -125,7 +262,7 @@ namespace Volo.Abp.Cli.ProjectModification
private Task AddToCsprojManuallyAsync(string projectFile, NugetPackageInfo package, string version = null)
{
var projectFileContent = File.ReadAllText(projectFile);
var doc = new XmlDocument() { PreserveWhitespace = true };
var doc = new XmlDocument() {PreserveWhitespace = true};
doc.Load(StreamHelper.GenerateStreamFromString(projectFileContent));
var itemGroupNodes = doc.SelectNodes("/Project/ItemGroup");
@ -164,9 +301,11 @@ namespace Volo.Abp.Cli.ProjectModification
return Task.CompletedTask;
}
private string GetAbpVersionOrNull(string projectFileContent)
private string GetAbpVersionOrNull(string projectFile)
{
var doc = new XmlDocument() { PreserveWhitespace = true };
var projectFileContent = File.ReadAllText(projectFile);
var doc = new XmlDocument() {PreserveWhitespace = true};
doc.Load(StreamHelper.GenerateStreamFromString(projectFileContent));

@ -15,7 +15,8 @@ namespace Volo.Abp.Cli.ProjectModification
var solutionFileContent = File.ReadAllText(solutionFile);
solutionFileContent.NormalizeLineEndings();
var lines = solutionFileContent.Split(new[] {Environment.NewLine, "\n"}, StringSplitOptions.None);
File.WriteAllText(solutionFile, RemoveProject(lines.ToList(), projectName).JoinAsString(Environment.NewLine));
File.WriteAllText(solutionFile,
RemoveProject(lines.ToList(), projectName).JoinAsString(Environment.NewLine));
}
public async Task AddModuleToSolutionFileAsync(ModuleWithMastersInfo module, string solutionFile)
@ -23,6 +24,49 @@ namespace Volo.Abp.Cli.ProjectModification
await AddModuleAsync(module, solutionFile);
}
public async Task AddPackageToSolutionFileAsync(NugetPackageInfo package, string solutionFile)
{
await AddPackageAsync(package, solutionFile);
}
private async Task AddPackageAsync(NugetPackageInfo package, string solutionFile)
{
var srcFolderId = await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, "src");
var file = File.ReadAllText(solutionFile);
var lines = file.Split(Environment.NewLine).ToList();
if (lines.Any(l => l.Contains($"\"{package.Name}\"")))
{
return;
}
var projectGuid = Guid.NewGuid().ToString();
var newProjectLine = "Project(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"" + package.Name + "\"," +
" \"packages\\" + package.Name + "\\" +
"\\" + package.Name + ".csproj\", \"{" + projectGuid + "}\""
+ Environment.NewLine + "EndProject";
lines.InsertAfter(l => l.Trim().Equals("EndProject"), newProjectLine);
var newPostSolutionLine =
" {" + projectGuid + "}.Debug|Any CPU.ActiveCfg = Debug|Any CPU" + Environment.NewLine +
" {" + projectGuid + "}.Debug|Any CPU.Build.0 = Debug|Any CPU" + Environment.NewLine +
" {" + projectGuid + "}.Release|Any CPU.ActiveCfg = Release|Any CPU" + Environment.NewLine +
" {" + projectGuid + "}.Release|Any CPU.Build.0 = Release|Any CPU";
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("ProjectConfigurationPlatforms"),
newPostSolutionLine);
var newPreSolutionLine =
" {" + projectGuid + "} = {" + srcFolderId + "}";
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine);
File.WriteAllText(solutionFile, string.Join(Environment.NewLine, lines));
}
private List<string> RemoveProject(List<string> solutionFileLines, string projectName)
{
var projectKey = FindProjectKey(solutionFileLines, projectName);
@ -63,7 +107,8 @@ namespace Volo.Abp.Cli.ProjectModification
{
var curlyBracketStartIndex = solutionFileLine.LastIndexOf("{", StringComparison.OrdinalIgnoreCase);
var curlyBracketEndIndex = solutionFileLine.LastIndexOf("}", StringComparison.OrdinalIgnoreCase);
return solutionFileLine.Substring(curlyBracketStartIndex + 1, curlyBracketEndIndex - curlyBracketStartIndex - 1);
return solutionFileLine.Substring(curlyBracketStartIndex + 1,
curlyBracketEndIndex - curlyBracketStartIndex - 1);
}
}
@ -72,13 +117,14 @@ namespace Volo.Abp.Cli.ProjectModification
private async Task AddModuleAsync(ModuleWithMastersInfo module, string solutionFile)
{
var srcModuleFolderId = await AddNewFolderAndGetIdOrGetExistingId(solutionFile, module.Name, await AddNewFolderAndGetIdOrGetExistingId(solutionFile, "modules"));
var testModuleFolderId = await AddNewFolderAndGetIdOrGetExistingId(solutionFile, module.Name + ".Tests", await AddNewFolderAndGetIdOrGetExistingId(solutionFile, "test"));
var srcModuleFolderId = await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, module.Name,
await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, "modules"));
var testModuleFolderId = await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, module.Name + ".Tests",
await AddNewFolderAndGetIdOrGetExistingIdAsync(solutionFile, "test"));
var file = File.ReadAllText(solutionFile);
var lines = file.Split(Environment.NewLine).ToList();
var projectsUnderModule = Directory.GetFiles(
Path.Combine(Path.GetDirectoryName(solutionFile), "modules", module.Name),
"*.csproj",
@ -92,7 +138,7 @@ namespace Volo.Abp.Cli.ProjectModification
foreach (var projectPath in projectsUnderModule)
{
var parentFolderId = projectsUnderTest.Contains(projectPath) ? testModuleFolderId : srcModuleFolderId;
var projectId = Path.GetFileName(projectPath).Replace(".csproj","");
var projectId = Path.GetFileName(projectPath).Replace(".csproj", "");
var projectParentFolderInModule = projectsUnderTest.Contains(projectPath) ? "test" : "src";
if (lines.Any(l => l.Contains($"\"{projectId}\"")))
@ -103,8 +149,9 @@ namespace Volo.Abp.Cli.ProjectModification
var projectGuid = Guid.NewGuid().ToString();
var newProjectLine = "Project(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"" + projectId + "\"," +
" \"modules\\" + module.Name + "\\"+ projectParentFolderInModule + "\\" + projectId + "\\" + projectId + ".csproj\", \"{" + projectGuid + "}\""
+ Environment.NewLine + "EndProject";
" \"modules\\" + module.Name + "\\" + projectParentFolderInModule + "\\" +
projectId + "\\" + projectId + ".csproj\", \"{" + projectGuid + "}\""
+ Environment.NewLine + "EndProject";
lines.InsertAfter(l => l.Trim().Equals("EndProject"), newProjectLine);
@ -114,12 +161,13 @@ namespace Volo.Abp.Cli.ProjectModification
" {" + projectGuid + "}.Release|Any CPU.ActiveCfg = Release|Any CPU" + Environment.NewLine +
" {" + projectGuid + "}.Release|Any CPU.Build.0 = Release|Any CPU";
lines.InsertAfter(l=>l.Contains("GlobalSection") && l.Contains("ProjectConfigurationPlatforms"), newPostSolutionLine);
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("ProjectConfigurationPlatforms"),
newPostSolutionLine);
var newPreSolutionLine =
" {"+ projectGuid + "} = {"+ parentFolderId + "}";
" {" + projectGuid + "} = {" + parentFolderId + "}";
lines.InsertAfter(l=>l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine);
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine);
}
File.WriteAllText(solutionFile, string.Join(Environment.NewLine, lines));
@ -133,19 +181,21 @@ namespace Volo.Abp.Cli.ProjectModification
}
}
private async Task<string> AddNewFolderAndGetIdOrGetExistingId(string solutionFile, string folderName, string parentFolderId = null)
private async Task<string> AddNewFolderAndGetIdOrGetExistingIdAsync(string solutionFile, string folderName,
string parentFolderId = null)
{
var file = File.ReadAllText(solutionFile);
var lines = file.Split(Environment.NewLine).ToList();
string folderId;
var folderLineIndex = lines.FindIndex(l =>
l.Contains("2150E333-8FDC-42A3-9474-1A3956D46DE8") && l.Contains("\""+ folderName + "\""));
l.Contains("2150E333-8FDC-42A3-9474-1A3956D46DE8") && l.Contains("\"" + folderName + "\""));
if (folderLineIndex < 0)
{
folderId = Guid.NewGuid().ToString();
var newFolderLine = "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \""+ folderName + "\", \""+ folderName + "\", \"{" + folderId + "}\""
var newFolderLine = "Project(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"" + folderName + "\", \"" +
folderName + "\", \"{" + folderId + "}\""
+ Environment.NewLine + "EndProject";
lines.InsertAfter(l => l.Trim().Equals("EndProject"), newFolderLine);
@ -155,7 +205,8 @@ namespace Volo.Abp.Cli.ProjectModification
var newPreSolutionLine =
" {" + folderId + "} = {" + parentFolderId + "}";
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"), newPreSolutionLine);
lines.InsertAfter(l => l.Contains("GlobalSection") && l.Contains("NestedProjects"),
newPreSolutionLine);
}
}
else

@ -365,7 +365,7 @@ namespace Volo.Abp.Cli.ProjectModification
}
else
{
await SourceCodeDownloadService.DownloadAsync(
await SourceCodeDownloadService.DownloadModuleAsync(
module.Name,
targetModuleFolder,
version,

@ -1,6 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Confluent.Kafka;
@ -15,7 +14,7 @@ namespace Volo.Abp.Kafka
{
protected AbpKafkaOptions Options { get; }
protected ConcurrentDictionary<string, IConsumer<string, byte[]>> Consumers { get; }
protected ConcurrentDictionary<string, Lazy<IConsumer<string, byte[]>>> Consumers { get; }
protected TimeSpan TotalDisposeWaitDuration { get; set; } = TimeSpan.FromSeconds(10);
@ -27,7 +26,7 @@ namespace Volo.Abp.Kafka
{
Options = options.Value;
Consumers = new ConcurrentDictionary<string, IConsumer<string, byte[]>>();
Consumers = new ConcurrentDictionary<string, Lazy<IConsumer<string, byte[]>>>();
Logger = new NullLogger<ConsumerPool>();
}
@ -36,7 +35,7 @@ namespace Volo.Abp.Kafka
connectionName ??= KafkaConnections.DefaultConnectionName;
return Consumers.GetOrAdd(
connectionName, connection =>
connectionName, connection => new Lazy<IConsumer<string, byte[]>>(() =>
{
var config = new ConsumerConfig(Options.Connections.GetOrDefault(connection))
{
@ -45,10 +44,9 @@ namespace Volo.Abp.Kafka
};
Options.ConfigureConsumer?.Invoke(config);
return new ConsumerBuilder<string, byte[]>(config).Build();
}
);
})
).Value;
}
public void Dispose()
@ -78,8 +76,8 @@ namespace Volo.Abp.Kafka
try
{
consumer.Close();
consumer.Dispose();
consumer.Value.Close();
consumer.Value.Dispose();
}
catch
{

@ -14,7 +14,7 @@ namespace Volo.Abp.Kafka
{
protected AbpKafkaOptions Options { get; }
protected ConcurrentDictionary<string, IProducer<string, byte[]>> Producers { get; }
protected ConcurrentDictionary<string, Lazy<IProducer<string, byte[]>>> Producers { get; }
protected TimeSpan TotalDisposeWaitDuration { get; set; } = TimeSpan.FromSeconds(10);
@ -26,7 +26,7 @@ namespace Volo.Abp.Kafka
{
Options = options.Value;
Producers = new ConcurrentDictionary<string, IProducer<string, byte[]>>();
Producers = new ConcurrentDictionary<string, Lazy<IProducer<string, byte[]>>>();
Logger = new NullLogger<ProducerPool>();
}
@ -35,14 +35,14 @@ namespace Volo.Abp.Kafka
connectionName ??= KafkaConnections.DefaultConnectionName;
return Producers.GetOrAdd(
connectionName, connection =>
connectionName, connection => new Lazy<IProducer<string, byte[]>>(() =>
{
var config = Options.Connections.GetOrDefault(connection);
Options.ConfigureProducer?.Invoke(new ProducerConfig(config));
return new ProducerBuilder<string, byte[]>(config).Build();
});
})).Value;
}
public void Dispose()
@ -72,7 +72,7 @@ namespace Volo.Abp.Kafka
try
{
producer.Dispose();
producer.Value.Dispose();
}
catch
{

@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Microsoft.Extensions.Options;
using RabbitMQ.Client;
@ -10,14 +11,14 @@ namespace Volo.Abp.RabbitMQ
{
protected AbpRabbitMqOptions Options { get; }
protected ConcurrentDictionary<string, IConnection> Connections { get; }
protected ConcurrentDictionary<string, Lazy<IConnection>> Connections { get; }
private bool _isDisposed;
public ConnectionPool(IOptions<AbpRabbitMqOptions> options)
{
Options = options.Value;
Connections = new ConcurrentDictionary<string, IConnection>();
Connections = new ConcurrentDictionary<string, Lazy<IConnection>>();
}
public virtual IConnection Get(string connectionName = null)
@ -25,15 +26,15 @@ namespace Volo.Abp.RabbitMQ
connectionName ??= RabbitMqConnections.DefaultConnectionName;
return Connections.GetOrAdd(
connectionName,
() =>
connectionName, () => new Lazy<IConnection>(() =>
{
var connection = Options.Connections.GetOrDefault(connectionName);
var hostnames = connection.HostName.TrimEnd(';').Split(';');
// Handle Rabbit MQ Cluster.
return hostnames.Length == 1 ? connection.CreateConnection() : connection.CreateConnection(hostnames);
}
);
})
).Value;
}
public void Dispose()
@ -49,7 +50,7 @@ namespace Volo.Abp.RabbitMQ
{
try
{
connection.Dispose();
connection.Value.Dispose();
}
catch
{

@ -232,7 +232,7 @@
useCommandShortcut: true,
initialValue: initialValue,
previewStyle: 'tab',
height: "25em",
height: "95vh",
minHeight: "25em",
initialEditType: initialValue ? 'wysiwyg' : 'markdown',
language: $editorContainer.data("language"),

@ -178,7 +178,7 @@
useCommandShortcut: true,
initialValue: initialValue,
previewStyle: 'tab',
height: "25em",
height: "95vh",
minHeight: "25em",
initialEditType: initialValue ? 'wysiwyg' : 'markdown',
language: $editorContainer.data("language"),

@ -86,7 +86,7 @@
useCommandShortcut: true,
initialValue: initialValue,
previewStyle: 'tab',
height: "25em",
height: "95vh",
minHeight: "25em",
initialEditType: initialValue ? 'wysiwyg' : 'markdown',
language: $editorContainer.data("language"),

@ -61,7 +61,7 @@
useCommandShortcut: true,
initialValue: initialValue,
previewStyle: 'tab',
height: "25em",
height: "95vh",
minHeight: "25em",
initialEditType: initialValue ? 'wysiwyg' : 'markdown',
language: $editorContainer.data("language"),

Loading…
Cancel
Save