create generic mvc view in mvc4 - c#

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>

Related

How to handle MVC DisplayTemplates for two classes with the same name (different namespaces)

You can only have one View per class name in the DisplayTemplates folder as the class name is used as the name of the view.cshtml file.
However, you can have two classes in a solution with the same name if they appear in different namespaces:
MyNamespace.Class1
MyOtherNamespace.Class1
Both try to use the DisplayTemplate defined by view:
Class1.cshtml
However in the view file you must declare the model - for example:
#model MyNamespace.Class1
This means that if you have a DisplayFor which takes a MyOtherNamespace.Class1 you get a runtime error due to a type mismatch.
If you knew in advance the places where this was going to happen you could use the UIHint to force the DisplayFor to use an alternative template (or you could use a named template directly in the view). But if you don't know in advance (you have all these objects in an enumeration of some kind and therefore can't write specific code to handle edge cases like this without a lot of unwieldy reflection - is there any way to have DisplayTemplates for these classes?
I haven't tried something like this before, but it should work. You can have the view accept a generic model type like object, and then attempt to cast it to the appropriate type:
#model object
#if (Model is MyNamespace.Class1)
{
var class1 = Model as MyNamespace.Class1;
// view code for this type
}
#if (Model is MyOtherNamespace.Class1)
{
var class1 = Model as MyOtherNamespace.Class1;
// view code for this type
}
UPDATE
Looking again at this, I'm bothered by the branching being done in this template. That's unavoidable, but a slightly better solution might be something like:
#model object
#if (Model is MyNamespace.Class1)
{
Html.RenderPartial("MyNamespaceClass1", Model);
}
#if (Model is MyOtherNamespace.Class1)
{
Html.RenderPartial("MyOtherNamespaceClass1", Model);
}
Then, simply create those additional views. That way, your code is still neatly broken into specific views, which can have the appropriate model declaration. This view basically just becomes a proxy that routes to the right one.

Passing dynamic object to View

I decided to try avoid view models and pass dynamic data to views, here is the test code I wrote in my controller:
dynamic model = new ExpandoObject();
var user = unitOfWork.UserRepository.Get().First();
model.Title = "Dynamic test";
model.User = user;
return View(model);
And in View:
#Model.Title
#Model.User.UserName
I like this method more because I don't have to write ViewModel class for every controller action, and also don't have to change ViewModel every time I decide to pass a new property to View.
The only downside I see is lack of intellisense in Views, because they are not strongly typed any more, but that doesn't seem as a big problem.
My question is, is there any other downsides of using this approach instead of ViewModels, because I am just starting a new project in my company, and I don't want to regret later if I use this approach...
I believe that the main advantage of creating view models is readability and resuseability of the code.
If I go to your piece of controller which you pasted, technically I can understand it, but I don't know what the model is about from business perspective. Of course you can name it more descriptive, but I don't believe it resolve the issue.
Second thing is reuseability, so I can imagine a lot of situation when multiple views can use the same model or some part of models and in this case you need to copy & paste code which creates you dynamic model or create some helper function which do this for you.
Basically I believe that it will be very painful when those dynamic models need to be changed e.g you removed some property in controller, but you forgot to do the same in some of the views. You won't be informed by compilator that something is wrong.
Additionally without strongly typed view model I believe there is no way to create attribute based model validation (which is very common business case)

Dynamic Razor data source

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.

MVC3 Razor Help required

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

When is it "acceptable" to use ViewBag/ViewData in ASP.NET MVC?

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

Categories

Resources