CSHTML / Razor视图的文档

时间:2016-11-15 22:17:27

标签: c# asp.net-mvc razor documentation

我正在努力记录我们的显示和编辑模板(作为扩展,记录我们所有的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帮助页面的系统选中?理想情况下,它会更进一步,从父类型开始,并允许您深入到每个类型的属性编辑器等,但我只是想先从小开始。

编辑:作为其中的一部分,我还想生成模板的示例,而无需硬/手动编写所述示例,只是为了帮助澄清我的想法。

2 个答案:

答案 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的使用情况。

结果

Final catalog display

解决方案

创建一个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;
    }
}

ViewComponent

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用法更改为new(从MVC Core 1.1开始)TagHelpers sintax。
  • 以类似方式包含模型文档。
  • 记录一堆HtmlHelpers [这是我的! ; - )]

希望它有所帮助。