我正在努力记录我们的显示和编辑模板(作为扩展,记录我们所有的CSHTML都是有益的)。话虽如此,我从未见过任何记录CSHTML Razor Views的方法。
例如,我有这个CSHTML EditorTemplate:MoneyPicker.cshtml
@model Decimal?
@{
Layout = null;
}
<div class="money-picker" data-money-picker>
<div class="form-control-wrapper">
@Html.TextBox(
"",
ViewData.TemplateInfo.FormattedModelValue,
new
{
type = "number",
@class = "form-control money-control",
placeholder = ViewData.ModelMetadata.Watermark ?? ViewData.ModelMetadata.DisplayName
} )
</div>
</div>
我知道这不是C#,但是有一些方法可以添加XML文档(或等效文档):
/// <summary>
/// Displays a text box wrapped with the money-picker wrappers, allowing javascript to show money buttons to pick the value.
/// </summary>
/// <param name="Model">A currency value</param>
/// <remarks>
/// The input is a text box that has the type "number"
/// </remarks>
如果没有,有没有人找到某种方法来记录编辑器/显示模板,这些模板可以被某种类似于Asp.Net WebApi的api帮助页面的系统选中?理想情况下,它会更进一步,从父类型开始,并允许您深入到每个类型的属性编辑器等,但我只是想先从小开始。
编辑:作为其中的一部分,我还想生成模板的示例,而无需硬/手动编写所述示例,只是为了帮助澄清我的想法。
答案 0 :(得分:1)
我也调查了这一点,但我找不到任何记录View
的方法,现在我刚刚记录了Controller
中的视图:
/// <summary>
/// This is an example of documentation for the View.
/// </summary>
/// <returns>This is what I am returning.</returns>
public ActionResult CreateNewUser()
{
return View();
}
您可以使用以下方式为此生成文档: SandCastle(我更喜欢这个)或GhostDoc。
您也可以在View
中写下正常评论,以便进行解释。
@* This is a comment *@
答案 1 :(得分:0)
这项工作正在进行中,但可能有所帮助。
一个MVC 5应用程序迁移到MVC Core,其中包含很多内部开发的HtmlHelper,必须从头开始重写MVC Core [:-(]但是,想要立即开始使用MVC Core,只需要很少的视图尽可能地改变。
我们的想法是拥有一个帮助程序目录,作为MVC Core应用程序运行,记录Razor的使用情况。
创建一个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
@{
var displayModel = Model.GetDisplayCopy();
}
<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;
}
}
希望它有所帮助。