7387
ASP.NET MVC2でCustomHelperを作っています。

必要な情報が取得できない問題があったので、  
解決方法があればご教示ください。

ViewModelにDisplayName属性やValidationAttributeをつけています。

属性を取得する際はModelMetadata.FromLambdaExpression()で取得できますが、  
対象のViewModelがBaseViewModelをoverrideしている場合、  
BaseViewModelの属性（たとえばDisplayName）を取得するようです。  
※今回の場合、BaseViewModelにはDisplayName属性をつけていないので  
取得できない

```

        public static MvcHtmlString LabelExFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    
            return LabelExFor(html, expression, metadata.IsRequired);
        }
    
```

ViewではBaseViewModelをoverrideしたViewModelを用いているので  
ViewModelの属性を取得したいのですが、どのようにすればよいでしょうか？

尚、ViewModelのプロパティをoverrideではなくnewで定義した場合は  
ViewModelの属性を取ってくるようです。

# 最終的な回避方法

標準の`LabelFor`は用いず、自作の`LabelExFor`で置き換える。`LabelExFor`では`FromLambdaExpression()`ではなく、`FromStringExpression()`を用いてmetadataの取得を行う。

```

    public static MvcHtmlString LabelExFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
    {
        var htmlFieldName = ExpressionHelper.GetExpressionText(expression);
        var metadata = ModelMetadata.FromStringExpression(ExpressionHelper.GetExpressionText(expression), html.ViewData);
    
        string labelText = metadata.DisplayName ?? 
                            metadata.PropertyName ?? 
                            htmlFieldName.Split('.').Last();
        if (String.IsNullOrEmpty(labelText))
        {
            return MvcHtmlString.Empty;
        }
        （以下略）
    
```
CC BY-SA 3.0
2015-03-03T02:11:01.320
7342
2015-03-19T03:08:42.557
2015-03-19T03:08:42.557
8647
8647
question
c# asp.net mvc
ModelMetadata.FromLambdaExpressionが親のメタデータを参照する
現行の`ModelMetadata.FromLambdaExpression`の[ソース](http://referencesource.microsoft.com/#System.Web/ModelBinding/ModelMetadata.cs)の290行目で、

```

    containerType = memberExpression.Expression.Type;
    
```

とコンテナ型を求めている箇所が`System.Web.Mvc.dll`のバージョン2.0.0.0では

```

    containerType = body.Member.DeclaringType;
    
```

となっているため、過去に不具合修正が入っているのだと思われます。

## 拡張メソッドでの回避方法

例えば`LabelFor`の場合、以下のように拡張メソッドを実装すれば`ModelMetadata.FromStringExpression`を利用します。なお拡張メソッドの利用には`web.config`の編集が必要です。

```

    public static class HtmlHelperExtensions
    {
        public MvcHtmlString LabelFor2<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
        {
            return html.Label(ExpressionHelper.GetExpressionText(expression));
        }
    }
    
```

これでもダメであれば自分で`ModelMetadata`と`HtmlHelper`を作って`LabelForModel`に渡すか、自分でHTMLを作るしかないように思われます。
CC BY-SA 3.0
2015-03-03T13:32:09.280
7387
2015-03-18T11:56:50.403
2020-06-17T08:14:45.997
-1
5750
7342
answer