0

I'm sending the following model to my view.

return View(new { url = returnUrl });

In the view, I'm don't want to specify any particular class for my object (since I wish to keep it flexible and elastic for now). So, the @Model is the apparently an object and as such, it's got no url property. Hence the error.

Additional information: 'object' does not contain a definition for 'url'

Now, I do know that the thing inside the object has url property. I have assigned it to it and I also see it when watching the variable as the exception's been thrown.

My question is how to access the field. Is my only option declaring a class and type the model using @model Something? I can't use as keyword to type it to var...

In "plain" C# we can do something like this.

var some = new {thing = "poof"};
string output = some.thing;

How do I do the equivalent of it in CSHTML file under Razor?

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • You should figure out what you want to display on there, and create a class with a `Url` property on it, and add as you need to expand. – krillgar Apr 05 '16 at 21:10
  • 1
    Why not just use `ViewBag`? – Paul Abbott Apr 05 '16 at 21:11
  • @krillgar I know how to solve that **if** I introduce a new class. However, the point of the question is to resolve it **without** it. Please view the added example from "plain" C#. I'm curious how to enforce that in CSHTML. Alternatively, I'd like to know **why** it isn't possible. – Konrad Viltersten Apr 05 '16 at 21:13
  • @PaulAbbott That's a feasible work-around (and I prefer that to declaring a custom class, at this point). Still, I'm curious why I can't use the usual C# syntax in the CSHTML page. Any ideas? – Konrad Viltersten Apr 05 '16 at 21:20
  • 1
    Your "plain c#' example is creating an anonymous type. Anonymous types cannot be used outside of the scope they are declared in (which is your case is the controller action). http://www.tutorialsteacher.com/csharp/csharp-anonymous-type – Paul Abbott Apr 05 '16 at 21:20

3 Answers3

3

Strongly-typed view models are the way to go. Create a type that suits the needs of the view and treat reusability/duplication as a secondary concern.

However, let me explain why your attempt did not work.

It is legal to pass an anonymous type--even between assemblies[1]--as long as it is cast to object. In fact, the MVC framework assemblies consume anonymous types in many helper methods. Those anonymous types are then evaluated using reflection (optimized by caching).

1: I believe there are some caveats to this, and it certainly isn't good practice in most cases.

A view is compiled into a class so that it can be executed. Part of the class's contract is the type of model it expects, as indicated by @model in your view markup.

This presents a problem with anonymous types, as you cannot indicate their type in your view and type object doesn't expose the properties you set when declaring the type. Thus, you end up with a view that only knows that its model is an object.

Again, use strongly-typed models, or the ViewBag if you truly only need one or two values.

However, to prove that the anonymous type can be passed to the view, look at this (horrible) example:

Controller

return View( new { property1 = "hello world"} );

View

@model object
@{
    var rvd = new RouteValueDictionary( Model );
}

@rvd["property1"]

We passed an anonymous type to the view as an object, and then read the object's properties using RouteValueDictionary.

Tim M.
  • 53,671
  • 14
  • 120
  • 163
  • 1. Truly a horrible example (I appreciate the fact that you actually present it to prove the case but won't be using it, of course). 2. How does that relate to the *dynamic* keyword (should it be avoided or can it be recommended - I've never had the need nor opportunity to apply it so it'd be interesting)? 3. Is *ViewBag* preferred before *ViewData* (I've seen both but people generally tend to suggest the former or both but never the latter alone)? – Konrad Viltersten Apr 05 '16 at 22:57
  • 1
    2) `dynamic` is designed for cases where you cannot easily know the type information at compile time (or just don't want to specify type information). It's different than an anonymous type, which *is* strongly-typed at compile time, just not in an easily-consumable way. 3) See http://stackoverflow.com/questions/4705426/whats-the-difference-between-viewdata-and-viewbag. The fact that `ViewBag` uses `dynamic` shows that it is not completely discouraged. Personally I've gotten used to creating many, purpose-specific view models (which was a paradigm shift for me). – Tim M. Apr 05 '16 at 23:06
2

You can use ViewData and ViewBag to send objects to the view page, in your case you can write in the controller something like this:

ViewData["url"] = url ; //Or whatever 
return View();

Now in the view you can simply use your object example:<div>@ViewData["url"]</div>

But mainly in MVC it is more recommended to use strongly typed View Models

hdrdiab
  • 343
  • 1
  • 11
1

You may want to look into using the dynamic type in C#. See https://msdn.microsoft.com/en-us/library/dd264736.aspx for details.

While the standard would be to use a strongly-typed view model, there are some scenarios where you might want to use dynamic as your model type (or as a property of your strongly-typed view model), such as in a CMS where the properties are built dynamically by the CMS Provider.

Example view:

@model dynamic
<p>
    Url:  @Model.url
</p>
Keith
  • 5,311
  • 3
  • 34
  • 50