diff --git a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs index 88c34aab2f..d6d101682d 100644 --- a/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs +++ b/modules/docs/src/Volo.Docs.Web/Areas/Documents/TagHelpers/TreeTagHelper.cs @@ -1,15 +1,11 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Text; -using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Razor.TagHelpers; -using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; using Volo.Docs.Documents; using Volo.Docs.Localization; -using Volo.Docs.Pages.Documents.Project; using Volo.Docs.Utils; namespace Volo.Docs.Areas.Documents.TagHelpers @@ -23,7 +19,7 @@ namespace Volo.Docs.Areas.Documents.TagHelpers private readonly IStringLocalizer _localizer; - private readonly LinkGenerator _linkGenerator; + private readonly IDocsLinkGenerator _docsLinkGenerator; private readonly Func _urlNormalizer; @@ -55,11 +51,11 @@ namespace Volo.Docs.Areas.Documents.TagHelpers [HtmlAttributeName("language")] public string LanguageCode { get; set; } - public TreeTagHelper(IOptions urlOptions, IStringLocalizer localizer, LinkGenerator linkGenerator, IServiceProvider serviceProvider) + public TreeTagHelper(IOptions urlOptions, IStringLocalizer localizer, IDocsLinkGenerator docsLinkGenerator, IServiceProvider serviceProvider) { _localizer = localizer; _uiOptions = urlOptions.Value; - _linkGenerator = linkGenerator; + _docsLinkGenerator = docsLinkGenerator; _urlNormalizer = _uiOptions.UrlNormalizer ?? (context => context.Url); _serviceProvider = serviceProvider; } @@ -183,14 +179,7 @@ namespace Volo.Docs.Areas.Documents.TagHelpers if (!UrlHelper.IsExternalLink(path)) { - var routeValues = new Dictionary { - { nameof(IndexModel.LanguageCode), LanguageCode }, - { nameof(IndexModel.Version), Version }, - { nameof(IndexModel.DocumentName), pathWithoutFileExtension }, - { nameof(IndexModel.ProjectName), ProjectName } - }; - - path = _linkGenerator.GetPathByPage("/Documents/Project/Index", values: routeValues); + path = _docsLinkGenerator.GenerateLink(ProjectName, LanguageCode, Version, pathWithoutFileExtension); } diff --git a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs index 44557ca0ed..2758ea1a30 100644 --- a/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs +++ b/modules/docs/src/Volo.Docs.Web/Markdown/MarkdownDocumentToHtmlConverter.cs @@ -19,16 +19,16 @@ namespace Volo.Docs.Markdown private readonly IMarkdownConverter _markdownConverter; private readonly DocsUiOptions _uiOptions; - private readonly LinkGenerator _linkGenerator; + private readonly IDocsLinkGenerator _docsLinkGenerator; private readonly IServiceProvider _serviceProvider; private readonly Func _urlNormalizer; public MarkdownDocumentToHtmlConverter(IMarkdownConverter markdownConverter, - IOptions urlOptions, LinkGenerator linkGenerator, + IOptions urlOptions, IDocsLinkGenerator docsLinkGenerator, IServiceProvider serviceProvider) { _markdownConverter = markdownConverter; - _linkGenerator = linkGenerator; + _docsLinkGenerator = docsLinkGenerator; _serviceProvider = serviceProvider; _uiOptions = urlOptions.Value; _urlNormalizer = _uiOptions.UrlNormalizer ?? (context => context.Url); @@ -126,7 +126,7 @@ namespace Volo.Docs.Markdown return NormalizeLink( displayText, MdLinkFormat, - GenerateUrl(languageCode, $"{version}{documentLocalDirectoryNormalized}", documentName, projectShortName), + _docsLinkGenerator.GenerateLink(projectShortName, languageCode, $"{version}{documentLocalDirectoryNormalized}", documentName), projectShortName, version, documentName, @@ -151,8 +151,8 @@ namespace Volo.Docs.Markdown { documentLocalDirectoryNormalized = "/" + documentLocalDirectoryNormalized; } - - link = GenerateUrl(languageCode, $"{version}{documentLocalDirectoryNormalized}", documentName, projectShortName); + + link = _docsLinkGenerator.GenerateLink(projectShortName, languageCode, $"{version}{documentLocalDirectoryNormalized}", documentName); } return NormalizeLink(displayText, MdLinkFormat, link,projectShortName, @@ -193,18 +193,5 @@ namespace Volo.Docs.Markdown return documentName.Left(documentName.Length - Type.Length - 1); } - - private string GenerateUrl(string languageCode, string version, string documentName, string projectShortName) - { - var routeValues = new Dictionary { - { nameof(IndexModel.LanguageCode), languageCode }, - { nameof(IndexModel.Version), version }, - { nameof(IndexModel.DocumentName), documentName }, - { nameof(IndexModel.ProjectName), projectShortName } - }; - - var encodedUrl = _linkGenerator.GetPathByPage("/Documents/Project/Index", values: routeValues); - return WebUtility.UrlDecode(encodedUrl); //Document name can contain path separators like /, so we need to decode it - } } } diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs index 2c66e5cecf..d19fc46d33 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml.cs @@ -21,6 +21,7 @@ using Volo.Docs.Models; using Volo.Docs.Projects; using Volo.Docs.GitHub.Documents.Version; using Volo.Docs.Localization; +using Volo.Docs.Utils; namespace Volo.Docs.Pages.Documents.Project { @@ -90,6 +91,8 @@ namespace Volo.Docs.Pages.Documents.Project private readonly IProjectAppService _projectAppService; private readonly IDocumentSectionRenderer _documentSectionRenderer; private readonly DocsUiOptions _uiOptions; + + protected IDocsLinkGenerator DocsLinkGenerator => LazyServiceProvider.LazyGetRequiredService(); public IndexModel( IDocumentAppService documentAppService, @@ -249,59 +252,52 @@ namespace Volo.Docs.Pages.Documents.Project new StringBuilder() .Append("/Abp/Languages/Switch?culture=") .Append(LanguageCode).Append("&uiCulture=") - .Append(LanguageCode).Append("&returnUrl=").Append(BuildDocumentUrl(ProjectName, LanguageCode, + .Append(LanguageCode).Append("&returnUrl=").Append(DocsLinkGenerator.GenerateLink(ProjectName, LanguageCode, LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, DocumentName)).ToString()); } public string GetFullUrlOfTheLatestDocument() { - return Request.Scheme + Uri.SchemeDelimiter + Request.Host.Value + Request.PathBase + BuildDocumentUrl(ProjectName, LanguageCode, DocsAppConsts.Latest, DocumentName); + return Request.Scheme + Uri.SchemeDelimiter + Request.Host.Value + Request.PathBase + DocsLinkGenerator.GenerateLink(ProjectName, LanguageCode, DocsAppConsts.Latest, DocumentName); } public string CreateDocumentLink(string documentName) { - return BuildDocumentUrl(ProjectName, LanguageCode, LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, documentName); + return DocsLinkGenerator.GenerateLink(ProjectName, LanguageCode, LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, documentName); } public string BuildDocumentUrl(string projectName, string languageCode, string version, string documentName) { - var routeValues = new Dictionary { - { nameof(LanguageCode), languageCode }, - { nameof(Version), version }, - { nameof(DocumentName), documentName }, - { nameof(ProjectName), projectName } - }; - - return Url.Page("/Documents/Project/Index", routeValues); + return DocsLinkGenerator.GenerateLink(projectName, languageCode, version, documentName); } private IActionResult RedirectToDefaultLanguage() { - return Redirect(BuildDocumentUrl( - projectName : ProjectName, - version : (LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version), - languageCode : DefaultLanguageCode, - documentName : DocumentName + return Redirect(DocsLinkGenerator.GenerateLink( + ProjectName, + DefaultLanguageCode, + LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, + DocumentName )); } private IActionResult RedirectToDefaultVersion() { - return Redirect(BuildDocumentUrl( - projectName : ProjectName, - version : DocsAppConsts.Latest, - languageCode : LanguageCode, - documentName : DocumentName + return Redirect(DocsLinkGenerator.GenerateLink( + ProjectName, + LanguageCode, + DocsAppConsts.Latest, + DocumentName )); } private IActionResult RedirectToDefaultDocument() { - return Redirect(BuildDocumentUrl ( - projectName : ProjectName, - version : (LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version), - documentName : "", - languageCode : DefaultLanguageCode + return Redirect(DocsLinkGenerator.GenerateLink ( + ProjectName, + DefaultLanguageCode, + LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, + "" )); } @@ -323,7 +319,7 @@ namespace Volo.Docs.Pages.Documents.Project { return null; } - return BuildDocumentUrl(project.ShortName, LanguageCode, Version, null); + return DocsLinkGenerator.GenerateLink(project.ShortName, LanguageCode, Version, null); } private async Task TrySetVersionAsync() @@ -467,7 +463,7 @@ namespace Volo.Docs.Pages.Documents.Project version = DocsAppConsts.Latest; } - return BuildDocumentUrl(ProjectName, LanguageCode, version, documentName); + return DocsLinkGenerator.GenerateLink(ProjectName, LanguageCode, version, documentName); } public string GetSpecificVersionOrLatest() @@ -526,7 +522,7 @@ namespace Volo.Docs.Pages.Documents.Project LanguageSelectListItems.Add( new SelectListItem( language.DisplayName, - BuildDocumentUrl(ProjectName, language.Code, LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, DocumentName), + DocsLinkGenerator.GenerateLink(ProjectName, language.Code, LatestVersionInfo.IsSelected ? DocsAppConsts.Latest : Version, DocumentName), language.Code.Equals(LanguageCode, StringComparison.OrdinalIgnoreCase) ) ); diff --git a/modules/docs/src/Volo.Docs.Web/Utils/DefaultDocsLinkGenerator.cs b/modules/docs/src/Volo.Docs.Web/Utils/DefaultDocsLinkGenerator.cs new file mode 100644 index 0000000000..51bbcaa8c1 --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/Utils/DefaultDocsLinkGenerator.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Net; +using Microsoft.AspNetCore.Routing; +using Volo.Abp.DependencyInjection; +using Volo.Docs.Pages.Documents.Project; + +namespace Volo.Docs.Utils; + +public class DefaultDocsLinkGenerator : IDocsLinkGenerator, ITransientDependency +{ + protected LinkGenerator LinkGenerator { get; } + + public DefaultDocsLinkGenerator(LinkGenerator linkGenerator) + { + LinkGenerator = linkGenerator; + } + + + public string GenerateLink(string projectName, string languageCode, string version, string documentName) + { + var routeValues = new Dictionary { + { nameof(IndexModel.LanguageCode), languageCode }, + { nameof(IndexModel.Version), version }, + { nameof(IndexModel.DocumentName), documentName }, + { nameof(IndexModel.ProjectName), projectName } + }; + + var encodedUrl = LinkGenerator.GetPathByPage("/Documents/Project/Index", values: routeValues); + return WebUtility.UrlDecode(encodedUrl); //Document name can contain path separators like /, so we need to decode it + } +} \ No newline at end of file diff --git a/modules/docs/src/Volo.Docs.Web/Utils/IDocsLinkGenerator.cs b/modules/docs/src/Volo.Docs.Web/Utils/IDocsLinkGenerator.cs new file mode 100644 index 0000000000..4c593dacee --- /dev/null +++ b/modules/docs/src/Volo.Docs.Web/Utils/IDocsLinkGenerator.cs @@ -0,0 +1,6 @@ +namespace Volo.Docs.Utils; + +public interface IDocsLinkGenerator +{ + string GenerateLink(string projectName, string languageCode, string version, string documentName); +} \ No newline at end of file