C# html-helper extend existing method without overriding?

后端 未结 1 1429
北荒
北荒 2021-01-22 04:26

I have already searched for the question and found possible answer, but I still need some help.

I am trying to write an html-helper to extend functionality of already ex

相关标签:
1条回答
  • 2021-01-22 04:38

    Here's a complete example that does what your asking

    Accessing the model attributes in a helper extension class

    public static class LabelExtensions
    {
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
            Expression<Func<TModel, TValue>> expression, IDictionary<String, Object> htmlAttributes,
            String requiredMarker = "*")
        {
            return LabelHelper(html, ModelMetadata.FromLambdaExpression(expression, html.ViewData),
                ExpressionHelper.GetExpressionText(expression), null, htmlAttributes, requiredMarker);
        }
    
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
            Expression<Func<TModel, TValue>> expression, Object htmlAttributes, String requiredMarker)
        {
            return LabelFor(html, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), requiredMarker);
        }
    
        internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, String htmlFieldName,
            String labelText = null, IDictionary<String, Object> htmlAttributes = null, String requiredMarker = null)
        {
            var resolvedLabelText = labelText ??
                                    metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
    
            var tag = new TagBuilder("label");
            tag.Attributes.Add("for",
                TagBuilder.CreateSanitizedId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName)));
            tag.SetInnerText(resolvedLabelText);
            tag.MergeAttributes(htmlAttributes, true);
    
            if (metadata.IsRequired && !String.IsNullOrWhiteSpace(requiredMarker))
            {
                var requiredSpan = new TagBuilder("span") {InnerHtml = requiredMarker};
                requiredSpan.AddCssClass("required");
    
                tag.InnerHtml += requiredSpan;
            }
    
            var result = tag.ToString(TagRenderMode.Normal);
    
            return new MvcHtmlString(result);
        }
    }
    

    and here's the unit tests

    public static class LabelExtensionFixtures
    {
        [TestFixture]
        public class should_return_label_with_required_info : MvcExtensionFixtureBase
        {
            private class TestClass
            {
                [Required]
                public Guid Id { get; set; }
            }
    
            private MvcHtmlString _expectedResult;
            private HtmlHelper<TestClass> _sut;
            private MvcHtmlString _result;
    
            [SetUp]
            public void Given()
            {
                //arrange
                _expectedResult =
                    MvcHtmlString.Create(
                        "<label class=\"control-label col-md-2\" for=\"Id\">Id<span class=\"required\">*</span></label>");
                _sut = CreateHtmlHelper(new TestClass {Id = Guid.NewGuid()});
    
                //act
                _result = _sut.LabelFor(model => model.Id, new { @class = "control-label col-md-2" }, "*");
            }
    
            [Test]
            public void Test()
            {
                //asert
                Assert.That(_result.ToHtmlString(), Is.EqualTo(_expectedResult.ToHtmlString()));
            }
        }
    }
    
    public abstract class MvcExtensionFixtureBase
    {
        protected HtmlHelper<T> CreateHtmlHelper<T>(T instance)
        {
            var viewDataDictionary = new ViewDataDictionary<T>(instance);
            var viewContext = A.Fake<ViewContext>();
            A.CallTo(() => viewContext.ViewData).Returns(viewDataDictionary);
    
            var viewDataContainer = A.Fake<IViewDataContainer>();
            A.CallTo(() => viewDataContainer.ViewData).Returns(viewDataDictionary);
    
            return new HtmlHelper<T>(viewContext, viewDataContainer);
        }
    }
    
    0 讨论(0)
提交回复
热议问题