Stack Overflow Exception in MVcHtmlString

308 views Asked by At

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.

1

There are 1 answers

1
AudioBubble On BEST ANSWER

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)