2011-03-26 13 views
1

Html.Editor()を拡張して、HTMLを生成するモデルのいくつかの属性に基づいている必要があります。例:ユーザーが管理者と異なる場合、生成されたHTMLはViewには表示されません。この場合Extend Html.Editor()

public class Person 
{ 
    public string Name { get; set; } 

    [DisplayFor(Role.Admin)] 
    public string Surname { get; set; } 
} 

答えて

2

サンプル実装があります。

public class MyMetadataProvider : DataAnnotationsModelMetadataProvider 
{ 
    protected override ModelMetadata CreateMetadata(
     IEnumerable<Attribute> attributes, 
     Type containerType, 
     Func<object> modelAccessor, 
     Type modelType, 
     string propertyName 
    ) 
    { 
     var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 
     var displayFor = attributes.OfType<DisplayForAttribute>().FirstOrDefault(); 
     if (displayFor != null) 
     { 
      metadata.AdditionalValues.Add("RequiredRole", displayFor.Role); 
     } 
     return metadata; 
    } 
} 

Application_Startに登録されます:

protected void Application_Start() 
{ 
    AreaRegistration.RegisterAllAreas(); 

    RegisterGlobalFilters(GlobalFilters.Filters); 
    RegisterRoutes(RouteTable.Routes); 

    ModelMetadataProviders.Current = new MyMetadataProvider(); 
} 

​​

次のあなたは、この属性を使用するカスタムメタデータプロバイダを書くことができます:あなたは、次の属性を定義したと仮定しましょう

最後の部分は、String型(~/Views/Shared/EditorTemplates/String.cshtml)のカスタムエディタテンプレートを記述することです:

@{ 
    var visible = false; 
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("RequiredRole")) 
    { 
     var role = (string)ViewData.ModelMetadata.AdditionalValues["RequiredRole"]; 
     visible = User.IsInRole(role); 
    } 
} 
@if (visible) 
{ 
    @Html.TextBox(
     "", 
     ViewData.TemplateInfo.FormattedModelValue, 
     new { @class = "text-box single-line" } 
    ) 
} 

最後に属性を使用する:

public class MyViewModel 
{ 
    [DisplayFor("Admin")] 
    public string Name { get; set; } 
} 

やビューのを:

@using (Html.BeginForm()) 
{ 
    @Html.EditorFor(model => model.Name) 
    <input type="submit" value="OK" /> 
} 

明らかにこれが唯一の文字列エディタテンプレートをカバーしていますが例を簡単に他に拡張することができdefault templatesには、表示テンプレートも含まれています。

+0

素晴らしい構造と実装! – nttakr

+0

@ダーリン、私はこれを動作させることはできません。 'return metadata'ステートメントにブレークポイントを置くことで、すべてが素晴らしいように見えます。メタデータへの私の付加価値やその他の調整はすべてそこにあります。しかし、Viewが何らかの方法でロードされる頃に、ViewModel.ModelMetaDataには私のCustomProviderメタデータが含まれていませんか? –

+0

@Doug Chamberlain、あなたは 'DisplayForAttribute'属性で修飾されたプロパティのエディタテンプレートの中でこれをしていますか?私の例では、デフォルトの 'String.cshtml'エディタテンプレートをオーバーライドしています。 –

0

私のプロジェクトには同じものがありますが、コードは動作しています。

は、私は私のObject.ascxで ModelMetadataまたは/および PropertyInfo

public static bool IsVisibleForRole(this PropertyInfo property, User c); 

のための拡張メソッドを書いた:

for (var field in fields) { 
    if(!field.IsVisibleForRole(this.CurrentUser())) continue; 
    //... 
} 

けれども、あなたのケースでは、あなたは、フィールドをスキップしていないかもしれないが、インサート代わりに<input type="hidden">しかし、これはセキュリティの問題かもしれません。詳細は、次をご覧ください。http://www.codethinked.com/aspnet-mvc-think-before-you-bind

関連する問題