Razor + dynamic + internal + interface & the 'object' does not contain a definition for 'xxxx' exception
I’ve come across this strange issue and decided to blog about it since I can’t figure out exactly why this is happening it is clearly something to do with the DLR and interfaces.
First, if you are getting the exception: 'object' does not contain a definition for 'xxxx' it is related to either an object you have being marked internal or you are are using an anonymous object type for your model (which .Net will always mark as internal).
Here’s a really easy way to replicate this:
1. Create an internal model
internal class MyModel
{
public string Name {get;set;}
}
2. Return this model in your MVC action
public ActionResult Index()
{
return View(new InternalTestModel("Shannon"));
}
3. Make your view have a dynamic model and then try to render the model’s property
@model dynamic
<h1>@Model.Name</h1>
You’ll get the exception:
Server Error in '/' Application.
'object' does not contain a definition for 'Name'
So even though the error is not very informative, it makes sense since Razor is trying to access an internal class.
Try using a public interface
Ok so if we want to keep our class internal, we could expose it via a public interface. Our code might then look like this:
public interface IModel
{
string Name {get;}
}
internal class MyModel : IModel
{
public string Name {get;set;}
}
Then we can change our view to be strongly typed like:
@model IModel
<h1>@Model.Name</h1>
And it will work, however if you change your view back to be @model dynamic you will still get the exception. Pretty sure it’s because the DLR is just binding to the instance object and doesn’t really care about the interface… this makes sense.
Try using an abstract public class
For some reason if you make your internal class inherit from a public abstract class that implements the same interface you will not get this exception even though the object instance you are passing to razor is internal. For example with this structure:
public interface IModel
{
string Name {get;}
}
public abstract class ModelBase : IModel
{
public abstract Name {get;}
}
internal class MyModel : IModel
{
public override string Name {get;set;}
}
You will not get this error if your view is @model dynamic.
Strange!
I’m sure there’s something written in the DLR spec about this but still seems strange to me! If you are getting this error and you aren’t using anonymous objects for your model, hopefully this might help you figure out what is going on.