mirror of https://github.com/abpframework/abp.git
committed by
GitHub
15 changed files with 793 additions and 26 deletions
@ -0,0 +1,96 @@ |
|||
// <auto-generated/>
|
|||
#pragma warning disable 1591
|
|||
namespace Volo.Abp.AspNetCore.RazorViews |
|||
{ |
|||
#line hidden
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
#nullable restore |
|||
#line 1 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
using System.Globalization; |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
#nullable restore |
|||
#line 2 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
using Volo.Abp.AspNetCore.MultiTenancy.Views; |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
#nullable restore |
|||
#line 3 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
using Volo.Abp.AspNetCore.RazorViews; |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
internal class MultiTenancyMiddlewareErrorPage : AbpCompilationRazorPageBase |
|||
{ |
|||
#pragma warning disable 1998
|
|||
public async override global::System.Threading.Tasks.Task ExecuteAsync() |
|||
{ |
|||
#nullable restore |
|||
#line 5 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
|
|||
Response.ContentType = "text/html; charset=utf-8"; |
|||
Response.StatusCode = 404; |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
WriteLiteral("\n"); |
|||
WriteLiteral("\n<html"); |
|||
BeginWriteAttribute("lang", " lang=\"", 453, "\"", 512, 1); |
|||
#nullable restore |
|||
#line 19 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
WriteAttributeValue("", 460, HtmlEncoder.Encode(CultureInfo.CurrentCulture.Name), 460, 52, false); |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
EndWriteAttribute(); |
|||
WriteLiteral(">\n <head>\n <meta charset=\"utf-8\" />\n <title>"); |
|||
#nullable restore |
|||
#line 22 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
Write(HtmlEncoder.Encode(Model.Message)); |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
WriteLiteral("</title>\n </head>\n <body>\n <h3>"); |
|||
#nullable restore |
|||
#line 25 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
Write(HtmlEncoder.Encode(Model.Message)); |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
WriteLiteral("</h3>\n <p>"); |
|||
#nullable restore |
|||
#line 26 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
Write(HtmlEncoder.Encode(Model.Details)); |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
WriteLiteral("<p/>\n </body>\n</html>\n"); |
|||
} |
|||
#pragma warning restore 1998
|
|||
#nullable restore |
|||
#line 10 "MultiTenancyMiddlewareErrorPage.cshtml"
|
|||
|
|||
public MultiTenancyMiddlewareErrorPage(MultiTenancyMiddlewareErrorPageModel model) |
|||
{ |
|||
Model = model; |
|||
} |
|||
|
|||
public MultiTenancyMiddlewareErrorPageModel Model { get; set; } |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
} |
|||
} |
|||
#pragma warning restore 1591
|
|||
@ -0,0 +1,28 @@ |
|||
@using System.Globalization |
|||
@using Volo.Abp.AspNetCore.MultiTenancy.Views |
|||
@using Volo.Abp.AspNetCore.RazorViews |
|||
@inherits AbpCompilationRazorPageBase |
|||
@{ |
|||
Response.ContentType = "text/html; charset=utf-8"; |
|||
Response.StatusCode = 404; |
|||
} |
|||
|
|||
@functions{ |
|||
public MultiTenancyMiddlewareErrorPage(MultiTenancyMiddlewareErrorPageModel model) |
|||
{ |
|||
Model = model; |
|||
} |
|||
|
|||
public MultiTenancyMiddlewareErrorPageModel Model { get; set; } |
|||
} |
|||
|
|||
<html lang="@HtmlEncoder.Encode(CultureInfo.CurrentCulture.Name)"> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<title>@HtmlEncoder.Encode(Model.Message)</title> |
|||
</head> |
|||
<body> |
|||
<h3>@HtmlEncoder.Encode(Model.Message)</h3> |
|||
<p>@HtmlEncoder.Encode(Model.Details)<p/> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,14 @@ |
|||
namespace Volo.Abp.AspNetCore.MultiTenancy.Views; |
|||
|
|||
public class MultiTenancyMiddlewareErrorPageModel |
|||
{ |
|||
public string Message { get; set; } |
|||
|
|||
public string Details { get; set; } |
|||
|
|||
public MultiTenancyMiddlewareErrorPageModel(string message, string details) |
|||
{ |
|||
Message = message; |
|||
Details = details; |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// <auto-generated/>
|
|||
#pragma warning disable 1591
|
|||
namespace Volo.Abp.AspNetCore.RazorViews |
|||
{ |
|||
#line hidden
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
#nullable restore |
|||
#line 1 "AbpMvcLibsErrorPage.cshtml"
|
|||
using Volo.Abp.AspNetCore.RazorViews; |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
internal class AbpMvcLibsErrorPage : AbpCompilationRazorPageBase |
|||
{ |
|||
#pragma warning disable 1998
|
|||
public async override global::System.Threading.Tasks.Task ExecuteAsync() |
|||
{ |
|||
#nullable restore |
|||
#line 3 "AbpMvcLibsErrorPage.cshtml"
|
|||
|
|||
Response.ContentType = "text/html; charset=utf-8"; |
|||
Response.StatusCode = 500; |
|||
|
|||
#line default
|
|||
#line hidden
|
|||
#nullable disable |
|||
WriteLiteral(@"
|
|||
<html> |
|||
<head> |
|||
<meta charset=""utf-8"" /> |
|||
<title>Error - The Libs folder is missing!</title> |
|||
</head> |
|||
<body> |
|||
<h1> ⚠️ The Libs folder under the <code style=""background-color: #e7e7e7;"">wwwroot/libs</code> directory is empty!</h1> |
|||
|
|||
<p>The Libs folder contains mandatory NPM Packages for running the project.</p> |
|||
|
|||
<p>Make sure you run the <code style=""background-color: #e7e7e7;"">abp install-libs</code> CLI tool command.</p> |
|||
|
|||
<p>For more information, check out the <a href=""https://abp.io/docs/latest/CLI#install-libs"">ABP CLI documentation</a></p>
|
|||
</body> |
|||
</html> |
|||
");
|
|||
} |
|||
#pragma warning restore 1998
|
|||
} |
|||
} |
|||
#pragma warning restore 1591
|
|||
@ -0,0 +1,22 @@ |
|||
@using Volo.Abp.AspNetCore.RazorViews |
|||
@inherits AbpCompilationRazorPageBase |
|||
@{ |
|||
Response.ContentType = "text/html; charset=utf-8"; |
|||
Response.StatusCode = 500; |
|||
} |
|||
|
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<title>Error - The Libs folder is missing!</title> |
|||
</head> |
|||
<body> |
|||
<h1> ⚠️ The Libs folder under the <code style="background-color: #e7e7e7;">wwwroot/libs</code> directory is empty!</h1> |
|||
|
|||
<p>The Libs folder contains mandatory NPM Packages for running the project.</p> |
|||
|
|||
<p>Make sure you run the <code style="background-color: #e7e7e7;">abp install-libs</code> CLI tool command.</p> |
|||
|
|||
<p>For more information, check out the <a href="https://abp.io/docs/latest/CLI#install-libs">ABP CLI documentation</a></p> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,283 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Globalization; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Text.Encodings.Web; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Http; |
|||
|
|||
namespace Volo.Abp.AspNetCore.RazorViews; |
|||
|
|||
public abstract class AbpCompilationRazorPageBase |
|||
{ |
|||
private readonly static Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); |
|||
private readonly static char[] NewLineChars = new[] { '\r', '\n' }; |
|||
private readonly Stack<TextWriter> _textWriterStack = new Stack<TextWriter>(); |
|||
|
|||
/// <summary>
|
|||
/// The request context
|
|||
/// </summary>
|
|||
protected HttpContext Context { get; private set; } = default!; |
|||
|
|||
/// <summary>
|
|||
/// The request
|
|||
/// </summary>
|
|||
protected HttpRequest Request { get; private set; } = default!; |
|||
|
|||
/// <summary>
|
|||
/// The response
|
|||
/// </summary>
|
|||
protected HttpResponse Response { get; private set; } = default!; |
|||
|
|||
/// <summary>
|
|||
/// The output stream
|
|||
/// </summary>
|
|||
protected TextWriter Output { get; private set; } = default!; |
|||
|
|||
/// <summary>
|
|||
/// Html encoder used to encode content.
|
|||
/// </summary>
|
|||
protected HtmlEncoder HtmlEncoder { get; set; } = HtmlEncoder.Default; |
|||
|
|||
/// <summary>
|
|||
/// Url encoder used to encode content.
|
|||
/// </summary>
|
|||
protected UrlEncoder UrlEncoder { get; set; } = UrlEncoder.Default; |
|||
|
|||
/// <summary>
|
|||
/// JavaScript encoder used to encode content.
|
|||
/// </summary>
|
|||
protected JavaScriptEncoder JavaScriptEncoder { get; set; } = JavaScriptEncoder.Default; |
|||
|
|||
/// <summary>
|
|||
/// Execute an individual request
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream to write to</param>
|
|||
public async Task ExecuteAsync(Stream stream) |
|||
{ |
|||
// We technically don't need this intermediate buffer if this method accepts a memory stream.
|
|||
var buffer = new MemoryStream(); |
|||
Output = new StreamWriter(buffer, UTF8NoBOM, 4096, leaveOpen: true); |
|||
await ExecuteAsync(); |
|||
await Output.FlushAsync(); |
|||
await Output.DisposeAsync(); |
|||
buffer.Seek(0, SeekOrigin.Begin); |
|||
await buffer.CopyToAsync(stream); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Execute an individual request
|
|||
/// </summary>
|
|||
/// <param name="context"></param>
|
|||
public async Task ExecuteAsync(HttpContext context) |
|||
{ |
|||
Context = context; |
|||
Request = Context.Request; |
|||
Response = Context.Response; |
|||
var buffer = new MemoryStream(); |
|||
Output = new StreamWriter(buffer, UTF8NoBOM, 4096, leaveOpen: true); |
|||
await ExecuteAsync(); |
|||
await Output.FlushAsync(); |
|||
await Output.DisposeAsync(); |
|||
buffer.Seek(0, SeekOrigin.Begin); |
|||
await buffer.CopyToAsync(Response.Body); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Execute an individual request
|
|||
/// </summary>
|
|||
public abstract Task ExecuteAsync(); |
|||
|
|||
protected virtual void PushWriter(TextWriter writer) |
|||
{ |
|||
ArgumentNullException.ThrowIfNull(writer); |
|||
|
|||
_textWriterStack.Push(Output); |
|||
Output = writer; |
|||
} |
|||
|
|||
protected virtual TextWriter PopWriter() |
|||
{ |
|||
Output = _textWriterStack.Pop(); |
|||
return Output; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Write the given value without HTML encoding directly to <see cref="Output"/>.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="object"/> to write.</param>
|
|||
protected void WriteLiteral(object value) |
|||
{ |
|||
WriteLiteral(Convert.ToString(value, CultureInfo.InvariantCulture)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Write the given value without HTML encoding directly to <see cref="Output"/>.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="string"/> to write.</param>
|
|||
protected void WriteLiteral(string? value) |
|||
{ |
|||
if (!string.IsNullOrEmpty(value)) |
|||
{ |
|||
Output.Write(value); |
|||
} |
|||
} |
|||
|
|||
private List<string>? AttributeValues { get; set; } |
|||
|
|||
protected void WriteAttributeValue(string thingy, int startPostion, object value, int endValue, int dealyo, bool yesno) |
|||
{ |
|||
if (AttributeValues == null) |
|||
{ |
|||
AttributeValues = new List<string>(); |
|||
} |
|||
|
|||
AttributeValues.Add(value.ToString()!); |
|||
} |
|||
|
|||
private string? AttributeEnding { get; set; } |
|||
|
|||
protected void BeginWriteAttribute(string name, string beginning, int startPosition, string ending, int endPosition, int thingy) |
|||
{ |
|||
Debug.Assert(string.IsNullOrEmpty(AttributeEnding)); |
|||
|
|||
Output.Write(beginning); |
|||
AttributeEnding = ending; |
|||
} |
|||
|
|||
protected void EndWriteAttribute() |
|||
{ |
|||
Debug.Assert(AttributeValues != null); |
|||
Debug.Assert(!string.IsNullOrEmpty(AttributeEnding)); |
|||
|
|||
var attributes = string.Join(" ", AttributeValues); |
|||
Output.Write(attributes); |
|||
AttributeValues = null; |
|||
|
|||
Output.Write(AttributeEnding); |
|||
AttributeEnding = null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the given attribute to the given writer
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the attribute to write</param>
|
|||
/// <param name="leader">The value of the prefix</param>
|
|||
/// <param name="trailer">The value of the suffix</param>
|
|||
/// <param name="values">The <see cref="AttributeValue"/>s to write.</param>
|
|||
protected void WriteAttribute( |
|||
string name, |
|||
string leader, |
|||
string trailer, |
|||
params AttributeValue[] values) |
|||
{ |
|||
ArgumentNullException.ThrowIfNull(name); |
|||
ArgumentNullException.ThrowIfNull(leader); |
|||
ArgumentNullException.ThrowIfNull(trailer); |
|||
|
|||
WriteLiteral(leader); |
|||
foreach (var value in values) |
|||
{ |
|||
WriteLiteral(value.Prefix); |
|||
|
|||
// The special cases here are that the value we're writing might already be a string, or that the
|
|||
// value might be a bool. If the value is the bool 'true' we want to write the attribute name
|
|||
// instead of the string 'true'. If the value is the bool 'false' we don't want to write anything.
|
|||
// Otherwise the value is another object (perhaps an HtmlString) and we'll ask it to format itself.
|
|||
string? stringValue; |
|||
if (value.Value is bool) |
|||
{ |
|||
if ((bool)value.Value) |
|||
{ |
|||
stringValue = name; |
|||
} |
|||
else |
|||
{ |
|||
continue; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
stringValue = value.Value as string; |
|||
} |
|||
|
|||
// Call the WriteTo(string) overload when possible
|
|||
if (value.Literal && stringValue != null) |
|||
{ |
|||
WriteLiteral(stringValue); |
|||
} |
|||
else if (value.Literal) |
|||
{ |
|||
WriteLiteral(value.Value); |
|||
} |
|||
else if (stringValue != null) |
|||
{ |
|||
Write(stringValue); |
|||
} |
|||
else |
|||
{ |
|||
Write(value.Value); |
|||
} |
|||
} |
|||
WriteLiteral(trailer); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// <see cref="HelperResult.WriteTo(TextWriter)"/> is invoked
|
|||
/// </summary>
|
|||
/// <param name="result">The <see cref="HelperResult"/> to invoke</param>
|
|||
protected void Write(HelperResult result) |
|||
{ |
|||
result.WriteTo(Output); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the specified <paramref name="value"/> to <see cref="Output"/>.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="object"/> to write.</param>
|
|||
/// <remarks>
|
|||
/// <see cref="HelperResult.WriteTo(TextWriter)"/> is invoked for <see cref="HelperResult"/> types.
|
|||
/// For all other types, the encoded result of <see cref="object.ToString"/> is written to
|
|||
/// <see cref="Output"/>.
|
|||
/// </remarks>
|
|||
protected void Write(object value) |
|||
{ |
|||
if (value is HelperResult helperResult) |
|||
{ |
|||
helperResult.WriteTo(Output); |
|||
} |
|||
else |
|||
{ |
|||
Write(Convert.ToString(value, CultureInfo.InvariantCulture)); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the specified <paramref name="value"/> with HTML encoding to <see cref="Output"/>.
|
|||
/// </summary>
|
|||
/// <param name="value">The <see cref="string"/> to write.</param>
|
|||
protected void Write(string? value) |
|||
{ |
|||
if (!string.IsNullOrEmpty(value)) |
|||
{ |
|||
WriteLiteral(HtmlEncoder.Encode(value)); |
|||
} |
|||
} |
|||
|
|||
protected string HtmlEncodeAndReplaceLineBreaks(string input) |
|||
{ |
|||
if (string.IsNullOrEmpty(input)) |
|||
{ |
|||
return string.Empty; |
|||
} |
|||
|
|||
// Split on line breaks before passing it through the encoder.
|
|||
return string.Join("<br />" + Environment.NewLine, |
|||
input.Split("\r\n", StringSplitOptions.None) |
|||
.SelectMany(s => s.Split(NewLineChars, StringSplitOptions.None)) |
|||
.Select(HtmlEncoder.Encode)); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.AspNetCore.RazorViews; |
|||
|
|||
public class AttributeValue |
|||
{ |
|||
public AttributeValue(string prefix, object value, bool literal) |
|||
{ |
|||
Prefix = prefix; |
|||
Value = value; |
|||
Literal = literal; |
|||
} |
|||
|
|||
public string Prefix { get; } |
|||
|
|||
public object Value { get; } |
|||
|
|||
public bool Literal { get; } |
|||
|
|||
public static AttributeValue FromTuple(Tuple<string, object, bool> value) |
|||
{ |
|||
return new AttributeValue(value.Item1, value.Item2, value.Item3); |
|||
} |
|||
|
|||
public static AttributeValue FromTuple(Tuple<string, string, bool> value) |
|||
{ |
|||
return new AttributeValue(value.Item1, value.Item2, value.Item3); |
|||
} |
|||
|
|||
public static implicit operator AttributeValue(Tuple<string, object, bool> value) |
|||
{ |
|||
return FromTuple(value); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
using System.IO; |
|||
|
|||
namespace Volo.Abp.AspNetCore.RazorViews; |
|||
|
|||
public class HelperResult |
|||
{ |
|||
public HelperResult(Action<TextWriter> action) |
|||
{ |
|||
WriteAction = action; |
|||
} |
|||
|
|||
public Action<TextWriter> WriteAction { get; } |
|||
|
|||
public void WriteTo(TextWriter writer) |
|||
{ |
|||
WriteAction(writer); |
|||
} |
|||
} |
|||
@ -0,0 +1,227 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Razor.Language; |
|||
using Microsoft.AspNetCore.Razor.Language.Extensions; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Cli.Args; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands; |
|||
|
|||
public class GenerateRazorPage : IConsoleCommand, ITransientDependency |
|||
{ |
|||
public const string Name = "generate-razor-page"; |
|||
|
|||
public ILogger<GenerateRazorPage> Logger { get; set; } |
|||
|
|||
public GenerateRazorPage() |
|||
{ |
|||
Logger = NullLogger<GenerateRazorPage>.Instance; |
|||
} |
|||
|
|||
public Task ExecuteAsync(CommandLineArgs commandLineArgs) |
|||
{ |
|||
var targetProjectDirectory = Directory.GetCurrentDirectory(); |
|||
var projectEngine = CreateProjectEngine(targetProjectDirectory); |
|||
|
|||
var results = MainCore(projectEngine, targetProjectDirectory); |
|||
|
|||
foreach (var result in results) |
|||
{ |
|||
File.WriteAllText(result.FilePath, result.GeneratedCode); |
|||
} |
|||
|
|||
Logger.LogInformation($"{results.Count} files successfully generated."); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
public string GetUsageInfo() |
|||
{ |
|||
var sb = new StringBuilder(); |
|||
|
|||
sb.AppendLine(""); |
|||
sb.AppendLine("Usage:"); |
|||
sb.AppendLine("abp generate-razor-page"); |
|||
sb.AppendLine(""); |
|||
sb.AppendLine("See the documentation for more info: https://abp.io/docs/latest/cli"); |
|||
|
|||
return sb.ToString(); |
|||
} |
|||
|
|||
public string GetShortDescription() |
|||
{ |
|||
return "Generates code files for Razor page."; |
|||
} |
|||
|
|||
private RazorProjectEngine CreateProjectEngine(string targetProjectDirectory, Action<RazorProjectEngineBuilder>? configure = null) |
|||
{ |
|||
var fileSystem = RazorProjectFileSystem.Create(targetProjectDirectory); |
|||
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder => |
|||
{ |
|||
builder |
|||
.SetNamespace("Volo.Abp.AspNetCore.RazorViews") |
|||
.ConfigureClass((document, @class) => |
|||
{ |
|||
@class.ClassName = Path.GetFileNameWithoutExtension(document.Source.FilePath); |
|||
@class.Modifiers.Clear(); |
|||
@class.Modifiers.Add("internal"); |
|||
}); |
|||
|
|||
SectionDirective.Register(builder); |
|||
|
|||
builder.Features.Add(new SuppressChecksumOptionsFeature()); |
|||
builder.Features.Add(new SuppressMetadataAttributesFeature()); |
|||
|
|||
if (configure != null) |
|||
{ |
|||
configure(builder); |
|||
} |
|||
|
|||
builder.AddDefaultImports(@"
|
|||
@using System |
|||
@using System.Threading.Tasks");
|
|||
}); |
|||
|
|||
return projectEngine; |
|||
} |
|||
|
|||
private List<RazorPageGeneratorResult> MainCore(RazorProjectEngine projectEngine, string targetProjectDirectory) |
|||
{ |
|||
var results = new List<RazorPageGeneratorResult>(); |
|||
Logger.LogInformation("Generating code files for pages in {0}", targetProjectDirectory); |
|||
|
|||
var cshtmlFiles = projectEngine.FileSystem.EnumerateItems(targetProjectDirectory) |
|||
.Where(x => File.ReadAllText(x.PhysicalPath).Contains("@inherits AbpCompilationRazorPageBase")) |
|||
.ToList(); |
|||
|
|||
if (!cshtmlFiles.Any()) |
|||
{ |
|||
Logger.LogInformation("No .cshtml or .razor files were found."); |
|||
return results; |
|||
} |
|||
|
|||
foreach (var item in cshtmlFiles) |
|||
{ |
|||
Logger.LogInformation(" Generating code file for page {0} ...", item.FileName); |
|||
|
|||
results.Add(GenerateCodeFile(projectEngine, item)); |
|||
|
|||
Logger.LogInformation(" Done!"); |
|||
} |
|||
|
|||
return results; |
|||
} |
|||
|
|||
private RazorPageGeneratorResult GenerateCodeFile(RazorProjectEngine projectEngine, RazorProjectItem projectItem) |
|||
{ |
|||
var projectItemWrapper = new FileSystemRazorProjectItemWrapper(Logger, projectItem); |
|||
var codeDocument = projectEngine.Process(projectItemWrapper); |
|||
var cSharpDocument = codeDocument.GetCSharpDocument(); |
|||
if (cSharpDocument.Diagnostics.Any()) |
|||
{ |
|||
var diagnostics = string.Join(Environment.NewLine, cSharpDocument.Diagnostics); |
|||
Logger.LogInformation($"One or more parse errors encountered. This will not prevent the generator from continuing: {Environment.NewLine}{diagnostics}."); |
|||
} |
|||
|
|||
var generatedCodeFilePath = Path.ChangeExtension(projectItem.PhysicalPath, ".Designer.cs"); |
|||
return new RazorPageGeneratorResult |
|||
{ |
|||
FilePath = generatedCodeFilePath, |
|||
GeneratedCode = cSharpDocument.GeneratedCode, |
|||
}; |
|||
} |
|||
|
|||
private class SuppressChecksumOptionsFeature : RazorEngineFeatureBase, IConfigureRazorCodeGenerationOptionsFeature |
|||
{ |
|||
public int Order { get; set; } |
|||
|
|||
public void Configure(RazorCodeGenerationOptionsBuilder options) |
|||
{ |
|||
Check.NotNull(options, nameof(options)); |
|||
|
|||
options.SuppressChecksum = true; |
|||
} |
|||
} |
|||
|
|||
private class SuppressMetadataAttributesFeature : RazorEngineFeatureBase, IConfigureRazorCodeGenerationOptionsFeature |
|||
{ |
|||
public int Order { get; set; } |
|||
|
|||
public void Configure(RazorCodeGenerationOptionsBuilder options) |
|||
{ |
|||
Check.NotNull(options, nameof(options)); |
|||
options.SuppressMetadataAttributes = true; |
|||
} |
|||
} |
|||
|
|||
private class FileSystemRazorProjectItemWrapper : RazorProjectItem |
|||
{ |
|||
private readonly ILogger<GenerateRazorPage> _logger; |
|||
private readonly RazorProjectItem _source; |
|||
|
|||
public FileSystemRazorProjectItemWrapper(ILogger<GenerateRazorPage> logger, RazorProjectItem item) |
|||
{ |
|||
_logger = logger; |
|||
_source = item; |
|||
|
|||
// Mask the full name since we don't want a developer's local file paths to be committed.
|
|||
PhysicalPath = $"{_source.FileName}"; |
|||
} |
|||
|
|||
public override string BasePath => _source.BasePath; |
|||
|
|||
public override string FilePath => _source.FilePath; |
|||
|
|||
public override string PhysicalPath { get; } |
|||
|
|||
public override bool Exists => _source.Exists; |
|||
|
|||
public override Stream Read() |
|||
{ |
|||
var processedContent = ProcessFileIncludes(); |
|||
return new MemoryStream(Encoding.UTF8.GetBytes(processedContent)); |
|||
} |
|||
|
|||
private string ProcessFileIncludes() |
|||
{ |
|||
var basePath = Path.GetDirectoryName(_source.PhysicalPath); |
|||
var cshtmlContent = File.ReadAllText(_source.PhysicalPath); |
|||
|
|||
var startMatch = "<%$ include: "; |
|||
var endMatch = " %>"; |
|||
var startIndex = 0; |
|||
while (startIndex < cshtmlContent.Length) |
|||
{ |
|||
startIndex = cshtmlContent.IndexOf(startMatch, startIndex, StringComparison.Ordinal); |
|||
if (startIndex == -1) |
|||
{ |
|||
break; |
|||
} |
|||
var endIndex = cshtmlContent.IndexOf(endMatch, startIndex, StringComparison.Ordinal); |
|||
if (endIndex == -1) |
|||
{ |
|||
throw new InvalidOperationException($"Invalid include file format in {_source.PhysicalPath}. Usage example: <%$ include: ErrorPage.js %>"); |
|||
} |
|||
var includeFileName = cshtmlContent.Substring(startIndex + startMatch.Length, endIndex - (startIndex + startMatch.Length)); |
|||
_logger.LogInformation(" Inlining file {0}", includeFileName); |
|||
var includeFileContent = File.ReadAllText(Path.Combine(basePath, includeFileName)); |
|||
cshtmlContent = string.Concat(cshtmlContent.Substring(0, startIndex), includeFileContent, cshtmlContent.Substring(endIndex + endMatch.Length)); |
|||
startIndex += includeFileContent.Length; |
|||
} |
|||
return cshtmlContent; |
|||
} |
|||
} |
|||
|
|||
private class RazorPageGeneratorResult |
|||
{ |
|||
public string FilePath { get; set; } |
|||
|
|||
public string GeneratedCode { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue