views:

2099

answers:

6

In RC1 the behavior of the template for creating a view changed.

As explained by Scott Gu's post about the release candidate a newly created aspx view doesn't have a code-behind file by default anymore.

Based on feedback we’ve changed view-templates to not have a code-behind file by default. This change helps reinforce the purpose of views in a MVC application (which are intended to be purely about rendering and to not contain any non-rendering related code), and for most people eliminates unused files in the project.

The RC build now adds C# and VB syntax support for inheriting view templates from base classes that use generics. For example, below we are using this with the Edit.aspx view template – whose “inherits” attribute derives from the ViewPage type:

I really like being able to write view specific code in the codebehind to just output the view - especially if I have logic repeated in several parts of the page where I cant justify creating a partial view.

My actual question: Scott said by default - which implies I can change that behavior, but i cannot seem to see where. Is it possible? Manually creatingn a codebehind file and changing things around is a pain.

This causes an additional problem too :

  • If I refactor the name of my model then the directive in the View isn't updated. This isn't the end of the world, but one distinct advantage of having it fully strongly typed.

Addendum: For those of you wondering WHY I would want a codebehind here are some of the possible reasons. This is a cumulative list of just about everything I've thought of. It goes without saying (well it should) that you mustn't access any data other than that which is already in the model. LINQ would be fine for simple manipulation of model data, but LINQ to SQL would NOT! MVC is for people who should already know this - thats why I love it - made BY smart people FOR smart people.

  • Databinding legacy ASP.NET controls - if an alternative is not available or a temporary solution is needed.
  • View logic that requires recursion to create some kind of nested or hierarchical HTML.
  • View logic that uses temporary variables. I refuse to define local variables in my tag soup! I'd want them as properties on the view class at the very least.
  • Logic that is specific only to one view or model and does not belong to an HtmlHelper. As a side note I don't think an HtmlHelper should know about any 'Model' classes. Its fine if it knows about the classes defined inside a model (such as IEnumerable<Product>, but I dont think for instance you should ever have an HtmlHelper that takes a ProductModel.
  • HtmlHelper methods end up becoming visible from ALL your views when you type Html+dot and i really want to minimize this list as much as possible.
  • What if I want to write code that uses HtmlGenericControl and other classes in that namespace to generate my HTML in an object oriented way (or I have existing code that does that that I want to port).
  • What if I'm planning on using a different view engine in future. I might want to keep some of the logic aside from the tag soup to make it easier to reuse later.
  • What if I want to be able to rename my Model classes and have it automatically refactor my view without having to go to the view.aspx and change the class name.
  • What if I'm coordinating with an HTML designer who I don't trust to not mess up the 'tag soup' and want to write anythin beyond very basic looping in the .aspx.cs file.

I think people are biased against 'code-behind' since it has traditially been interpreted to mean 'event handling code' as opposed to 'the other half of a view's partial class' which is what it is.

Code-behind for views is just fine.

I'm not disagreeing that it clutters up the folder structure a little, but thats what the + icon is for. I just want the ability to create a view with codebehind using 'Add view'.

+1  A: 

To answer your question directly, I don't think you can change this default. You could try modifying the template (which would be somewhere in %programfiles%\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates"), but I don't know for sure.

However, the "MVC-way" for this scenario is probably to create a custom helper, in a separate class.

I recently wrote a web app that used Gravatar (http://www.gravatar.com) to generate profile pictures and I kept writing the same custom <img> tags all over my views, so I created a helper: Html.Gravatar()

Just create a static class "MyHelpers" or "GravatarHelpers" or "FooHelpers" and add static extension methods with signatures like this:

public static string Gravatar(this HtmlHelper htmlHelper, string emailAddress) {
    return htmlHelper.Image(...);
}

or, if you use strongly typed views (ViewPage<T>) and want to take advantage of that you can extend HtmlHelper<T>

public static string Foo<TModel>(this HtmlHelper<TModel> htmlHelper, ...) {
    // Do stuff
    return // Stuff
}

You can easily switch out HtmlHelper for UrlHelper or AjaxHelper. I believe you can also access the ViewData, etc. from a ViewContext property on the helper.

anurse
if its generic - definitely a helper is the way to go. but what if i'm writing somethin that requires for instance recursion or just complex logic i dont want all over my view?
Simon_Weaver
I'd probably still use a helper, even if it was just going to be used multiple times in only one view. Just create a helpers class for that view: "NewCustomerViewHelpers", in the same namespace as the view so it doesn't conflict with other view helpers. That's practically a codebehind file :)
anurse
+1  A: 

That really doesn't seem like a great idea. Every commentary I've read has said "don't use the code-behind; we wish it wasn't there". And I agree. You could try writing your logic in extension methods (traditionally on HtmlHelper) like here.

Marc Gravell
every commentary i've heard (mostly podcasts) says 'be careful to not put non-view logic in there'. MVC is meant for people that know what they're doing. if you're stupid enough to put LINQ in your View then thats your fault. theres plenty of VIEW logic that makes perfect sense to go in the view.cs
Simon_Weaver
@Simon; I suspect we'll have to agree to disagree on that one...
Marc Gravell
@marc even with my addendum above ;-) maybe i'll concede that the new default should remain the new default - i'd just like it to be made easier for each person/architect to be able to choose
Simon_Weaver
A: 

I would also like to have code-behinds as default, can't find the way to change it though. This page explains how to add a codebehind to a page: http://msdn.microsoft.com/en-us/magazine/cc301556.aspx.

In my opinion code-behind classes are ideal for databinding controls and doing some minor changes to the data in case it's necessary (for example date and currency formatting). Also Repeaters are by far the easiest way to display data lists, I still cant find a way to iterate through an anonymous type collection, and only having a for statement in a page reminds me of PHP :S

Pablote
i'd say date and currency formatting belongs in some other util library (provided you are doing some special formatting - perhaps based on a user preference). It doesn't really belong in the 'code-behind' and definitely not in HtmlHelper (unless youre generating a true Html representation of a date)
Simon_Weaver
A: 

I answered this question here:

How to add a Code-behind page to a Partial View

Seems this wasn't particularly tricky, and is quite do-able This answer worked for a Partial 'ViewUserControl' but the same should apply

Ok.

First: Add a Class file with the convention of .cs (i.e. view.ascx.cs)

Second: Add "using System.Web.Mvc;" to the class

Third: Change the Class to Inherit from "ViewUserControl<>"

Fourth: Add the following to the View's header:

CodeBehind="View.ascx.cs" Inherits="Project.Views.Shared.View"

Fifthly: Copy the files out of the solution and drag back in to reassociate the two together

Note: For this to work with a Normal MVC View you just need to inherit the class from "ViewPage"

Harry
+1  A: 

I am of the opinion that code behind files are still a useful thing. While many people talk about how they are bad because they provide a method to break the design pattern that MVC strives for, they do not inherently do this. You can say that the view is supposed to be stupid, but I think its probably more accurate to say that the view isn't suppose to concern itself with complex business logic. It does however need to concern it self with the aspects of presentation. As such, there are still elements to presenting information that require code beyond simple html. It follows the reasoning of separation of concerns (let alone, pure readability of the view) that the markup concern itself with markup with the code behind supporting it where code is necessary.

Luis Abreu has written a good article about the subject

Codebehind files in asp.net mvc are not evil

Mr Bell
+1  A: 

FYI - In Visual Studio 2010, simply adding the appropriately named code file to the file containing the view will automatically associate the new code-behind file with the view. You don't need to remove and re-add the files to get them to link up. However, you'll still need to change the inherited classes to make it work as @Harry describes.

Peter
thats nice :) things used to get in a real mess sometimes when it got confused!
Simon_Weaver