Server Error in '/' Application.
--------------------------------------------------------------------------------
The property System.Data.DataRowView.Dosage 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 System.Data.DataRowView.Dosage could not be found.
Source Error:
Line 1: <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
Line 2: <td><%= Html.Display("Dosage")%></td>
Line 3: <td><%= Html.Display("Drug") %></td>
Line 4: <td><%= Html.Display("Patient") %></td>
Source File: c:\Tests\Test222\Test222\Views\Home\Row.ascx Line: 2
Stack Trace:
[ArgumentException: The property System.Data.DataRowView.Dosage could not be found.]
System.Web.Mvc.AssociatedMetadataProvider.GetMetadataForProperty(Func`1 modelAccessor, Type containerType, String propertyName) +462344
System.Web.Mvc.ModelMetadata.GetMetadataFromProvider(Func`1 modelAccessor, Type modelType, String propertyName, Type containerType) +79
System.Web.Mvc.ModelMetadata.FromStringExpression(String expression, ViewDataDictionary viewData) +395
System.Web.Mvc.Html.TemplateHelpers.Template(HtmlHelper html, String expression, String templateName, String htmlFieldName, DataBoundControlMode mode, TemplateHelperDelegate templateHelper) +41
System.Web.Mvc.Html.TemplateHelpers.Template(HtmlHelper html, String expression, String templateName, String htmlFieldName, DataBoundControlMode mode) +60
System.Web.Mvc.Html.DisplayExtensions.Display(HtmlHelper html, String expression) +10
ASP.views_home_row_ascx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\Tests\Test222\Test222\Views\Home\Row.ascx:2
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
System.Web.UI.Page.Render(HtmlTextWriter writer) +29
System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +59
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266
--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.4200; ASP.NET Version:2.0.50727.4016
Basically, I just want to use the same rendering that I have for the types in the application.
Is there any workaround or fix for this problem?
Here is the code to create DataTable:
static DataTable GetTable()
{
//
// Here we create a DataTable with four columns.
//
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
//
// Here we add five DataRows.
//
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
return table;
}
In case of using the DataTable, the Object that represents the row will be of type
DataRowView.To access a value from that object, you should access it throug it's
Row Property:
If you put something like this: <%= Html.Eval("Dosage") %> it will return a value correctly.
View and all the code is correct, the problem is in ModelMeradata.FromStringExpression:
public static ModelMetadata FromStringExpression(string expression, ViewDataDictionary viewData) {
if (expression == null) {
throw new ArgumentNullException("expression");
}
if (viewData == null) {
throw new ArgumentNullException("viewData");
}
if (expression.Length == 0) { // Empty string really means "model metadata for the current model"
return FromModel(viewData);
}
ViewDataInfo vdi = viewData.GetViewDataInfo(expression);
Type containerType = null;
Type modelType = null;
Func<object> modelAccessor = null;
string propertyName = null;
if (vdi != null) {
if (vdi.Container != null) {
containerType = vdi.Container.GetType();
}
modelAccessor = () => vdi.Value;
if (vdi.PropertyDescriptor != null) {
propertyName = vdi.PropertyDescriptor.Name;
modelType = vdi.PropertyDescriptor.PropertyType;
}
else if (vdi.Value != null) { // We only need to delay accessing properties (for LINQ to SQL)
modelType = vdi.Value.GetType();
}
}
// Try getting a property from ModelMetadata if we couldn't find an answer in ViewData
else if (viewData.ModelMetadata != null) {
ModelMetadata propertyMetadata = viewData.ModelMetadata.Properties.Where(p => p.PropertyName == expression).FirstOrDefault();
if (propertyMetadata != null) {
return propertyMetadata;
}
}
return GetMetadataFromProvider(modelAccessor, modelType ?? typeof(string), propertyName, containerType);
}
ViewDataInfo is returned correctly and vdi is not null there, and after the if statement it tries to get metadata by calling GetMetadataFromProvider (you can see in the callstack in my first post). And there is a propertyName = "Dosage", containerType =
DataRowView, and there is modelAccessor too which will just return the correct value of the Column.
So finally it gets to AssociatedMetadataProvider.GetMetadataForProperty() where it actually throws exception because there is no such property on the DataRowView.
After that line, an ArgumentException is being thrown by the code if the property is null.
if (property == null) {
throw new ArgumentException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.Common_PropertyNotFound,
containerType.FullName, propertyName));
}
Apparently, incase of the DataRowView, our target property will be in a sub level inside the Row proeprty and that's why the Find method is unable to locate the property.
I think there must be a check on the ContainerType and if it's of type DataRowView (like incase we have model with type DataView as incase which is also IEnumerable) , then i think we should first access the Row property then get the target property from the Row.
I don't want to provide fix because i'm not good enough in C#, but this is what it could be :
PropertyDescriptor property = typeDescriptor.GetProperties().Find("Row", true).GetChildProperties().Find(propertyName, true);
if (property == null)
{
// Last chance check incase the Container type is DataRowView
if (containerType == typeof(DataRowView))
property = typeDescriptor.GetProperties().Find("Row", true).GetChildProperties().Find(propertyName, true);
if (property == null)
{
throw new ArgumentException(
String.Format(
CultureInfo.CurrentCulture,
MvcResources.Common_PropertyNotFound,
containerType.FullName, propertyName));
}
}
The Html.Display/Editor functionality is not designed to work with objects this way. It's designed to work with raw objects with properties, not dictionaries.
Marked as answer by ricka6 on Mar 09, 2010 09:24 PM
SuperUser
0 Points
4 Posts
Templates, Metadata and DataTable
Mar 08, 2010 05:40 PM|LINK
Hi guys,
I'm trying to show data from DataTable using templates.
I created a view which goes through items of IEnumerable and renders each item:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable>" %> <table> <tr> <th> Dosage </th> <th> Drug </th> <th> Patient </th> <th> Date </th> </tr> <% foreach (var item in Model) { %> <tr> <% Html.RenderPartial("Row", item); %> </tr> <% } %> </table>To render row I use partial view with name "Row", and I'm passing a row as a model to that view. In this view, I'm trying to render data:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <td><%= Html.Display("Dosage")%></td> <td><%= Html.Display("Drug") %></td> <td><%= Html.Display("Patient") %></td> <td><%= Html.Display("Date")%></td>On the first line I get an exception:
Server Error in '/' Application. -------------------------------------------------------------------------------- The property System.Data.DataRowView.Dosage 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 System.Data.DataRowView.Dosage could not be found. Source Error: Line 1: <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> Line 2: <td><%= Html.Display("Dosage")%></td> Line 3: <td><%= Html.Display("Drug") %></td> Line 4: <td><%= Html.Display("Patient") %></td> Source File: c:\Tests\Test222\Test222\Views\Home\Row.ascx Line: 2 Stack Trace: [ArgumentException: The property System.Data.DataRowView.Dosage could not be found.] System.Web.Mvc.AssociatedMetadataProvider.GetMetadataForProperty(Func`1 modelAccessor, Type containerType, String propertyName) +462344 System.Web.Mvc.ModelMetadata.GetMetadataFromProvider(Func`1 modelAccessor, Type modelType, String propertyName, Type containerType) +79 System.Web.Mvc.ModelMetadata.FromStringExpression(String expression, ViewDataDictionary viewData) +395 System.Web.Mvc.Html.TemplateHelpers.Template(HtmlHelper html, String expression, String templateName, String htmlFieldName, DataBoundControlMode mode, TemplateHelperDelegate templateHelper) +41 System.Web.Mvc.Html.TemplateHelpers.Template(HtmlHelper html, String expression, String templateName, String htmlFieldName, DataBoundControlMode mode) +60 System.Web.Mvc.Html.DisplayExtensions.Display(HtmlHelper html, String expression) +10 ASP.views_home_row_ascx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\Tests\Test222\Test222\Views\Home\Row.ascx:2 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Page.Render(HtmlTextWriter writer) +29 System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +59 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266 -------------------------------------------------------------------------------- Version Information: Microsoft .NET Framework Version:2.0.50727.4200; ASP.NET Version:2.0.50727.4016Basically, I just want to use the same rendering that I have for the types in the application.
Is there any workaround or fix for this problem?
Here is the code to create DataTable:
static DataTable GetTable() { // // Here we create a DataTable with four columns. // DataTable table = new DataTable(); table.Columns.Add("Dosage", typeof(int)); table.Columns.Add("Drug", typeof(string)); table.Columns.Add("Patient", typeof(string)); table.Columns.Add("Date", typeof(DateTime)); // // Here we add five DataRows. // table.Rows.Add(25, "Indocin", "David", DateTime.Now); table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now); table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now); table.Rows.Add(21, "Combivent", "Janet", DateTime.Now); table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now); return table; }Thanks.
anas
All-Star
73649 Points
7914 Posts
Moderator
Re: Templates, Metadata and DataTable
Mar 08, 2010 06:28 PM|LINK
In case of using the DataTable, the Object that represents the row will be of type DataRowView.To access a value from that object, you should access it throug it's Row Property:
Example:
Html.Display("Row.Dosage")
SuperUser
0 Points
4 Posts
Re: Templates, Metadata and DataTable
Mar 08, 2010 06:46 PM|LINK
Well, it doesn't work like this.
If you put something like this: <%= Html.Eval("Dosage") %> it will return a value correctly.
View and all the code is correct, the problem is in ModelMeradata.FromStringExpression:
public static ModelMetadata FromStringExpression(string expression, ViewDataDictionary viewData) { if (expression == null) { throw new ArgumentNullException("expression"); } if (viewData == null) { throw new ArgumentNullException("viewData"); } if (expression.Length == 0) { // Empty string really means "model metadata for the current model" return FromModel(viewData); } ViewDataInfo vdi = viewData.GetViewDataInfo(expression); Type containerType = null; Type modelType = null; Func<object> modelAccessor = null; string propertyName = null; if (vdi != null) { if (vdi.Container != null) { containerType = vdi.Container.GetType(); } modelAccessor = () => vdi.Value; if (vdi.PropertyDescriptor != null) { propertyName = vdi.PropertyDescriptor.Name; modelType = vdi.PropertyDescriptor.PropertyType; } else if (vdi.Value != null) { // We only need to delay accessing properties (for LINQ to SQL) modelType = vdi.Value.GetType(); } } // Try getting a property from ModelMetadata if we couldn't find an answer in ViewData else if (viewData.ModelMetadata != null) { ModelMetadata propertyMetadata = viewData.ModelMetadata.Properties.Where(p => p.PropertyName == expression).FirstOrDefault(); if (propertyMetadata != null) { return propertyMetadata; } } return GetMetadataFromProvider(modelAccessor, modelType ?? typeof(string), propertyName, containerType); }ViewDataInfo is returned correctly and vdi is not null there, and after the if statement it tries to get metadata by calling GetMetadataFromProvider (you can see in the callstack in my first post). And there is a propertyName = "Dosage", containerType = DataRowView, and there is modelAccessor too which will just return the correct value of the Column.
So finally it gets to AssociatedMetadataProvider.GetMetadataForProperty() where it actually throws exception because there is no such property on the DataRowView.
Thanks.
SuperUser
0 Points
4 Posts
Re: Templates, Metadata and DataTable
Mar 08, 2010 06:58 PM|LINK
I forgot to say that I pass DefaultView of the DataTable to the List view:
<% Html.RenderPartial("List", ((DataTable)ViewData["Data"]).DefaultView); %>Thanks.
anas
All-Star
73649 Points
7914 Posts
Moderator
Re: Templates, Metadata and DataTable
Mar 08, 2010 08:12 PM|LINK
I think the problem is located in the class "AssociatedMetadataProvider" at line 49:
PropertyDescriptor property = typeDescriptor.GetProperties().Find(propertyName, true);
After that line, an ArgumentException is being thrown by the code if the property is null.
if (property == null) { throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, MvcResources.Common_PropertyNotFound, containerType.FullName, propertyName)); }Apparently, incase of the DataRowView, our target property will be in a sub level inside the Row proeprty and that's why the Find method is unable to locate the property.
I think there must be a check on the ContainerType and if it's of type DataRowView (like incase we have model with type DataView as incase which is also IEnumerable) , then i think we should first access the Row property then get the target property from the Row.
I don't want to provide fix because i'm not good enough in C#, but this is what it could be :
PropertyDescriptor property = typeDescriptor.GetProperties().Find("Row", true).GetChildProperties().Find(propertyName, true); if (property == null) { // Last chance check incase the Container type is DataRowView if (containerType == typeof(DataRowView)) property = typeDescriptor.GetProperties().Find("Row", true).GetChildProperties().Find(propertyName, true); if (property == null) { throw new ArgumentException( String.Format( CultureInfo.CurrentCulture, MvcResources.Common_PropertyNotFound, containerType.FullName, propertyName)); } }SuperUser
0 Points
4 Posts
Re: Templates, Metadata and DataTable
Mar 08, 2010 08:29 PM|LINK
I think this is a bug in the framework which should be fixed.
Thanks.
bradwils
Contributor
5779 Points
691 Posts
Microsoft
Re: Templates, Metadata and DataTable
Mar 09, 2010 12:08 AM|LINK
The Html.Display/Editor functionality is not designed to work with objects this way. It's designed to work with raw objects with properties, not dictionaries.