Looking for a way to implement a polymorphic view in ASP.NET Core - asp.net

I'm working on an ASP.NET MVC Core web app that would have a lot of similar views. Each view is just a simple form that has a list of label&control pairs.
An "Object" editor template has been built in order to generate the content of such views automatically based on view model properties.
Each view would basically have just one line of code:
#Html.EditorFor(m => m)
Each view model is derived from a base class.
Is there a way to get rid of duplicate views and controller actions?
Ideally, I'd like to have just one view where the model is the base model class and one controller action that would receive that base model.

Himanshu's comment steered me to use Partials for the child classes and use the base class as the model for the main views. You may be able to just use reflection/property annotation to populate the views according to the given Model, though I have not tried it.
What I have tried successfully is using a base class that is not abstract and thus will not duplicate properties in the child classes, then using generics like...
List<T> GetChildClasses<T>() where T : BaseClass;
which is called by the controller method and supplies the View Model, and then displaying like this...
#model MyApp.Models.BaseClass
<div class="show_base_class_properties_here">
</div>
#if(Model is ChildClass)
{
#await Html.PartialAsync("_ChildPartial", Model);
}
<div class="whatever_comes_next">
</div>
I suspect there is a better way but this works. Apparently there can only be one #model in a view file.

Related

How to inject a child component into a razor generic component like react.js

I would like to know if it is possible to create components (Razor / Asp.NET) like the react style. I'll illustrate:
<GenericDadContainer>
<ChildComponentDinamic />
</GenericDadContainer>
I want to do this so that my parent containers have dynamicity. They will serve only as containers, and your children need to be dynamic regardless of their models.
If possible I would also like to know if in this context it would be possible to pass parameters to the same besides the child itself.
I understand little of Razor, and I didn't find anything from the internet on a way to reuse the layout better.
Not exactly the same style, but the same idea: in Razor, you can use the so-called "partial views" to divide your page up into "components", and yes, you can pass data to a partial view.
Here is a mini-example:
<div class="container">
#Html.Partial("view-name-here", model)
</div>
The model variable could be any object you choose.
Read up on partial views in ASP.NET/MVC, for example here.

Should I use PartialViewResult or separate method in another contoller?

I am using ASP MVC 4 framework. For example, I have 2 controllers: MainPanelController and CartController.
MainPanel controller defines methods and views for showing base main panel functions. Cart controller for example defines standard cart methods: RemoveFromCart, ClearCart, AddItemToCart etc.
Where should I define ShowCartItems method, if I want to display cart items list in main panel index page? I have two choises:
in CartController as PartialViewResult and render it in Index View of
MainPanel controller
completely define it in MainPanelController
I think showing cart items is CartController's task. Or maybe should I define ShowCartItems view in MainPanelController?
Maybe what your are looking for is RenderAction method, which provides you a way to output an action from other controller:
#{
Html.RenderAction("ShowCartItems","CartController");
}

ASP.Net MVC 3 Razor: how to create and pass info to a dynamic layout

In other languages (PHP/Python), I am used to creating a class which represents a given HTML page layout. These classes can have an unlimited number of attributes and dynamic features, such as Navigation (multi level), error messages, info messages, footer text, etc... Most of these items have defaults, but may be overridden on a per-page level. For example:
Layout = MainPage()
Layout.Title = "Google Image Search"
Layout.Nav1.Add("Google", "http://www.google.com", Selected=True)
Layout.Nav1.Add("Yahoo", "http://www.yahoo.com")
Layout.Nav1.Add("Bing", "http://www.bing.com")
Layout.Nav2.Add("Google Image Search", "http://......", Selected=True)
Layout.Nav2.Add("Google Shopping Search", "http://......")
Layout.Nav2.Add("Google Video Search", "http://......")
Layout.Nav2.Add("Google Web Search", "http://......")
or, handling errors:
try:
# do something
except ValidationError as e:
Layout.Error.Add(e)
or a php example:
$Layout->Info[] = "Your changes have been saved!";
My question is: how do I implement similar functionality into ASP.Net MVC 3 Razor (VB)?
So far, I have been able to see how you can use ViewData to pass various bits of data to a view. Also, I have been working with strongly typed views.
Frankly, I'm not sure who's job it is to have this logic, the controller or the view (or is there a model that should be in there somewhere).
Here is a summary of what I am shooting for:
A single place to initialize the default values for the layout (like the first layer of navigation, etc...)
Strongly typed attributes, such as Public Readonly Property Nav1 as List(of NavElement)
And a single place to render these layout elements (I assume _Layout.vbhtml)
Please forgive the here-and-there of this post... I'm trying to figure out the "right way" it's done on a platform that is both new (Razor) and new to me (ASP.Net MVC).
General advise very welcome!
I usually have a controller property (MainMenu) which I add to the ViewData dictionary in Controller.OnResultExecuting in my BaseController. Note that it's named ViewBag in mvc3 and it's a dynamic object.
Another approach would be to use sections in razor. Look at this question: ContentPlaceHolder in Razor?
I lean toward the fat models, skinny controllers perspective. If it were me I would create a base class for your page models that provides support for your common data. You can then inherit from that for individual page models and store your page specific data there.
The MVC implementations that have worked well for me usually have relatively clean Controllers. The controller is just the connector, getting the data from the request into the model and then handing off the prepared model to the correct view.
As for how you store collections of things in .Net - look at the classes that implement IEnumerable interface. Specifically focus on the Dictionary and the List classes. Dictionary objects store name/value pairs and can include nested dictionaries. You can work with them almost exactly like you can use multi-dimensional arrays in PHP. List objects are just indexed collections of items of the same type. You can work with them just like a simple array in PHP.
One side note - if you're just getting started in .Net and coming from a PHP/Python background, it might be better if you can switch to C#. You'll find the syntax much more comfortable and the tutorials/examples more plentiful (especially in the asp.net mvc world)
It's not difficult! :-)
If layout model is of the same type of the content page, the association is automatic! Here is the simplest example...
This is a test layout:
#model string
<style>
.test
{
background:#Model;
}
</style>
<div class="test">
Ciao
</div>
#RenderBody()
And this is a test content page
#{
Layout = "~/Views/Shared/_Test.cshtml";
}
#model string
...blah blah...
Just call the View with something like:
...
return View("Name", (object)"Green");
and it's done! The model is the same in the content page and in the layout page!
Andrea
P.S.: Believe me! This is useful!!! Maybe it's not the best for purists, but it's really useful!!! :-)

What's the base class of a Razor View in ASP.NET MVC3

I'm trying to have all my views inherit from a custom class so that I can add certain behaviour and values to all pages, but I'm having some issues. I tried subclassing System.Web.Mvc.WebViewPage but I'm forced to implement an Execute procedure that I don't know what it should do. Also, if I try to access the Context variable, I get a null reference (really weird). This leads me to think that I may have the wrong base class....
Any thoughts?
Diego, System.Web.Mvc.WebViewPage is the right base type (and you should have another class inheriting from System.Web.Mvc.WebViewPage<TModel> if you want strongly-typed views). You should mark your own class as abstract so that you are not forced to implement the Execute method.
Update: To configure all your views to use your custom base class, look into the ~\Views\Web.config file. Inside of it there's a Razor-specific section where you can use the pageBaseType attribute to configure your custom type.
As far as the Context property is concerned, it should be fully initialized once the view is executing. However, it might not be available if you try to access it too early (for example, from your classes constructor). When are you trying to access it?
The Execute method is something that is provided by the Razor compiler when your view is compiled. For example, given the following view file
Hello #Name!
The Razor compiler will behind the scenes generate the following class (this is a simplification, so the details might be off, but it should convey the point)
public class _Some_Generated_Class_Name_ : System.Web.Mvc.WebViewPage {
public void Execute() {
Write("Hello ");
Write(Name);
Write("!");
}
}
Then the framework calls the Execute method on your view class and your view gets executed.

MVC - How best to organize commonly used drop-down lists in many views

I am trying to understand how best to organize some common Dropdown lists used in several views (some are cascading)
Is it best to create
a single \Models\CommonQueries
then create a webservice for each dropdown used in cascading situation
then have a single controller that contains actions for each dropdowns
This way I can follow DRY principle and not repeat the dropdown logics since they are used in various views.
Much Thanks and Regards for reading my question and taking the your time.
+ab
When you say your dropdowns are used in several views, do you still consider these dropdowns as part of the view that is rendering them? If so, I think using a custom HTML helper or a partial view (ascx) is appropriate. Then, like you suggest, you can populate the data for the dropdowns using a common service from your domain layer. I think that is a very reasonable approach.
However, if you feel the dropdowns are somewhat external/unrelated to the view, then you might find that using Html.RenderAction() gives you a much cleaner result. Using Html.RenderAction(), you can output the result of an Action method directly into any other view. Therefore, you can create 1 controller with the necessary Action method(s) to populate those dropdowns. For example, let say you have a view with roughly something like:
<div>
<div id="coreView1">
<!-- some view code here -->
</div>
</div>
<div id="commonDropdowns">
<% Html.RenderAction("Create", "Dropdown"); %>
</div>
where Create is the name of your method in the DropdownController.
For example:
public class DropdownController : Controller
{
public ViewResult Create()
{
// do stuff here to create the ViewResult of the common Dropdowns
}
}
Note: Some people dislike this approach as it doesn't fit the typical MVC seperation of concerns. However, it can be a really great fit for some cases.
Hope one of these approaches can help.

Resources