I am trying to use Razor Engine as a standalone template engine. This is working great except that I don't know which are the properties that will be passed to Razor therefore I can't declare an object listing my vars. I currently do this using a dictionary, allowing me to write things like that :
#Model.Vars["MyProperty"]
But I would like to be able to simply write :
#MyProperty
Is there some way to do this ?
Thanks in advance for your answers.
You can use some razor syntax to provide intellisense for your view:
#inherits MyNamespace.MoreNamespace.MyCustomRazorModel<MyModelType>
As long as your MyCustomRazorModel implements the required Write, WriteLiteral etc methods, then everything should work correctly, and you could use the following in your views:
#MyProperty
Assuming you had a definition like so:
public class MyCustomRazorModel<T>
{
public string MyProperty { get; set; }
}
I mention that your backing Razor implementation should probably be Generic simply so that you can re-use it with whatever model you want for templating. That is also how the Razor engine works in ASP.NET, by providing a Generic model that exposes the model in the #Model property.
EDIT
For example, take a look at the following class to see how the framework guys did it:
http://msdn.microsoft.com/en-us/library/gg402107(v=vs.108).aspx
This is the backing view for the RazorEngine in ASP.NET. For standalone implementations, you would make a backing type for the view to inherit like this.
Related
I have raised similar question before, have got no answers.
How can I create a generic mvc4 view that can display list of or a single model that is passed to it. model can be either Person or Organization or Party whatever that is passed to it.
If you are looking for something like:
#model MyViewModel<T> where T : IViewModel
... then that is not supported by Razor.
You may be able to use something like this:
#model MyViewModel<IViewModel>
... that way you could define all types that could be passed as follows
public class Person : IViewModel { ... }
public class Organisation : IViewModel { ... }
public class Party : IViewModel { ... }
Please, DON'T DO THAT!!
You should make a view for each kind of object / list of objects.
However, yu can still reuse elements:
keep the common part (menu, header, footer...) on the site layout
make a view for each kind of object
make a view for each kind of list. in this vie you can use the object's view as a partial view and render it as many times as object are on the list.
Another possibility is to make templates for "Display For" for each kind of object. You can define a view for each kind of object, and store it in an special folder. When you use Html.Display or Html.DisplayForin your templates, the system will choose and render the right template depending on the type of the object to display. (You could also make named templates, and select them by name). For an introduction on this technique, look at this excellent posts by Brad Wilson.
But I insist, please, don't make a "generic view", as this will add extra complexity (check if it's a list or a simple object, get the type of the object, choose how to display it and display it). You can make very simple views by reusing the elements as explained, and letting the controllers decide which view to show for each object or list of object. Or use templates. In this way your system will be easier to maintain and less prone to errors because of added complexity (you don't need to change the same template all the time, but to add new templates, with very few code on them)
What I can't understand is why you want to have a simple view. What's the reason for it?
#model MyViewModel<IViewModel>
If you define a model like this then this error occurs:
Server Error in '/' Application.
The model item passed into the dictionary is of type MyViewModel\'1[Person], but this dictionary requires a model item of type MyViewModel'1[IViewModel].
To achieve a Generic View Use below code. dynamic is an inbuilt keyword that accepts any model.It worked fine for me
#model dynamic
or
#model IEnumerable<dynamic>
I'm hoping you guys can answer me a question?
I've only just started out using ASP.NET MVC3 have come unstuck at a certain point. I've been learning this stuff from books and I'm slightly unsure on a few things.
Can a VIEW, only have one #Model reference?
At the moment I have a VIEW setup with a HTTP-POST on a ViewResult, that validates the data in the View, entered by the user and then "on post", passes this info to a method that writes it back to a database(ADO.NET - Access). Now I need to change my VIEW, so that I can replace a couple of my text boxes for Dropdownlistfor controls. The Data to populate these controls will need to be passed in from the Database.
Would I be correct in saying that this data needs to be passed in the HTTP-GET Viewresult of the page, and if so, can i reference more than one #Model in this same View (*.cshtml).
I have a class that takes in the user response, and this is referenced in the View. But will i need to create a new class for the dropdownlist data and reference that too. So that in the background I populate the data into a SelectListItem, pass it to the View and then populate each drop down control within the view?
I'm sorry if this is poorly written, very hard to explain, I find learning from books hard and I'm pretty stuck now. Any help would be appreciated. Just to give me an understanding of how this all wraps around. I'm comfortable with the C# syntax, but very unsure of MVC3!
There are two ways you can handle this.
Use a View Model.
In this scenario you have a class that contains your data model as well as other things required by the view, so something like this:
public class ViewModel
{
public MyDomainModel Model { get; set; }
public IEnumerable<SelectListItem> SelectListItems { get; set; }
}
Use ViewBag.
In this case you add everything extra into the ViewBag dictionary. So in the controller, you'd have stuff like this:
ViewBag.SelectListItems = new SelectListItem[] { ... };
Then you can reference in the view itself
#Html.DropDownList("myselectlist", ViewBag.SelectListItems)
I think that this will help you pluralsight mvc3 intro. It sure helped me
...before everything, I'm doing this out of curiosity only. Nothing real-world application here, but just for knowledge and tinkering about...
ASP.NET Views have properties like Model and ViewData and even has methods as well.
You can even use #Using just like a regular class.cs file.
I know that it is of type WebPageView<TModel>
My main question is: is it a class?
It should be because it's a type, but..
I should be able to also do this then (Razor engine):
#{
public class Person
{
//etc...
}
var p = new Person();
}
<span>#p.Name</span>
However I can't.. why?
note: currently a C#, ASP.net beginner.
Sure, you need to use the functions keyword in order to drop down to exposing class-level things like fields, properties, methods, and inner types:
#functions {
public class Person
{
public string Name { get; set; }
}
}
#{
var p = new Person();
}
<span>#p.Name</span>
This will work just fine.
That being said, keep in mind that the only purpose of these inner classes is if you need to define a type only for use within a view. Myself, I've never found a need to do this for classes. However, I have taken advantage of this technique to add new methods that are not syntactically possible with helper methods.
You can't do it because Razor markup is compiled into a sequence of statements inside a method within the generated class derived from WebViewPage or WebViewPage<TModel>
The more important question though, is why would you want to do this? Instead prefer to keep Razor free of this kind of logic - it's job should be to produce layout, not do any kind of business logic, or business data transformation. Do all the heavy lifting in your action method and deliver a Model that describes the data required to render the layout in a format that requires only simple Razor markup to process.
There are quite a few tutorials a round that describe how to approach MVC and Razor. I dug up this one that is brief but does a reasonable job of covering an end-to-end story that might help you get the idea. It does include using EF to get data as well which might be more that you were bargaining for - but it's worth a read to get the full picture of how a whole architecture hangs together: http://weblogs.asp.net/shijuvarghese/archive/2011/01/06/developing-web-apps-using-asp-net-mvc-3-razor-and-ef-code-first-part-1.aspx
Yes, Views are classes. They are compiled into a temporary assembly (so they don't have access to internal members of the main assembly, which is good to know when dealing with dynamic/anonymous types).
I think that Razor has a rule that disallows declaring inner classes, haven't checked.
I'm learning asp.net mvc and found something interesting:
It seems that I can't explicitly define a View's Model from within the View with error message saying that it has no setter.
#{ this.Model = "Hello" } //error
Then I looked at the source code in WebViewPage.cs and a View's Model property is actually like this:
public object Model {
get {
return ViewData.Model;
}
}
Thus the error.
But it's interesting how I can do this: #{ ViewData.Model = "hello"; } and actually be able to use the #model statement, resulting to "hello"
I think I'm looking too much into it, but why is this so?
beginner at C# and ASP.NET
The rule is Separation of Concern...In MVC, a Controller supplies a Model to a View and it will always be the controller that can set/assign a Model to a view....which the Views can use...this is by design...play by rules is what I would say...and If you are learning MVC its great and I would strongly recommend you to read
Stevens Sandersons MVC book
Things like ModelBinders and what not sometimes need to change the model in context, so they need the setter. Another reason is to facilitate unit testing.
However, you would seldom need to do this yourself in views, so abuse it at your own risk.
It is the "pit of success" theory of API design. You aren't supposed to alter the Model property in your view, so they make it harder to do so. But since there may be cases where you have no choice, they don't make it impossible.
There is no magic here. In the first case (as you pointed out), there is not property setter for a Model property. So, you cannot assign anything. And that makes sense -- why do you need to re-assign model from within view?
In the second case you hack/bypass that constraint using ViewData.Model directly. Since it's of Object type, you can assign anything.
(BTW, I assume in the first code snippet you assign "Hello", not 'Hello')
I realize that the best practice is to use strongly typed Views and pass in all needed data in a ViewModel, but I am curious if there are situations where it is actually considered "best practice" to pass data in the ViewBag/ViewData.
In what scenarios is the ViewBag/ViewData preferred for passing data to a view?
update
It's great to hear the various uses everyone has come up with for ViewBag/ViewData. We may never arrive at a "best practice" but it will be great to see the different solutions people have come up with that rely on the ViewBag/ViewData.
I use them rarely, for bits of information that are totally unrelated to the model or view model that I'm passing to the view, again, most of the times I use a view model
I prefer to use some DTO instead of using viewbag. Using DTO make you strong type your viewdata.
Hope this helps.
I typically will use a strongly typed view for displaying any content but will often set ViewBag.Member to the currently logged in member so that it can be used in the main Layout in addition to the specific view.
I have an attribute called PopulateMemberContext which populates ViewBag.Member and I add that attribute to my base controller so that every view will always have the necessary data.
"Right" or "Wrong" I don't know - but it works wonderfully.
i can't say about best practice but i mostly use it when using Editor Templates. e.g if i want to display a dropdown list for editing certain field i make following editor template
<%:Html.DropDownList("GetIDHere", new SelectList((IEnumerable<someModel>)ViewData["xyz"]),"select Author")%>
Then you put UIHint attribute on BookID field of your model for instance
public class Book
{
public int BookID{get;set;}
[UIHint("mytemplate")]
public int AuthorID{get;set;}
}
in such cases, i assume, its particularly fine and clean to use ViewData. this is the way Telerik asp.net mvc projects have coded in their demo projects demo