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