2012-04-02 6 views
11

Ho uno strano problema con una delle mie viste Razor in un'applicazione ASP.NET MVC3. Ricevo un errore che mi dice che non è possibile trovare una proprietà, quando la proprietà sembra esistere quando scrivo il suo valore sulla console del debugger.Razor e ereditarietà dell'interfaccia in ASP.NET MVC3: perché non è possibile trovare questa proprietà?

La mia vista prende come modello una classe denominata FormEditViewModel. FormEditViewModel ha una proprietà di tipo IForm, un'interfaccia che eredita da un'altra interfaccia, IFormObject. IFormObject definisce un nome di proprietà, quindi qualsiasi implementazione di IForm deve implementare una proprietà denominata Nome. Il tipo concreto Form implementa l'interfaccia IForm e definisce una proprietà Name come richiesto.

Quando eseguo il codice e ispeziono l'oggetto FormEditViewModel passato alla vista, posso vedere che ha una proprietà Form, di tipo IForm e questo oggetto Form ha una proprietà Name. Se inserisco la seguente riga nel mio controller, per scrivere il valore di FormEditViewModel.Name appena prima che si passa alla vista, la finestra di output viene visualizzato il nome corretto:

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

Eppure, quando ho eseguito la vista che ottenere un errore dicendo che "La proprietà MyCompany.MyApplication.Domain.Forms.IForm.Name non è stata trovata." Perché Razor non può trovare la proprietà Name quando il codice C# nel controller è evidentemente in grado?

La mia vista va così. La riga che genera l'eccezione è @ Html.LabelFor (model => model.Form.Name, "Titolo modulo").

@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> 
       ... 

Ecco il modello di vista:

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; } 
    } 
} 

oggetto la forma è davvero lunga quindi non mi incollare il tutto qui. Si dichiara così:

public class Form : FormObject, IForm 

oggetto la forma non ridefinire la proprietà Name, ma eredita dalla classe FormObject. FormObject inizia così:

public abstract class FormObject : IFormObject 

Ecco l'interfaccia IForm. Come si può vedere, non dichiara un membro di nome, ma si aspetta di ereditare che dal 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; } 
    } 
} 

Ed ecco l'IFormObject di interfaccia:

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; } 
    } 
} 

La domanda è: perché fa il Razor vista mi danno la seguente eccezione quando lo eseguo, poiché mi sarei aspettato che IForm ereditasse la sua proprietà Name da IFormObject?

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 

mi rendo conto che la mia gerarchia di ereditarietà è un po 'disordinato e che questo non è il codice più bello, ma io sono curioso di sapere il motivo per cui questo accade e quali sono le mie opzioni per il fissaggio. Non riesco a capire qualcosa su come l'ereditarietà dell'interfaccia funziona in C#?

risposta

7

Verificare this question e this uno pure. Apparentemente questo è un problema noto e il lavoro sembra essere:

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

Grazie Bryan.Deludente vedere che Microsoft non ha intenzione di risolverlo e (dal commento di Scott Hanselman sotto il primo dei tuoi link) che "Avere dei modelli basati sull'interfaccia non è qualcosa che incoraggiamo". Poiché in linea di principio qualsiasi classe può essere passata a una vista, inclusa una classe concreta con membri il cui tipo è un'interfaccia (come nel mio caso) il suo consiglio in realtà significa evitare le interfacce del tutto solo per essere sicuri, il che sembra una cattiva pratica . Utilizzerò la soluzione alternativa, che dovrebbe essere: @ Html.HiddenFor (m => (m come IFormObject) .Name) – Richard

+0

@Richard: Bene, ora che ASP.NET MVC è open source, le cose potrebbero cambiare :) –

Problemi correlati