2012-04-02 2 views
11

私は、ASP.NET MVC3アプリケーションのRazorビューの1つに奇妙な問題があります。デバッガコンソールにその値を書き出すときにプロパティが存在するように見える場合、プロパティが見つからないというエラーが表示されます。ASP.NET MVC3の面倒やインターフェイス継承:なぜこのプロパティを見つけることができないのですか?

私のビューは、そのモデルとしてFormEditViewModelというクラスをとります。 FormEditViewModelには、別のインターフェイスIFormObjectから継承するインターフェイスであるIForm型のプロパティがあります。 IFormObjectはプロパティNameを定義するため、IFormを実装するものはすべてNameというプロパティを実装する必要があります。具体的な型FormはインターフェイスIFormを実装し、必要に応じてNameプロパティを定義します。

コードを実行し、ビューに渡されるFormEditViewModelオブジェクトを調べると、フォームにIForm型のプロパティがあり、このFormオブジェクトにNameプロパティが含まれていることがわかります。私は私のコントローラに以下の行を挿入した場合、それはビューに渡される直前FormEditViewModel.Nameの値を書き出すために、出力ウィンドウには、正しい名前を示しています。しかし、

Debug.WriteLine("Name: " + vm.Form.Name); 

を、私は、ビューを実行するとI 「MyCompany.MyApplication.Domain.Forms.IForm.Nameプロパティが見つかりませんでした」というエラーが表示されます。コントローラのC#コードが明白にできるとき、RazorがNameプロパティを見つけられないのはなぜですか?

私の見解はこのようになります。例外をスローする行は、@ Html.LabelFor(model => model.Form.Name、 "Form title")です。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using MyCompany.MyApplication.Domain.Forms; 
using MyCompany.App.Web.ViewModels; 

namespace MyCompany.MyApplication.ViewModels 
{ 
    public class FormEditViewModel : ViewModelBase 
    { 
     public IForm Form { get; set; } 
     public int Id 
     { 
      get { return Form.ZooFormId; } 
     } 
     public IEnumerable<Type> Types { get; set; } 
     public Dictionary<string, string> FriendlyNamesForTypes { get; set; } 
     public Dictionary<string, string> FriendlyNamesForProperties { get; set; } 
     public IEnumerable<String> PropertiesForUseInForms { get; set; } 
     public ObjectBrowserTreeViewModel ObjectBrowserTreeViewModel { get; set; } 
    } 
} 

Formオブジェクトが本当に長いですので、私はここで全部を貼り付けません。

@using MyCompany.MyApplication.ViewModels; 
@model FormEditViewModel 
@{ 
    ViewBag.Title = "Edit form"; 
} 
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 
<div class="MyApplicationcontainer"> 
    @using (Html.BeginForm("UpdateForm", "ZooForm")) 
    { 
     <div class="formHeader"> 
      @Html.ValidationSummary(true) 
      @Html.Hidden("id", Model.Form.ZooFormId) 
      <div id="editFormTitleDiv"> 
       <div class="formFieldContainer"> 
        @Html.Label("Form ID") 
        @Html.TextBoxFor(m => m.Form.ZooFormId, new { @disabled = true }) 
       </div> 
       <div class="formFieldContainer"> 
        @Html.LabelFor(model => model.Form.Name, "Form title") 
        @Html.EditorFor(model => model.Form.Name) 
        @Html.ValidationMessageFor(model => model.Form.Name) 
       </div> 
       ... 

は、ここでビューモデルです。

public class Form : FormObject, IForm 

FormオブジェクトはNameプロパティを再定義しませんが、FormObjectクラスから継承します。 FormObjectは次のようになります。

public abstract class FormObject : IFormObject 

ここではインターフェイスIFormです。あなたが見ることができるように、それは名前のメンバを宣言したが、IFormObjectからことを継承することを期待していません。

using System; 
namespace MyCompany.MyApplication.Domain.Forms 
{ 
    public interface IForm : IFormObject 
    { 
     bool ContainsRequiredFields(); 
     MyCompany.MyApplication.Domain.Forms.Factories.IFormFieldFactory FormFieldFactory { get; } 
     MyCompany.MyApplication.Domain.Forms.Factories.IFormPageFactory FormPageFactory { get; } 
     string FriendlyName { get; set; } 
     System.Collections.Generic.List<IFormField> GetAllFields(); 
     System.Collections.Generic.IEnumerable<DomainObjectPlaceholder> GetObjectPlaceholders(); 
     System.Collections.Generic.IEnumerable<IFormField> GetRequiredFields(); 
     System.Collections.Generic.IEnumerable<MyCompany.MyApplication.Models.Forms.FormObjectPlaceholder> GetRequiredObjectPlaceholders(); 
     System.Collections.Generic.List<IFormSection> GetSectionsWithMultipliableOption(); 
     MyCompany.MyApplication.BLL.IHighLevelFormUtilities HighLevelFormUtilities { get; } 
     int? MasterId { get; set; } 
     DomainObjectPlaceholder MasterObjectPlaceholder { get; set; } 
     MyCompany.MyApplication.Domain.Forms.Adapters.IObjectPlaceholderAdapter ObjectPlaceholderAdapter { get; } 
     MyCompany.MyApplication.Domain.Forms.Adapters.IObjectPlaceholderRelationshipAdapter ObjectPlaceholderRelationshipAdapter { get; } 
     System.Collections.Generic.List<IFormPage> Pages { get; set; } 
     MyCompany.MyApplication.Repository.IAppRepository AppRepo { get; set; } 
     int ZooFormId { get; } 
     MyCompany.MyApplication.BLL.IPocoUtils PocoUtils { get; } 
     void RemoveSectionWithoutChangingDatabase(int sectionId); 
     int? TopicId { get; set; } 
     DomainObjectPlaceholder TopicObjectPlaceholder { get; set; } 
     System.Collections.Generic.IEnumerable<FluentValidation.Results.ValidationResult> ValidationResults { get; set; } 
    } 
} 

そして、ここでは、インタフェースIFormObjectです:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace MyCompany.MyApplication.Domain.Forms 
{ 
    public interface IFormObject 
    { 
     string Name { get; } 
     string LongName { get; } 
     Guid UniqueId { get; } 
     string Prefix { get; } 
     string IdPath { get; set; } 
     string IdPathWithPrefix { get; } 
    } 
} 

質問をされ、なぜカミソリはありませんIFormがIFormObjectからNameプロパティを継承すると予想していたので、私はそれを実行すると、私に次の例外を与えてくれますか?

Server Error in '/' Application. 

The property MyCompany.MyApplication.Domain.Forms.IForm.Name could not be found. 

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.ArgumentException: The property MyCompany.MyApplication.Domain.Forms.IForm.Name could not be found. 

Source Error: 


Line 24:     </div> 
Line 25:     <div class="formFieldContainer"> 
Line 26:      @Html.LabelFor(model => model.Form.Name, "Form title") 
Line 27:      @Html.EditorFor(model => model.Form.Name) 
Line 28:      @Html.ValidationMessageFor(model => model.Form.Name) 

Source File: c:\Users\me\Documents\Visual Studio 2010\Projects\zooDBMain\zooDB\zooDB\Views\ZooForm\Edit.cshtml Line: 26 

Stack Trace: 


[ArgumentException: The property MyCompany.MyApplication.Domain.Forms.IForm.Name could not be found.] 
    System.Web.Mvc.AssociatedMetadataProvider.GetMetadataForProperty(Func`1 modelAccessor, Type containerType, String propertyName) +505385 
    System.Web.Mvc.ModelMetadata.GetMetadataFromProvider(Func`1 modelAccessor, Type modelType, String propertyName, Type containerType) +101 
    System.Web.Mvc.ModelMetadata.FromLambdaExpression(Expression`1 expression, ViewDataDictionary`1 viewData) +421 
    System.Web.Mvc.Html.LabelExtensions.LabelFor(HtmlHelper`1 html, Expression`1 expression, String labelText) +56 
    ASP._Page_Views_ZooForm_Edit_cshtml.Execute() in c:\Users\me\Documents\Visual Studio 2010\Projects\zooDBMain\zooDB\zooDB\Views\ZooForm\Edit.cshtml:26 
    System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +272 
    System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +81 
    System.Web.WebPages.StartPage.RunPage() +58 
    System.Web.WebPages.StartPage.ExecutePageHierarchy() +94 
    System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +173 
    System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +220 
    System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +115 
    System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +303 
    System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +13 
    System.Web.Mvc.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19() +23 
    System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +260 
    System.Web.Mvc.<>c__DisplayClass1e.<InvokeActionResultWithFilters>b__1b() +19 
    System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +177 
    System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +343 
    System.Web.Mvc.Controller.ExecuteCore() +116 
    System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +97 
    System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10 
    System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37 
    System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21 
    System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12 
    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +62 
    System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +50 
    System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7 
    System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +22 
    System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60 
    System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9 
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8971485 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184 

Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.547 

私は私の継承階層は少し厄介であり、これは最も美しいコードではありませんが、私はこの問題が発生し、どのような私のオプションは、それを固定するためのものである理由を知りたいんだということを理解します。インターフェイスの継承がC#でどのように機能するかを理解できないのですか?

答えて

7

thisの質問とthisも参照してください。どうやらこれは既知の問題で、回避策は次のように思われます。

<%: Html.HiddenFor(m => (m as IFormObject).Name) %> 
+0

ありがとうBryan。マイクロソフトがそれを修正するつもりはなく、(最初のリンクのScott Hanselmanのコメントから)「インターフェースベースのモデルを持つことは私たちが奨励しているものではない」と思っています。私の場合のように、型がインターフェイスであるメンバを持つ具体的なクラスを含む、すべてのクラスをビューに渡すことができるので、アドバイスは実際にはインターフェイスを避けて安全な側に置くことを意味します。 。あなたの回避策を使用してください: @ Html.HiddenFor(m =>(IFormObject).Name) – Richard

+0

@リチャード:さて、ASP.NET MVCはオープンソースです。 –

関連する問題