Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpressionHelper.GetExpressionText(expression) not returning the name of my property

I have implemented a MVC Extension to format the numbers in my application. It is based off the code found here. And is as follows

public static MvcHtmlString DecimalBoxFor<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, double?>> expression, string format, object htmlAttributes = null)
{
    var name = ExpressionHelper.GetExpressionText(expression);   
    double? dec = expression.Compile().Invoke(html.ViewData.Model);
    var value = dec.HasValue ? (!string.IsNullOrEmpty(format) ? dec.Value.ToString(format) : dec.Value.ToString()): "";
    return html.TextBox(name, value, htmlAttributes);
}

When I call it with the following line of Razor syntax

@Html.DecimalBoxFor(model => Model.PointAttributes[i].Data.Y,"0.000", new { @class = "span1 number" })

I get an exception because the variable 'name' in my extension is an empty string. I have tried changing the var name line to this but it only gives me the property name of 'Y' and not the full 'Model.PointAttributes[i].Data.Y' that I need to bind the model back for MVC.

var name = ((expression.Body is MemberExpression ?((MemberExpression)expression.Body).Member : ((MemberExpression)((UnaryExpression)expression.Body).Operand).Member)).Name;
like image 389
PlTaylor Avatar asked May 10 '12 12:05

PlTaylor


3 Answers

Try using this function:

    static public string GetExpressionText(LambdaExpression p)
    {
        if (p.Body.NodeType == ExpressionType.Convert || p.Body.NodeType == ExpressionType.ConvertChecked)
        {
            p = Expression.Lambda(((UnaryExpression)p.Body).Operand,
                p.Parameters);
        }
        return ExpressionHelper.GetExpressionText(p);
    }
like image 179
Nadav Avatar answered Nov 15 '22 10:11

Nadav


This is a known behavior. I have figured out writing my own version of ExpressionHelper that handle that specific case. Now you have two option:

  1. Use the NuGet package:

    Install-Package Mariuzzo.Web.Mvc.Extras
    
  2. Or just grab the source code of the aforementioned ExpressionHelper and glue it into your project.

like image 33
Rubens Mariuzzo Avatar answered Nov 15 '22 09:11

Rubens Mariuzzo


Here a 'hybrid' one :)

    public static void AddModelError<TModel>(this ModelStateDictionary state, Expression<Func<TModel, object>> expression, string message)
    {
        LambdaExpression lambdaExpression = null;
        string fieldName = string.Empty;

        if (expression.Body.NodeType == ExpressionType.Convert || expression.Body.NodeType == ExpressionType.ConvertChecked)
        {
            lambdaExpression = Expression.Lambda(((UnaryExpression)expression.Body).Operand, expression.Parameters);
            fieldName = ExpressionHelper.GetExpressionText(lambdaExpression);
        } else {
            fieldName = ExpressionHelper.GetExpressionText(expression);
        }

        state.AddModelError(fieldName, message);
    }

This one is more compact and probably a better solution:

https://stackoverflow.com/a/12689563/951001

like image 38
KoalaBear Avatar answered Nov 15 '22 09:11

KoalaBear