Reputation: 3141
Since it is not possible to pass multiple models to a view in ASP.NET MVC 4, I am trying to stuff the various models into a dynamic ExpandoObject
and then unpacking it from within the view.
My Model (consists of more than just this class, but for brevity I'll just show this):
public class Modular_ArtistModel
{
public string Artist_Name { get; set; }
}
My Controller:
(I am packing more than just this List<>
object into the dynamic
object, but for brevity's sake...)
dynamic ArtistModel = new ExpandoObject();
var Modular_ArtistModel = LoadSP_Modular_ArtistModel("sp_Mod_Artist_Artist", i);
List<Modular_ArtistModel> mod_ArtistModel = new List<Modular_ArtistModel>();
foreach (var row in Modular_ArtistModel)
{
mod_ArtistModel.Add(new Modular_ArtistModel
{
Artist_Name = row.Artist_Name
});
}
ArtistModel.Artist = mod_ArtistModel;
My View: (This is the first thing in the view and the program chokes on the following assignment)
@model dynamic
@{
string artist_Name = Model.Artist.Artist_Name;
}
When the cursor reaches the above assignment in the View layer, it throws the following exception:
'Model.Artist.Artist_Name' threw an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'
Data: {System.Collections.ListDictionaryInternal}
HResult: -2146233088
HelpLink: null
InnerException: null
Message: "'System.Collections.Generic.List<....Models.Modular_ArtistModel>' does not contain a definition for 'Artist_Name'"
Source: "Anonymously Hosted DynamicMethods Assembly"
StackTrace: " at CallSite.Target(Closure , CallSite , Object )\r\n at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)"
TargetSite: {System.Object CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Object)}
Does anyone know what I need to do to fix this? Not sure if it's a quick fix or a more extensive redesign.
Upvotes: 0
Views: 1586
Reputation: 886
I think that using dynamic object is not a good idea,by default views are strongly typed and without Model there is no way to create attribute based model validation ...
By referring to the official documentation and others resources you can use extension method to convert your object into an ExpandoObject and your function should be works :
Extension method :
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in anonymousDictionary)
expando.Add(item);
return (ExpandoObject)expando;
}
In the return of your controller method try to add:
return ( "yourView", ArtistModel.ToExpando() );
Explanation:
The reason for this is that the anonymous type being passed in the controller in internal, so it can only be accessed from within the assembly in which it’s declared. Since views get compiled separately, the dynamic binder complains that it can’t go over that assembly boundary.
But if you think about it, this restriction from the dynamic binder is actually quite artificial, because if you use private reflection, nothing is stopping you from accessing those internal members (yes, it even work in Medium trust). So the default dynamic binder is going out of its way to enforce C# compilation rules (where you can’t access internal members), instead of letting you do what the CLR runtime allows.
For more details please read this answer:
Dynamic Anonymous type in Razor causes RuntimeBinderException
and this article:
Upvotes: 1
Reputation: 1044
You send list artist but try to get one artist you should change this
string artist_Name = Model.Artist.Artist_Name;
To
string artist_Name= Model.Artist.FirstOrDefault().Artist_Name;
Or
Change
@model dynamic
To
@model ExpendoObject
Upvotes: 1