16

On an ASP.NET Core 2.0 application I need to render a partial view and pass a few parameters:

@Html.Partial("Form", new { File = "file.pdf" })

On the partial view I tried to access it using:

@Model.File

And I get the error:

RuntimeBinderException: 'object' does not contain a definition for 'File'

If I simply use on my partial:

@Model

I get the following printed on the page:

{ File = file.pdf } 

So there the model is being passed and there is a property File in it.

So what am I missing?

Miguel Moura
  • 36,732
  • 85
  • 259
  • 481
  • Should be the same situation that here: https://stackoverflow.com/questions/223713/can-i-pass-an-anonymous-type-to-my-asp-net-mvc-view – DaniCE Sep 07 '17 at 16:05

4 Answers4

28

You are passing untyped (anonymous type) data to partial view. You cannot use @Model.File. Instead, you will need to use ViewData's Eval method to retrieve the value.

@ViewData.Eval("File")

Traditional approach is to create a strongly typed ViewModel class, and pass it to the partial view. Then you can access it as @Model.File.

public class SampleViewModel
{
    public string File { get; set; }
}

@Html.Partial("Form", new SampleViewModel { File = "file.pdf" })

Inside Partial View,

@model SampleViewModel

<h1>@Model.File</h1>
Win
  • 61,100
  • 13
  • 102
  • 181
  • Yes, I am going for the classic Model approach although not sure why the dynamic approach does not work without the ViewData.Eval – Miguel Moura Sep 07 '17 at 16:35
  • Strongly typed model is stored inside ViewData's Model. In contrast, untyped data is stored inside ViewData's Dictionary. It is why we need to use `ViewData.Eval` when retrieving data from ViewData's Dictionary. – Win Sep 07 '17 at 16:40
6

You should have dynamic as the model of your partial view, this way, you can pass everything - like your anonymous object - and it will just work. Add:

@model dynamic

To the Form.cshtml file.

Ricardo Peres
  • 13,724
  • 5
  • 57
  • 74
  • I tried that and I still get the same error: RuntimeBinderException: 'object' does not contain a definition for 'File' – Miguel Moura Sep 07 '17 at 16:16
  • 1
    Then you're doing something wrong, as this is the standard way to do it. If you only need to pass the File property, why not pass that directly, e.g., @Html.Partial("Form", (object)"File.pdf") and access it directly in Model? – Ricardo Peres Sep 07 '17 at 16:18
  • dynamic is used in a slightly different way. The object passed in is still of type object. Dynamic simply means that it would evaluate the type of the object in run-time. In run-time, the object will still be taken as type object. – Neville Nazerane Sep 07 '17 at 23:03
  • That's not true. If you pass an anonymous object, it will be an anonymous object, and by wrapping it in a dynamic, you will be able to access its properties. The views created by the VS templates use dynamic just for that purpose. – Ricardo Peres Sep 07 '17 at 23:31
1

When you do new { File = "file.pdf" }, you are passing an object that contains an attribute file. Since this is of type object, you can't access any of its variables in c# directly. There some ugly codes to access a fields from an object such as the one that can be found here: C# .NET CORE how to get the value of a custom attribute?

However in this case the most recommended way (for safety) is the create a class and pass an object of that class.

So if you create the following class:

public class MyFileInfo{
    public string File { get; set }
}

Then you can create your object by passing:

@Html.Partial("Form", new MyFileInfo{ File = "file.pdf" })

In your partial view, at the beginning, define your model class

@model MyFileInfo

Then in the same file you will now be able to access

@Model.File
Neville Nazerane
  • 6,622
  • 3
  • 46
  • 79
0

For the sake of completeness: you can pass arbitrary variable via a ViewDictionary

@Html.Partial("_Partial", model, new ViewDataDictionary(ViewData) { { "MyVarName", someValue } })

And then access it like this in the partial:

ViewData["MyVarName"]

Another option, you can simply set a ViewData var before calling the partial, and it will be passed on to it

@{
    ViewData["MyVarName"] = "hello";
}
@Html.Partial("_Partial", model)

However, strongly typed models are much easier to work with.

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149