I have developed a plugin system that makes it easy to plug in new logic to an application. Now I need to provide the ability to easily add UI widgets.
There are already some good responses on how to create a portal system (like iGoogle) with ASP.NET MVC, and I'm fine about the overall concept.
My question is really about how we make strongly typed widgets.
Essentially when we set up a widget we define the controller and action names that are used to render that widget. We can use one controller action for widgets that are not strongly typed (since we just return PartialView(widgetControlName) without a model)
For widgets that are strongly typed (for example to an IList) we would need to add a new controller action (since I believe it is not possible to use Generics with ActionResult e.g. ActionResult).
The important thing is that the widget developers should not change the main application controllers. So my two thoughts are this:
Create new controllers in a separate class library
Create one partial WidgetController in the main web project and then extend this in other projects (is this even possible?) - not possible as per #mfeingold
As far as the development of the widgets (user controls) go, we can just use post build events from our extension projects to copy these into the Views/Widgets directory.
Is this a good approach. I am interested to here how others have handled this scenario.
Thanks
Ben
P.S - in case it helps, an example of how we can render widgets - without using Javascript
<%foreach (var widget in Model) {%>
<%if (widget.IsStronglyTyped) {
Html.RenderAction(widget.Action, widget.Controller);
} else {
Html.RenderPartial(widget.ControlName);
}
%>
<%} %>
For me it seems that MvcContrib's portable areas fits for developing independent widgets perfectly.
Here is an example - OpenId authentication widget.
Next week You can even watch c4mvc presentation about it.
The answer to your second question is NO. all source code for partial classes should be in the same project.
Is it possible with the templating engine to create a template for your widget type, then just call <%: Html.EditorForModel(untypedWidgetModel) %> - in theory, your template for that type would then take over and render appropriate HTML.
Or have I misunderstood how templating can work?
Related
Which is the best way to create custom controls in a Big Mvc application? Partials views which means a partial view for each control ? HTML Helpers? another alternative?
please find below a sample of custom control that I have in the asp web application:
protected override void Render(HtmlTextWriter writer)
{
writer.WriteLine("<div class=\"btnContainer\">");
base.Render(writer);
writer.WriteLine("</div>");
writer.WriteLine("<div class=\"clr\"></div>");
}
Partials alone aren't really "controls". They need something to drive them. In MVC 5 and previous you can use child actions to create something very similar to an ASCX control. In MVC 6+ View Components are the way to go.
You can also use an HtmlHelper extension. Really, the chief determination of which you should use boils down to whether you need external data access. If you need to query a database, hit a Web API, etc., then use child actions / view components. If you're self contained (i.e. you just want to render a bit of HTML based on some existing value you already have, then you can go with an HtmlHelper extension. However, a child action / view component still works in this scenario, as well, meaning they're much more versatile overall.
We're building a business application using Microsoft ASP.NET MVC 3.
Some views are now becoming so complex that it seems reasonable to divide them into two or more separate views, with separate controllers and models. (Reuse is another reason for wanting to build separate views.)
Which method do you recommend for achieving such separation in ASP.NET MVC?
Partial Views seems like the obvious answer, but as I see it, partial views "out of the box" has little support for separate controllers.
The best solution we've found so far is this, using the
Html.RenderAction("<view initialization action method>")
method as explained here: http://www.primaryobjects.com/CMS/Article129.aspx
This post also mentions the RenderAction method: ASP .NET MVC correct UserControl architecture
Do you see any weaknesses with this approach?
Do you recommend any better, easier ways of achieving this?
Take a "Post Detail" view. A composite view that displays both "Post Summary" and "Post Comments".
Taking the partial approach, you'd end up with:
public class PostDetailModel
{
PostSummaryModel Summary { get;set; }
PostCommentsModel Comments { get;set; }
}
and view:
<div id="post_detail">
#Html.Partial("Summary", Model.Summary)
<ul class="comment-list">
#foreach(var comment in Model.Comments)
{
<li>#Html.Partial("Comment", comment)</li>
}
</ul>
</div>
This means that the PostController.Detail method would be responsible for constructing a PostSummaryModel, constructing a PostCommentsModel and selecting which partials to use to render each.
If you then also had the following model:
public class PostListModel
{
ICollection<PostSummaryModel> Posts { get;set; }
}
You would have two actions responsible for constructing a PostSummaryModel and knowing which partial to use. If your application isn't properly structured, this might lead to duplicate data access/model mapping code. But if you delegate and abstract model construction into re-usable model factories (that could be called by both actions) you minimise this risk.
One the other hand, taking the Html.Action approach your model simply becomes:
public class PostDetailModel
{
int PostId { get;set; }
}
and view:
<div id="post_detail">
#Html.Action("Summary", new { Model.PostId })
#Html.Action("Comments", new { Model.PostId })
</div>
It can then be left up the "Summary" and "Comments" actions to construct their own model and select a view.
There is however an ever so slight performance hit in choosing the Html.Action approach because ASP.NET MVC has to go through the whole process of model-binding, executing action filters, validating, etc so you probably wouldn't use Html.Action to display items in a sufficiently long list view. But for creating a composite view it can be a really clean way to stitch together half a dozen or so existing views.
I think you should go with Action or RenderAction as Darin points out if you want to have logic in your view. However, there is a "hacky" solution that you could use and that is to implement your own IViewPageActivator. Then you could have your views implement a custom WebViewPage and inject services in this WebViewPage and they will be available to your views. To summarize:
Use Partial or RenderPartial if you only need to inject the model
Use Action or RenderAction if you have some logic in your partial view
Implement IViewPageActivator and some other stuff if you really have to
UPDATE: Also, in simple scenarios helpers might do the job for you depending on what you are trying to achieve.
Take a look at client site MVC javascript framework for controlling complex UI.
In combination with jquery templating very powerfull and an option to keep an eye on ...
Backbone.js
http://documentcloud.github.com/backbone/
Kockout.js
http://knockoutjs.com/
Knockout.js vs. Backbone.js – Part 1
http://ifandelse.com/?p=61
Knockout.js vs. Backbone.js – Part 2
http://ifandelse.com/?p=70
Html.Action and Html.RenderAction are the best way to externalize some repeating complex logic in the views that requires its own controllers and models.
We're evaluating asp.net MVC and are looking for some more complicated examples over and above NerdDinner.
Specifically, in a more complex web app, I might have a navigation bar (including primary nav, a search box and a log-in status display), a main content area, a sub-content area (including related content) and a footer. In MVC a controller returns a ViewModel (not a View if I'm thinking that I want to de-couple my Controller from my View) - would my ViewModel have to have properties to cover each and every aspect of the "page" I am aiming to render as output?
If this is unclear, I may be able to re-word my question.
BTW - I know this site is built using MVC. I'm after downloadable examples.
Thanks in advance.
Take a look at CodeCampServer.
Edit: With reference to your query about view models, this isn't the perfect answer to it but thought I'd draw attention to AutoMapper (used by CodeCampServer) which can assist with auto mapping data between models and view models which is a real time saver. Also worth considering the concept of Input Builders (there's some available with MVCContrib and also some in ASP.NET MVC 2) which will also reduce the amount of data you have to pass into a view by encapsulating common functionality across the board.
There's a good video on the ASP.NET MVC 2 offering here: http://channel9.msdn.com/posts/Glucose/Hanselminutes-on-9-ASPNET-MVC-2-Preview-1-with-Phil-Haack-and-Virtual-Scott/.
Here ya go:
<% Html.RenderAction<LayoutController>(c => c.SearchBox()); %>
<% Html.RenderAction<LayoutController>(c => c.NavBox(Model)); %>
Put these in your masterpages, or on specific views for sidebar widgets, and abstract their logic away from your controller/viewmodel you are working on. They can even read the current RouteData (url/action) and ControllerContext (parameters/models), cause you are dealing with ambient values in these objects - and executing a full ActionMethod request!
I blogged about this little known secret here. I also blogged about where this is located, which is the ASP.NET 1.0 MVC Futures assembly that is a seperate add-on from Microsoft.
Steve Sanderson actually gives gives examples of complex logic and application building in a book I have called Pro ASP.NET MVC (shameless plug, I know, but it's what you are looking for in your question), where he actually uses the RenderAction! I made the blog post, before I even read the book so I am glad we are on the same page.
Actually, there are dozens of extensions and functionality that was developed by the ASP.NET MVC team that was left out of the ASP.NET MVC 1.0 project - most of which makes complex projects much more managable. This is why more complex examples (list above in most people's answers) have to use some type of custom ViewEngine, or some big hoop jumping with base controllers and custom controllers. I've looked at almost all of the open source versions listed above.
But what it comes down to is not looking at a complex example, but instead knowing the ways to implement the complex logic that you desire - such as your Navigation bar when all you have is a ViewModel in a single controller to deal with. It gets tiring very quickly having to bind your navbar to each and every ViewModel.
So, an example of these is the Html.RenderAction() extension (as I started off with) that allows you to move that more complex/abstracted logic off of the viewmodel/controller (where it is NOT even your concern), and place it in its own controller action where it belongs.
This littler baby has saved MVC for me, especally on large scale enterprise projects I am currently working on.
You can pass your viewmodel into the RenderAction, or just render anything like a Footer or Header area - and let the logic be contained within those actions where you can just fire and forget (write the RenderAction, and forget about any concern of what it does for a header or footer).
You are welcome to take a look at good.codeplex.com
It has much of what you seek above but there is work to be done! However, after you've looked I'd be happy to field questions on it here or over on codeplex.
This is what mygoodpoints.org is currently running on.
would my ViewModel have to have
properties to cover each and every
aspect of the "page" I am aiming to
render as output?
Yes. There is another option with RenderAction, but apart from that a ViewModel in generall is often big and you have to find a good way to fill it. I admit this sounds like a trouble spot first.
AtomSite is a blog engine written using ASP.NET MVC
As far as I know, a Controller directly returns a View and can pass data to the View using either the ViewData or the Context.
The former is just a loose bag of various bits of data, whereas the latter is a specific type.
The ViewModel would be passed to the View as the Context (and the mark-up of the View would be strongly-typed to the type of ViewModel it expects).
That's my 2c worth :) Hope that helped-- sorry I could not include any downloadable examples.
To automatically pass data to all views, you can make your own controller class and use that:
Example
public class MyController : Controller
{
private User _CurrentUser;
public User CurrentUser
{
get
{
if (_CurrentUser == null)
_CurrentUser = (User)Session["CurrentUser"];
return _CurrentUser;
}
set
{
_CurrentUser = value;
Session["CurrentUser"] = _CurrentUser;
}
}
/// <summary>
/// Use this override to pass data to all views automatically
/// </summary>
/// <param name="context"></param>
protected override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
if (context.Result is ViewResult)
{
ViewData["CurrentUser"] = CurrentUser;
}
}
}
I make heavy use of View Components in some of the larger applications I've built in Monorail - What is the equivalent approach in ASP.Net MVC for a view component, that can support sections etc.?
Actually you have several options to create the equivalent of a ViewComponent in ASP.NET MVC, depending in the complexity of your component. I use these two approaches which are the more mvc-ish of the options I am aware of.
1:
The simplest thing is to create a ViewUserControl and display it using Html.RenderPartial with the helper. The ViewUserControl is a simple piece of markup with no backing controller (I think you can put a codebehind file if you want).
Optionally, you can pass a model object or the entire ViewData dictionary to the view when calling RenderPartial, like this:
<% Html.RenderPartial("TopBar", model); %>
"TopBar" is an ascx page. This works anywhere, in master pages and in normal views.
2:
If you want your component to have more complicated logic or to access datasources, IoC, etc, then you can use Html.RenderAction which is an extension method found in the Microsoft.Web.Mvc assembly. I am using this out of the mvccontrib distribution. It works like this, you need to create a normal controller with all the logic you need, then create some views and all of these things become your component, for example:
public class AboutComponentController : Controller {
public IRepository Repository{ get; set; }
public ActionResult Detail() {
var lastEvent = Repository.FindAll<Auditoria>().FirstOrDefault();
return View(lastEvent);
}
}
Notice how I have a reference to an IRepository which is going to be injected with IoC (Windsor in my case) and I can do anything a normal controller would do.
Now, in any page (master or normal) where you want to use your component, import Microsoft.Web.Mvc and call Html.RenderAction with the appropriate parameters. This will create a mini mvc pipeline that creates the controller, resolves the view, etc., just like a Monorail ViewComponent. I prefer to use the lambda based variation of the method, like this:
<% Html.RenderAction<AboutComponentController>(x => x.Detail("a message"));%>
Unfortunately, the only way to pass parameters is to use the method call itself, which in turn must be unique in the controller. Still needs some work to resemble a ViewComponent.
I don't use masterpages or layouts in the views of my components since they are composition elements themselves.
Remember that when using the Webforms view engine, you can have strongly typed views if you like to have intellisense when using the Model variable in code blocks.
The beauty of this is that you can mix view engines with these approaches, I usually create the components in nvelocity and display them in aspx pages, etc.
I now there can be issues with caching of the partial views but I haven't run into any so far. I am sure there are other options (like subcontrollers in mvccontrib) but this is usually enough for simple cases. Of course you can use normal ASP.net components in your aspx view pages but that would be cheating right? hehe. I hope it helps.
Phil Haack blogged about creating areas to group controllers into sub-folders/sections similar to MonoRails.
I am currently building an application using ASP.NET MVC. The data entry pages are fairly easy to code, I just make the Model for the page of the type of my business object:
namespace MyNameSpace.Web.Views.ProjectEdit
{
public partial class MyView : ViewPage<Project>
{
}
}
Where I am struggling is figuring out the best way to implement a dashboard like interface, with stand-alone parts, using ASP.NET MVC, where the Model for each part would be different? I'm assuming that each part would be an MVC user control.
Also, how could I make it so each part is testable?
I think that user controls is probably the way to go. I'm not sure what the concern is about testability. You should be able to test that your controller is providing the right view data -- since you'll have several models each of these will probably be stored in a separate view data item, rather than aggregating them in a single model. Aggregating in a single model is also possible, although probably more brittle. Each control would just need to check for a particular view data item, rather than being specific to a particular model. You could approximate the model variable on each view page by doing:
<% MyUserControlModel model = ViewData["MyUserControlModel"]
as MyUserControlModel; %>
<div id="myUserControl_dashboard" class="dashboard">
Name: <%= model.Name %><br />
Count: <%$ model.Count %>
</div>
If you need to test your view, then you're probably already using Selenium or some other web testing framework. I don't think that these would care how the page was constructed and you should be able to construct your tests pretty much like you always do.
Check out the notion is sub-controllers in MVC-Contrib http://www.codeplex.com/MVCContrib. Basically you run a full request to a partial then display that partial where you want in your existing code.
Alternatively you can check out this post: http://blog.codeville.net/2008/10/14/partial-requests-in-aspnet-mvc/
Codeplex.com has an open source project "DotNet.Highcharts". This project provides an ASP.NET control that wraps around the excellent (free for personal use) Highcharts charting library. that includes a sample MVC3 project in the downloads section.
URL: http://dotnethighcharts.codeplex.com/
I have posted an article on CodeProject.com that includes a downloadable VS2012 solution and some sample C# code. However I use a webform template in my example, not MVC. The bulk of the dashboard is done using JavaScript libraries, HTML & CSS. I have included some sample C# code to demo data retrieval in C# which in then merged with JavaScript code to render one of the many dashboard charts.