这是正在进行中的工作,但可能会有所帮助。
背景
一个MVC 5应用程序正在迁移到MVC Core,并且有很多内部开发的HtmlHelpers必须从头开始为MVC Core重新编写[:-(],但是想要尽快开始使用MVC Core,并尽可能少地更改视图。
想法是拥有一个帮助器目录,作为运行MVC Core应用程序,记录Razor使用的文档。
结果
![Final catalog display](https://istack.dev59.com/vn3Ta.webp)
解决方案
创建一个ViewComponent,它读取当前视图的源代码并将其显示为格式化的HTML,以及实际的HTML输出。
然后只需为每个HtmlHelper创建一个示例的部分视图即可。
在这种情况下,HtmlHelpers根据“ViewRole”生成不同的HTML,该“ViewRole”指定视图是处于显示模式还是编辑模式。
部分视图
@model App.WebLib.AspNetCore.WebApp.Areas.AppHelpers.Models.AppHelpersViewModel
<div class="form-group">
@Html.LabelTagFor(m => m.TextInput, 4)
<div class="col-md-8">
@Html.TextTagFor(Model.ViewRole, m => m.TextInput)
</div>
</div>
@await Component.InvokeAsync("DisplaySource", new { executingViewPath = ViewContext.ExecutingFilePath, viewRole = Model.ViewRole })
索引视图
@model App.WebLib.AspNetCore.WebApp.Areas.AppHelpers.Models.AppHelpersViewModel
@
<form class="form-horizontal">
<div class="row">
<div class="col-md-9">
<h3>Estructura General de las Formas</h3>
@Html.Partial("_FormLayout")
<h3>Helper Básicos</h3>
<h4>Campo de texto</h4>
@Html.Partial("_TextInput")
@Html.Partial("_TextInput", displayModel)
<h4>Campo numérico</h4>
@Html.Partial("_NumberInput")
@Html.Partial("_NumberInput", displayModel)
</div>
</div>
</form>
模型
public class AppHelpersViewModel : ViewModelBase
{
public AppHelpersViewModel()
{
ViewRole = ViewRole.Edit;
}
[Display(Name = "Text Display Name", Prompt = "Text Display Prompt")]
public string TextInput { get; set; }
[Display(Name = "Number Display Name")]
public decimal NumberInput { get; set; }
[Display(Name = "Date Display Name")]
public DateTime? DateInput { get; set; }
[Display(Name = "Bool Display Name", Prompt ="Bool Display Prompt")]
public bool BoolInput { get; set; }
[Display(Name = "Required Text Input Label", Prompt = "Placeholder Text")]
[Required]
public string RequiredTextInput { get; set; }
public AppHelpersViewModel GetDisplayCopy()
{
var displayCopy = this.MemberwiseClone() as AppHelpersViewModel;
displayCopy.ViewRole = ViewRole.Display;
displayCopy.TextInput = "TextInput content";
displayCopy.RequiredTextInput = "RequiredTextInput content";
displayCopy.NumberInput = 45.4m;
displayCopy.DateInput = new DateTime(2016, 10, 24);
displayCopy.BoolInput = true;
return displayCopy;
}
}
视图组件
public class DisplaySourceViewComponent : ViewComponent
{
public DisplaySourceViewComponent(IHostingEnvironment hostingEnvironment)
{
WebRootPath = hostingEnvironment.WebRootPath;
ContentRootPath = hostingEnvironment.ContentRootPath;
}
public string ContentRootPath { get; set; }
public string WebRootPath { get; set; }
public async Task<IViewComponentResult> InvokeAsync(string executingViewPath, ViewRole viewRole)
{
if (viewRole != ViewRole.Display)
{
return new NullViewComponentResult();
}
IEnumerable<string> viewSource = await GetViewSourceAsync(executingViewPath);
return View(viewSource);
}
private int GetLastContentIndex(List<string> lines)
{
for (int i = lines.Count - 1; i >= 0; i--)
{
if (!String.IsNullOrWhiteSpace(lines[i]))
{
return i;
}
}
return -1;
}
private async Task<IEnumerable<string>> GetViewSourceAsync(string executingViewPath)
{
executingViewPath = executingViewPath.Substring(1).Replace('/', Path.DirectorySeparatorChar);
string viewFilePath = Path.Combine(ContentRootPath, executingViewPath);
var lines = new List<string>();
using (var reader = new StreamReader(viewFilePath, Encoding.UTF8))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (line.StartsWith("@model")) continue;
if (line.StartsWith("@await") && line.Contains(@"InvokeAsync(""DisplaySource""")) continue;
lines.Add(line);
}
}
return Trim(lines);
}
private IEnumerable<string> Trim(List<string> lines)
{
var contentLines = new List<string>();
int lastContentIndex = GetLastContentIndex(lines);
for (int i = 0; i <= lastContentIndex; i++)
{
string line = lines[i];
if (String.IsNullOrWhiteSpace(line) && contentLines.Count == 0) continue;
contentLines.Add(line);
}
return contentLines;
}
}
public class NullViewComponentResult : IViewComponentResult
{
public void Execute(ViewComponentContext context)
{
return;
}
public Task ExecuteAsync(ViewComponentContext context)
{
return Task.CompletedTask;
}
}
待办事项
- 将ViewComponent的用法更改为新的(MVC Core 1.1版本)TagHelpers语法。
- 以类似的方式包含模型文档。
- 记录一堆HtmlHelpers [这是我的!;-)]
希望对您有所帮助。