tags:

views:

49

answers:

3

I have an ASP.NET MVC View with the typical TitleContent and MainContent, with a fairly complicated title that I want to calculate once and then share between these two content sections, like so:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<%
    var complicatedTitle = string.Format("{0} - {1}", Model.FirstThing, Model.SecondThing);
%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    <%: complicatedTitle %>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2><%: complicatedTitle %></h2>

</asp:Content>

This, however, doesn't work, as the resulting error message would say that only Content controls are allowed directly in a content page that contains Content controls.

The calculation definately belongs in the view. How do you solve this problem?

+4  A: 

The reason the code cannot be outside a Content control is because it needs to be in a server-side section of some type for the server to be able to automatically render it.

I'd suggest that it would be more common for this title to be constructed in your Controller Action method and saved to ViewData.

David Neale
+1, using ViewData is much more appropriate here. Views should not do calculations, they should only render what's passed in by the controller.
Darin Dimitrov
But the calculation is specific to how it must be rendered.
Dave Van den Eynde
@Dave: You will be dealing with the `Model` object in the controller so will have access to do the calculation. Conceptually you have hit a grey-area that can be argued but the ASP.NET MVC implementation favours doing this in the controller.
David Neale
I strongly disagree. This specific calculation may be different from one view to another, while the same model can be used in both. Heck, different actions use this same view.
Dave Van den Eynde
It completely depends on how you're going to use it. In most circumstances you will be changing title data to give context to the page, that's best done in the controller. If you're going to be using this calculation a number of times then either create a HtmlHelper method or put the logic into the model itself.
David Neale
I'd also suggest that conceptually the view should not be making its own calculations on its context - if you have enough common code to have different actions rendering the same view you should be looking into using a partial view.
David Neale
A: 

here's one way : [Edit: looks like this one results in a static field - so don't use this - sorry]

<Script runat="server" language="C#">
    string foo = "first thing " + " second thing";
</Script>

<asp:Content ContentPlaceHolderID="head" runat="server">
    <%= foo %>
</asp:Content>

<asp:Content ContentPlaceHolderID="body" runat="server">
    <%= foo %>
</asp:Content>

(note you can't use 'var' in Script)

and a second way :

  • Use code-behind to calculate the property with a ComplicatedTitle property that private to the view. You're still completely relying on the view to perform the logic, but taking it out of the HTML part of the view - after all your aspx and aspx.cs file end up becoming the same class in the end anyway!
  • Some people are freaked out by code in views, but I think it definitely has its place if you're cautious and sensible

and a third way :

i'm assuming you don't want to make a third property in your model but heres a quick and dirty way if it ever seems appropriate. at least your controller is not doing it, but this probably isn't the best way

public class MyModel {

   public string Prop1 {get;set;}
   public string Prop2 {get;set;}

   public string GetFormattedTitle() {
      return Prop1 + " - " + Prop2;
   }    
}
Simon_Weaver
there may be an aspx directive to serve as a shortcut for <script>...</script> but i don't remember if there is or not, but that would be slightly cleaner markup if it does exist.
Simon_Weaver
Yes there is: the one used by the OP - `<%`
Darin Dimitrov
@darin - hmm. then perhaps the questioner has wrongly nested <asp:content> tags. you'll get that same error if you mess up the html. this example i gave does compile and run so i'm not sure immeditaly why his original didnt.
Simon_Weaver
You can't use var in <script /> because it becomes a static field, where var is not allowed. Also, it's static, so pretty pointless if I have to pull something from the viewmodel.
Dave Van den Eynde
@Simon_Weaver there must be a difference between <script /> and <% %>, because the former doesn't give me the same error.
Dave Van den Eynde
A: 

Another way is by adding an HTML helper specifically to produce the well-formatted title.

public static string FormattedTitle(this HtmlHelper helper, string firstPart, string secondPart)
{
    return firstPart + secondPart;
}

and then invoke it with

<%: Html.FormattedTitle(firstPart, secondPart) %>
Dave Van den Eynde
In fact, I can get rid of all the arguments but the helper, since I can pull all the information that I need from the model in the helper.
Dave Van den Eynde
How are you planning on removing the arguments? I'm not sure I follow you.
David Neale
All the information needed to calculate that title can be found in the viewmodel, which is available through the helper. It's how DisplayFor() and EditorFor() work as well.
Dave Van den Eynde
But you won't you be explicitly referencing properties in the Model? Html helpers should be domain model-agnostic. It would better follow the separation of concerns principle to implement the code as above with the arguments to concatenate.
David Neale
You're absolutely right. I'm just commenting that it's possible.
Dave Van den Eynde
@David could you argument about why HTML helpers should be domain model-agnostic? Or did you mean viewmodel-agnostic? Still, why?
Dave Van den Eynde
Because the FirstPart and SecondPart properties may or may not exist on the model. A helper will be available to all views and therefore could be passed any model which may not contain those properties. DisplayFor() and EditorFor() use reflection so are model-agnostic.
David Neale