Writing line of enterprise purposes normally means creating plenty of types for information entry. Writing the HTML for them over and over is tedious and likewise means copy-pasting the format construction into each single kind. Copy-pasting works superb so long as we one is proud of the design, however when it must be altered (past what’s potential by CSS), all types within the utility want to vary. To treatment this, I created a form-entry tag helper. Now creating an entry for a subject in a kind is so simple as <form-entry asp-for="LocationName" />.

Using the default scaffolding in Visual Studio, I’d get a kind that repeats the identical sample over and over, for every property of the view mannequin.

<kind asp-motion="Create">
    <div asp-validation-abstract="ModelOnly" class="text-danger"></div>
    <div class="form-group">
        <label asp-for="Name" class="control-label"></label>
        <enter asp-for="Name" class="form-control" />
        <span asp-validation-for="Name" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Address" class="control-label"></label>
        <enter asp-for="Address" class="form-control" />
        <span asp-validation-for="Address" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="City" class="control-label"></label>
        <enter asp-for="City" class="form-control" />
        <span asp-validation-for="City" class="text-danger"></span>
    </div>
    <div class="form-group">
      <enter kind="submit" worth="Create" class="btn btn-default" />
    </div>
</kind>

Using my form-entry tag helper, the code required is considerably much less.

<kind asp-motion="Create">
    <div asp-validation-abstract="ModelOnly" class="text-danger"></div>
    <form-entry asp-for="Name" />
    <form-entry asp-for="Address" />
    <form-entry asp-for="City" />
    <div class="form-group">
        <enter kind="submit" worth="Create" class="btn btn-default"/>
    </div>
</kind>

The design targets for the form-entry tag helper will be summarized as DRY. DRY is brief for Don’t Repeat Yourself. One motive for that’s to scale back typing. But that isn’t a very powerful half. No, the essential elements are readability and maintainability. With the form-entry tag helper the code will get a lot cleaner and it’s simpler to see what fields the shape are literally made up of.
The different essential half is maintainability. Repeating the identical html sample over and over in all types in utility means spreading the information of how types look throughout the applying. That information ought to be in a single single place.

Using Razor

I though thought it will be good to have the ability to use Razor for the template itself, to simply have the ability to name the tag helpers for producing labels and so on appropriately. Unfortunately I didn’t succeed on this goal. The motive is that the tag helpers are constructed on the idea that the razor file comprises the kind of the mannequin. And right here we wish to have the ability to use a generic Razor file for all totally different fashions within the mission.

Reusing Tag Helpers

When the Razor path turned out not possible, I as an alternative checked out calling the tag helpers from code. This too turned out to be arduous as it will require producing the proper context for a tag helper. But due to the layered structure of the tag helpers reuse was nonetheless potential. The inbuilt tag helpers don’t do the Html era themselves. Instead they depend on an IHtmlGenerator to try this. And the IHtmlGenerator turned out te be pretty easy to name from my customized tag helper.

public class FormEntryTagHelper: TagHelper
{
  personal readonly IHtmlGenerator htmlGenerator;
  personal readonly HtmlEncoder htmlEncoder;
 
  public FormEntryTagHelper(IHtmlGenerator htmlGenerator, HtmlEncoder htmlEncoder)
  {
    this.htmlGenerator = htmlGenerator;
    this.htmlEncoder = htmlEncoder;
  }
 
  personal const string ForAttributeName = "asp-for";
 
  [HtmlAttributeName(ForAttributeName)]
  public ModelExpression For { get; set; }
 
  [HtmlAttributeNotBound]
  [ViewContext]
  public ViewContext ViewContext { get; set; }
 
  public override void Process(TagHelperContext context, TagHelperOutput output)
  {
    output.TagName = "div";
    output.TagMode = TagMode.BeginTagAndFinishTag;
    output.Attributes.Add("class", "form-group");
 
    utilizing (var author = new StringWriter())
    {
      WriteLabel(author);
      WriteInput(author);
      WriteValidation(author);
      output.Content.AppendHtml(author.ToString());
    }
  }
 
  personal void WriteLabel(TextWriter author)
  {
    var tagBuilder = htmlGenerator.GenerateLabel(
      ViewContext,
      For.ModelExplorer,
      For.Name,
      labelText: null,
      htmlAttributes: new { @class = "control-label" });
 
    tagBuilder.WriteTo(author, htmlEncoder);
  }
 
  personal void WriteInput(TextWriter author)
  {
    var tagBuilder = htmlGenerator.GenerateTextBox(
      ViewContext,
      For.ModelExplorer,
      For.Name,
      worth: null,
      format: null,
      htmlAttributes: new { @class = "form-control" });
 
    tagBuilder.WriteTo(author, htmlEncoder);
  }
 
  personal void WriteValidation(TextWriter author)
  {
    var tagBuilder = htmlGenerator.GenerateValidationMessage(
      ViewContext,
      For.ModelExplorer,
      For.Name,
      message: null,
      tag: null,
      htmlAttributes: new { @class = "text-danger" });
 
    tagBuilder.WriteTo(author, htmlEncoder);
  }
}

Posted in
C#, Web on 2018-04-23 | Tagged Asp.Net Core




Source link