ASP.NET MVC ViewPage rendered in a ViewPage - c#

I'm wondering if it is possible to render a ViewPage inside of a ViewPage.
Normally, you'd have this:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<my_object>"%>
and then in the page you can render a user control:
<%Html.RenderPartial("~/Views/Shared/mycontrol.ascx", this.ViewData);%>
However I'd like to render a ViewPage in a ViewPage. The reason? I'm working on a very large project with 10+ developers and a lot of code already written. A large piece is already written which dynamically renders the UI however there are 15+ methods which pass around a ViewPage.
In other words, I'm calling this in the ViewPage:
<%this.RenderUI();
And the method stub is this:
public static void RenderUI(this ViewPage viewPage)
So in order to reuse the most code, I'd like to pull the call to this.RenderUI() into it's own ViewPage but then include that on some ViewPages. It's a hairy situation and it sounds unnecessary, but there's a lot of code rework that would need to be done otherwise. Does anyone know if this can be achieved?

Render your subview in the main view using RenderAction() instead of RenderPartial(). This allows you to keep your controller and view for each subview, and "inject" the output of each controller/subview combination into any main view, in a location of your choosing within the main view.
This arrangement should ease some of the complexity of managing each of the views and subviews. It is an approach reminiscent of the "web parts" in traditional ASP.NET or SharePoint. It is a more modular approach that provides for better reusability.

Related

ASP.Net MVC Generate DNS Prefetch Tags

Is there a way to find all the src="" urls when rendering a ASP.net MVC page in the view to then generate DNS prefetch tags on the fly?
https://www.chromium.org/developers/design-documents/dns-prefetching
If I understood correctly I can tell you the following:
Option #1: (Not a pretty solution but would work.)
NOTE: for this try to use simple Javascript and not rely on JQuery or other (since then you still need to "load" the .JS file for that and that is ruining the point of your question.
Process your src/href or some other predefined property tag with some kind of "OwnLogic" to define the "base target",
but in a way that the browser would not be able to initiate the request to obtain that image or other file.
Example:
<img url="" class="DNS_BaseTarget" DNS_BaseTarget="smiley.gif||myCDNPointerInfo" alt="">
Then, with javascript, get a list of all elements that uses the class DNS_BaseTarget and then read the property value and update the "src" tag.
At the same time you can inject by javascript inject all the '<link rel="dns-prefetch" href="https://cdn.yourTargetDomain.com">' that you will use based on the information you just processed.
I did not tested this concept, so "lag" or some sort of delay in the client might be expected (but maybe not noticeble by the user).
Option #2:
The View Result Execution Process (in MVC life cycle) tell us that the method 'Render()' is the last one to be executed.
With this being said, you can create your own custom override logic
Example: intercept view rendering to add HTML/JS on all partial views?
How to intercept view rendering to add HTML/JS on all partial views?
With this concept of trying to "process" the final html before sending it to the user, you could somehow "parse" the file.... try to get all the 'src/href' and then
inject all the '<link rel="dns-prefetch" href="https://cdn.yourTargetDomain.com">' that you will use.

Re-using another page section

I have created a web page that I use as a small dashboard to hold issue or no issue. It works great. The page uses an .aspx and .aspx.cs. I would like to be able to reuse the information on this page on other pages. My site already uses master pages and I have not been able to find an easy way to include this information.
How can I use an include from a page that has coding in the code behind easily?
Typically you use Web User Controls for this.
Web User Controls allow you to package up other controls into one that you can drop onto multiple pages. They are great for common UI items such as address entries, dashboards, etc. Basically anything that needs to be the same across multiple pages.
At the risk of seeming very obvious - do you mean usercontrols. These will allow you to reuse chunks of functionality across your site.
I guess this question falls into two categories: User Controls, and Code Reuse. Not sure which one you are after.
User Controls
If you are talking about the controls on your page you will want to create a common user control.
Code Reuse
You need to create a common class (whether it is static or not depends on how you intend to use it) and define functions within that class.
For instance, lets say you have a page that you want to print "Hello World!" on any aspx/.cs page.
You could do this
public static class MyClass
{
public string PrintHelloWorld()
{
return "Hello World!";
}
}
Then you call it from any of your pages like so:
MyClass.PrintHelloWorld();
Right click on the project > Add New Item...
Select User Control (.ascx)
Put your markup & code behind there.
Then you add that control in any other page (includding other controls [although I wouldn't recommend that])
It sounds like you may want to create an ascx User Control.
http://msdn.microsoft.com/en-us/library/ie/2x6sx01c.aspx

Is it bad practice for views to create partial(child) views?

I'm creating a little view framework. I'm not trying to stick to strict MVC adherence, but I am definitely trying to not get in the way of MVC practices.
Anyway, one of my questions is this: Is it bad for a view to create it's own child views?
For instance, in pseudo-ish C# code:
/*BlogEntryView*/
<h1>my blog entry...</h1>
<div class="Comments">
{# //code
foreach(var comment in Comments){
Write(new CommentView(comment));
}
#}
</div>
Is this bad practice for an MVC style? Would the proper thing to do be to provide a "placeholder" in BlogEntryView where the model populates it with CommentViews?
(also, please do not tag asp.net-mvc, this is similar, but in no way uses ASP.Net MVC technologies)
For comparison, the opposite of this, would be adding views with some placeholder in the model code:
/*BlogEntryView*/
<h1>my blog entry...</h1>
<div class="Comments">
{# SomePlaceholder #}
</div>
/*In the model code for BlogEntry*/
//v is a BlogEntryView
foreach(var comment in Comments){
v.PlaceHolder.Add(new CommentView(comment));
}
Both ASP.NET MVC and Ruby on Rails facilitate the approach I think your referring to through the use of partial views.
Using your example would typically result in a view that called a partial for comment record. In ASP.NET MVC C# this would look like the following: -
<h1>my blog entry...</h1>
<div class="Comments">
<% foreach (var comment in Model.Comments) { %>
<% Html.RenderPartial("Comment", comment); %>
<% } %>
</div>
Following current MVC philosophies and design principals this sort of decomposition into small "atomic" portions of view code is actively encouraged in many circles. However, there is always a balance to be sought between this decomposition and the maintainability.
No. This is actually how the ASP.NET MVC Templates features work in MVC. However, a potential pitfall in ASP.NET MVC is a slight performance cost to searching the file structure for the views. This can be avoided by specifying the full view path explicitly.
http://vishalswami.blogspot.com/2007/11/design-patterns-in-mvc_30.html discusses MVC architecture. The Gang of Four also advises that one of MVC's greatest advantages is that it facilitates a Composite UI (which is what you are describing).
In traditional MVC, there's one view to each controller and model, which is call the "MVC Triad". I think what you what is the view's template to be able to embed other templates for re-usability (think partials).
One piece of tech that gets this correct with mustache. It uses a view model, coupled with a template. The template can request other partials to reuse chunks of other templates.
The problem with many web MVC frameworks is that they treat the view as a template, which is the wrong way to view it (no pun intended). Once you have a class representing the view, this all becomes much easier.
Personally, I think the specific example you posted is bad form, because a template should never have that sort of access to objects and instantiating them like that. Templates should get their data from outside sources (the view model), which cane make those instantiations cleaner.
Is it bad for a view to create it's own child views? My answer is "NO". In face creating partial views gives you more power to change the UI contents in a modular way.
There are always multiple ways of achieving results. I personally think ascx files are a good clean way of creating reusable modules which can inherit from customized user controls. Its modularized approach keeps things very organized for me.
Just my 2 cents...
I understand that there are communities both pro and against views rendering child views.
Personally I consider the use of RenderPartial to still be a view concern. I don't have an issue with view depending on another view, providing it assumes the same model offered by the controller action's model.
RenderAction on the other hand is less of a view concern because it winds up invoking a controller action, which then renders a view. It's an entire request lifecycle unto itself. However, it has a lot of benefits, particularly for cross-cutting concerns such as site navigation, user account state, ads, or other page features that are completely independent of the page's primary goal.

Is there a way to prevent a plain text section of an MVC view from rendering?

I have a web application I'm working on, and I'd like to avoid the clutter of if/elseif/else in the view, and of having way too many separate ascx files just for conditional inclusion in a view.
What I want to do is create some sort of simple class that works like so (an example will demonstrate what I'd like to achieve)
<% using(RequiresAccessTo.Feature(Features.FancyStuff)) { %>
Special content for users
<% } %>
If the user does not have access to the feature, the class would render a sign up link instead. I know I could simply use if/else, but the content of the else block could be one of 2-3 different standard responses depending on access level, and this mechanism would be used in countless places around the website.
If there a way to simply prevent Special content for users from rendering altogether, it'll mean I can make the templates around the website really easy to maintain.
Another option you might try would be to create a custom server control. Properties on the control could include the feature set you'd want to check permission for. If that permission wasn't met, the control would render the sign up link appropriate for that access level or permission. Your view would end up looking something like:
<controls:SignUpWrapper runat="server" id="signup" access="FancyStuff">
<div>
Approved user contents.
</div>
</controls:SignUpWrapper>
In your control, you would first check permission then render either the appropriate link or the provided HTML. The trickiest bit here might be getting the routing information to your server control code. Not something I've tried. Worst case scenario I imagine you should be able to pass the necessary information or even the entire sign up link through properties. No wait, worse would be bypassing routing altogether and forcing the URL in through a configuration value, erm... yeah. Either way it's a bit wordier than your desired example, but not far off.
I suppose some folk might see even the server control idea as a bit wonky. But as long as you stay away from view state, post back behavior and maybe a few other classic ASP.NET features, there's nothing preventing using server controls. We all use masters and content containers already. Sorry to preach if you're already in the choir. =)
For the time being, this is stretching my imagination and maybe even common sense a bit depending on the difficulty of generating that link. I'll check back if I think of anything else.
I can think of one other decent option to keeping your if/else logic in a partial view.
You could create an HtmlHelper extension method. HtmlHelper is the object used when calling things like Html.ActionLink in a view. You can write your own method that produces whatever HTML you want. The conditionals all take place in the extension method and your view code is reduced to:
<%= Html.MyControl(param1, param2) %>
The rule of thumb I follow when deciding when to create an HtmlHelper extension method and when to create a partial view is generally how much HTML is going to be generated. If I end up with more than a few lines of rendered HTML, a partial control is generally your best bet as it is generally easier to understand and maintain the HTML.
If you're worried about organizing numerous partial views, you can create subfolders under your Shared view directory. The views can then be referenced like this:
<% Html.RenderPartial("Subfolder/PartialView") %>
I just thought of an alternative solution:
<% if(!BlockContentAndRenderPlaceHolder(Feature.Whatever)) { %>
whatever
<% } %>
I know it looks a bit obtuse, but if you saw the content on these pages, you'd understand.

Passing ViewData to ViewPage in ASP.NET MVC

I'm trying to build a custom control in ASP.NET MVC. The thing that I want to avoid is mixing the view (html) and the code (C#) in these controls.
After hours of googling and struggling with this problem I've finally thought of creating helper methods that use the ASP view Engine thought the ViewPage class.
I'm able to create an instance of the class and even load an ascx template using LoadControl and LoadTemplate methods but the problem is that when I pass a ViewData object to an instance of ViewPage class I cannot see the ViewData in the ViewPage and I'm getting this error:
The ViewUserControl '~/Components/Controls/EditableLabel/Views/EditableLabel.ascx' cannot find an IViewDataContainer. The ViewUserControl must be inside a ViewPage, ViewMasterPage, or another ViewUserControl.
Generally the final effect that I want to achieve is loading controls with some parameters, these parameters should be readable in the template (ascx).
example:
<% Html.EditableLabel(Writer, "memberName", "Name", "Antonio", "/identity/updateProperty", "memberName"); %>
Is there a way to pass the ViewData to the ViewPage instance that I create?
Is there a smarter way to create custom controls/widgets in ASP.NET MVC?
Thanks in advance
You can pass VD to the VP from controller via "return View(...)" or via "ViewData[name] = value".
It's better to use ascx controls which are inherited from ViewUserControl in order to create a custom control. In this way you easily can pass data to it:
<% Html.RenderPartial("FooControl", new FooViewData(){ Name="aa", Type="awesome", Id = 2}); %>
<% Html.RenderPartial("FooControl", new FooViewData(){ Name="aa", Type="awesome", Id = 2}, ViewData); %>
And all necessary parameters you can define in your FooViewData class.
If you really want to write an extension to the HtmlHelper which will load some ascx controls you should look at a Repeater class in MvcFutures (sources of MVC are here). But I'm sure that in a common case you'll not need this.
I am tracking with zihotki on this one. With #2 I will add a caveat, however. In the default implementation, which uses neutered ASPX and ASCX as views, creating MVC controls (use the template to ensure your dog is neutered) is the best option.
Now for the caveat. ASPX and ASCX do not have to be the views. If you look at Phil Haack's blog, you will see some other view engines mentioned, like the Spark View Engine (ASP.NET MVC Northwind Demo Using the Spark View Engine). In fact, Phil has set up a sample of using alternative view engines in this entry: Rendering A Single View Using Multiple ViewEngines.
I am not suggesting that you move to other view engines, only that there is an option, if you find one that better fits your problem domain. Sometimes it is better to stick with the out of the box implementation. In this case, keep things simple with ASCX controls.
By the way, if you are seriously getting into MVC as your UI story, you should look at the codeplex projects for MVC. The most important here is probably MVC.Contrib, but there are a few other gems in the list.

Categories