4

I have created my own Html Helper which adds red asterisks to any required field.

It successfully works with both

@Html.myLabelFor(model => model.Description)
//and
@Html.myLabelFor(model => model.Description, new { /*stuff*/ })

However, some of the code lines are like following

@Html.myLabelFor(model => model.Description, "Deletion Reason", new { /*stuff*/ })

My method was not designed to handle 3 parameters, so I added a caller which would handle 3 parameters

public static MvcHtmlString myLabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
     Expression<Func<TModel, TValue>> expression, string labelText, Object htmlAttributes)
  {
      return myLabelFor(html, expression, labelText, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
  }    

Below are other methods that are working properly (including internal, which contains all necessary code and whose structure I used as a reference)

public static MvcHtmlString myLabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
   Expression<Func<TModel, TValue>> expression, IDictionary<String, Object> htmlAttributes)
  {
      return LabelHelper(html, ModelMetadata.FromLambdaExpression(expression, html.ViewData),
          ExpressionHelper.GetExpressionText(expression), null, htmlAttributes);
  }

  public static MvcHtmlString myLabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
  Expression<Func<TModel, TValue>> expression)
  {
      return LabelHelper(html, ModelMetadata.FromLambdaExpression(expression, html.ViewData),
          ExpressionHelper.GetExpressionText(expression), null);
  }

  public static MvcHtmlString myLabelFor<TModel, TValue>(this HtmlHelper<TModel> html,
      Expression<Func<TModel, TValue>> expression, Object htmlAttributes)
  {
      return myLabelFor(html, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
  }

  //USED ITS STRUCTURE AS A REFERENCE
  internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, String htmlFieldName,
      String labelText = null, IDictionary<String, Object> htmlAttributes = null)

Logically, I was expecting that parameter labelText would take a value of "Deletion Reason" from the line of code above. However, instead it had thrown a StackOverflowException inside my 3-parameter method. Microsoft description was vague, additional explanation did not help, and additional solution was using

Expression<Func<TModel, string>> expression instead of my Expression<Func<TModel, TValue>> expression

I do not understand what I am doing wrong. At this point I can only think of "fiddle with parameters until it works", but I am hopeful there is more elegant solution to that problem.

PS: Please let me know if my code for internal helper will help to solve the problem.

12
  • Because your first myLabelFor() method is calling itself (not LabelHelper()) which in turn calls itself again, which in turn calls itself again and so on and so on. Commented Jun 23, 2016 at 22:53
  • Your first myLabelFor method calls itself! Commented Jun 23, 2016 at 22:54
  • @DavidG You mean the one with string labelText? Commented Jun 23, 2016 at 22:55
  • Yes, that one, it recursively calls itself. Commented Jun 23, 2016 at 22:56
  • @DavidG But what about the method inside big block with html, expression, and htmlAttributes, which also returns myLabelFor? It did not throw exception there, which is why I decided to use it instead of Label helper, since changing to LabelHelper causes errors. Commented Jun 23, 2016 at 22:59

1 Answer 1

2

You getting an exception on the first overload, because the method is recursively calling itself, and keeps doing so until the execution stack overflows. Rather than calling itself you need to change

return myLabelFor(html, 
                  expression,
                  labelText,
                  HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

to

return LabelHelper(html,
                   ModelMetadata.FromLambdaExpression(expression, html.ViewData),
                   ExpressionHelper.GetExpressionText(expression),
                   labelText,
                   HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));

From your comments, the reason your 4th overload which uses return myLabelFor(...) does not throw the exception is because it calls your 2nd overload which in turn calls return LabelHelper(...)

I recommend that you change the 4th overload to call LabelHelper() directly, and change all the public overloads to explicitly call LabelHelper(), passing all 4 parameters, which is the pattern used by the in-built `HtmlHelper extension methods (you can view the source code for LabelFor() here)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much Stephen! It works, and now I have learned the cause of it, along with some interesting source code. I am accepting your answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.