Visual Studio MVC Oddity? - asp.net-mvc

I've been stuck on the same DropDownList problem for days now while working on a MVC project in VS2010. The problem has become even more frustrating right now because when I copy all relevant code into a completely new, blank project, the second instance actually runs perfectly and produces exactly the result I expect...
Controller:
<HandleError()> _
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
ViewData("Message") = "Welcome to ASP.NET MVC!"
Return View()
End Function
Function About() As ActionResult
Dim configList As List(Of String) = New List(Of String)
configList.Add("10GBaseLX4")
configList.Add("10GFC")
configList.Add("10GigE")
configList.Add("100BaseFX")
configList.Add("Test")
ViewData("cprotocols") = New SelectList(configList)
Return View()
End Function
End Class
View:
<%# Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="aboutTitle" ContentPlaceHolderID="TitleContent" runat="server">
About Us
</asp:Content>
<asp:Content ID="aboutContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>About</h2>
<p>
<% Using Html.BeginForm()%>
<%= Html.DropDownList("cprotocols") %>
<% End Using %>
</p>
</asp:Content>
The page doesn't do anything right now other than simply display a dropdownlist with the options shown hard-coded in the controller, but I'm not even going to bother with writing logic when my current site refuses to even show the list to the user.
The error message is There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'cprotocols'. but once again, there are no runtime errors when i copy this bit of code over to a blanked solution.
Any ideas how to solve this or even any clues on what is causing such an inconsistency? I don't want to copy over all the other files from my current project into the new one just to have the problem manifest itself again somewhere down the line (which is bound to happen when the code is only half broken...)

I would try changing the ViewData key name and see if that helps anywhere. If not, if you can you could create a new project and copy all your existing model/controller/view classes over the other project, this seems like something in your project configuration that could have gone off.
Hope this helps a little :)

Turns out it was a problem with the module; the code itself is fine. I had to delete Temporary ASP.NET files, clean up my GAC, as well as nuke all current assembly references in my project, clean solution, re-add required references, and finally clean and rebuild. I'm still not clear on why exactly VS2010 was referring to assemblies from an old build (simply cleaning and rebuilding is not enough). I also don't know at what point the environment stops "refreshing" and decides to simply refer to obsolete builds. I'll try to do a bit more research on this point and then add on to this post.

Related

Modifying T4 code templates for ASP.NET MVC to get rid of full namespace reference

We're using (there is need to tell where the files are, thanks) custom T4 code templates on creating a view or controller. Default implementation makes this kind first row.
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ProjectNameHere.ViewModels.ViewModelClass>" %>
We have already ViewModel and MVC namespace defined in the Web.config, so I would like code template to generate this.
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="ViewPage<ViewModelClass>" %>
Any suggestions how modify the default templates to get that kind of results? Which of the template lines actually generate these?
More information
I know where the files are and modifications has been made. Problem is that in the template they're using this
string mvcViewDataTypeGenericString = (!String.IsNullOrEmpty(mvcHost.ViewDataTypeName)) ? "<" + mvcHost.ViewDataTypeName + ">" : String.Empty;
It seems that ViewDataTypeName contains full namespace reference. I would like get just name of the class (in this case ViewModel class name)
You can find the templates here:
*\Microsoft Visual Studio \Common7\IDE\ItemTemplates\CSharp\Web\MVC 2\CodeTemplates*
There you can edit the generated code for each template, the template lines vary for each template so i cannot tell you, but you will spot them immidiately.
EDIT
The source for Web.Extensions is not available, but you can make use of relector and reflect on
\Microsoft Visual Studio \Common7\IDE\Microsoft.VisualStudio.Web.Extensions.dll assembly to see what "mvcHost" gives you :)
You will then notice a ViewDataType property which is a "Type", and you should then be able to create some logic around it to get the class name.

Problems with Site.Master and ASP.NET MVC

i'm trying to make my site master page (views/shared/site.master) strongly typed.
eg. Inherits="TestProject.Mvc.Views.Shared.Site"
I can't seem to get this work. Once i make the site.master page strongly, typed, Visual Studio seems to 'loose' what <%= Html.XXX %> is. Also, the page throws an error when i try to display the default index route.
The SiteMasterViewData class exists in the views/shared/ folder and has been included at the top of the master page via..
<%# Import Namespace="TestProject.Mvc.Views.Shared"%>
Can this be done? is there a better way to do this?
Damn - found my own answer.
All masterpages in the ASP.NET MVC v1. need to inherit from:
<%# Master
Language="C#"
Inherits="System.Web.Mvc.ViewMasterPage" %>
so if u want to strongly type it, you can do this.
<%# Master
Language="C#"
Inherits="System.Web.Mvc.ViewMasterPage<SiteMasterViewData>" %>
HTH's other peeps :)

Script & CSS Registration Helper in ASP.NET MVC?

I have tried to use ASP.NET MVC for a while, then I face a problem that I don't want to include all of my js and css in master page. But how can I register it in head of master page from my specific view?
The default master page template includes a Content PlaceHolder for the head. If it doesn't you can easily add one:
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server" />
</head>
Your views can then put anything they want in the head:
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script src="Scripts/myScripts.js" type="text/javascript"></script>
<link href="Styles/myStyles.css" rel="stylesheet" type="text/css" />
</asp:Content>
It doesn't look like there's a simple option 'built-in' to the ASP.NET MVC framework just yet. If you are using a user control (.ascx), which you may be if you are creating self-contained controls which also want to manage their own JavaScript requirements, then you can't even use the placeholders to help you out.
In the end I created a helper class and in it there are a couple of methods:
private static SortedList<int, string> GetRegisteredScriptIncludes()
{
var registeredScriptIncludes = System.Web.HttpContext.Current.Items["RegisteredScriptIncludes"] as SortedList<int, string>;
if (registeredScriptIncludes == null)
{
registeredScriptIncludes = new SortedList<int, string>();
System.Web.HttpContext.Current.Items["RegisteredScriptIncludes"] = registeredScriptIncludes;
}
return registeredScriptIncludes;
}
public static void RegisterScriptInclude(this HtmlHelper htmlhelper, string script)
{
var registeredScriptIncludes = GetRegisteredScriptIncludes();
if (!registeredScriptIncludes.ContainsValue(script))
{
registeredScriptIncludes.Add(registeredScriptIncludes.Count, script);
}
}
public static string RenderScripts(this HtmlHelper htmlhelper)
{
var registeredScriptIncludes = GetRegisteredScriptIncludes();
var scripts = new StringBuilder();
foreach (string script in registeredScriptIncludes.Values)
{
scripts.AppendLine("<script src='" + script + "' type='text/javascript'></script>");
}
return scripts.ToString();
}
That's a basic form of it anyway to try and show the way it works. It could be enhanced in many ways, but at the moment it just filters out duplicate script insert requests for you. Whenever you want to add a new script in the ascx (or aspx for that matter) you can do it this way:
<%
Html.RegisterScriptInclude(Url.Content("~/Scripts/MapLayers/MapLayer.js"));
Html.RegisterScriptInclude(Url.Content("~/Scripts/MapLayers/Vehicles.js"));
%>
Then you need to remember to output them once you're done. This is achieved by making the following call at the place in your page where you want to output the script tags:
<%=Html.RenderScripts() %>
Seems to work so far for me. I did half expect to have rendering issues depending at what point RenderScripts was called, especially if not all of the RegisterScriptIncludes had been called yet, but so far it seems to do the job. If you render the scripts last then you should have no problems.
#Jason: WARNING, you shouldn't be using static variables like this... In a web context static variables are shared across all users and all page requests. I am amazed that you haven't run into trouble with your code. The principle is fine but the code is wrong and will give you trouble. In this case you should be using System.Web.HttpContext.Current.Items. See http://www.hanselman.com/blog/ATaleOfTwoTechniquesTheThreadStaticAttributeAndSystemWebHttpContextCurrentItems.aspx for more.
Here is a solution similar to the one Jason gave, but takes vdh_ant's comments into consideration:
http://frugalcoder.us/post/2009/06/29/Handling-Scripts-in-ASPNet-MVC.aspx
technically you should be putting all your js at the bottom of the page for the best performance.
I think the only way you could do this though would be to include the javascript in the VIewData and have the ViewData displayed on the masterpage (not a great solution).
MVC Futures now has built in helpers for this...
1.<head>
2. <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
3. <%= Html.Css("BlueTheme/site.css") %>
4. <%= Html.Script("jquery-1.3.2.js") %>
5.</head>
More information here: http://blog.osbornm.com/archive/2009/10/12/mvc-script-css-helpers.aspx
Mathew,
I took a look at your blog on Html.Css and Html.Script helpers. I don't mean to be critical but I do not see any mention in the blog about how the Css and Script helpers would address the problem discussed here. The problem here is one of needing to "registered" script references at any point during the rendering process, and possibly multiple times (in the case of an template or partial view that is used several times and registers its own scripts), and then outputting the aggregate results, sans duplicates, in a single location.
If your solution addresses this, please correct me with some clarification.
--Regards,
Ken
I wrote just such a manager for MVC, and wrote about it on my blog:
"JavascriptHelper–Managing JS files for ASP.NET MVC"
UPDATE: I added bundling:
"JavascriptHelper:Managing JS files for ASP.NET MVC (With Bundling)"

Remove the *.cs, *.Designer.cs codebehind files?

Yeah, its a bit on this side of pointless, but I was wondering... I've got all these codebehind files cluttering my MVC app. The only reason why I need these files, as far as I can tell, is to tell ASP.NET that my page extends from ViewPage rather than Page.
I've tried a couple different Page directives changes, but nothing I've found will allow me to identify the base class for the page AND let me delete the codebehind files.
Is there a way to do it?
UPDATE: I'm trying to inherit from a strongly-typed ViewPage! Seems like its possible to inherit from a regular ViewPage...
Delete the codebehind and use a page directive like this:
<%# Page Title="Title" Inherits="System.Web.Mvc.ViewPage" Language="C#" MasterPageFile="~/Views/Layouts/Site.Master" %>
Or, if you want to get rid of the codebehind but still want to use strongly typed view, then read this link: http://devlicio.us/blogs/tim_barcz/archive/2008/08/13/strongly-typed-viewdata-without-a-codebehind.aspx
Here is a cut and paste of what this would look like:
<%# Page Inherits="System.Web.Mvc.ViewPage`1[[ABCCompany.MVC.Web.Models.LoginData, ABCCompany.MVC.Web]]" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" %>
Assuming you don't have any code in your codebehind, why don't you point them all to one codebehind file?
Straight out of the box you should be able to delete the .designer.cs and nothing will break. The other code behind can be useful, for instance if you'd like to strongly type your viewdata.

.NET MVC Ambiguous Type Reference

Not entirely sure what's going on here; any help would be appreciated.
I'm trying to create a new .NET MVC web app. I was pretty sure I had it set up correctly, but I'm getting the following error:
The type 'System.Web.Mvc.ViewPage' is ambiguous: it could come from assembly
'C:\MyProject\bin\System.Web.Mvc.DLL' or from assembly
'C:\MyProject\bin\MyProject.DLL'. Please specify the assembly explicitly in the type name.
The source error it reports is as follows:
Line 1: <%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
Line 2:
Line 3: <asp:Content ID="indexContent" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">
Anything stand out that I'm doing completely wrong?
I suppose you named one of your page "ViewPage" is that the case?
And like #Jonathan mentioned, this smells:
Inherits="System.Web.Mvc.ViewPage"
On my MVC application, all the view pages have this instead:
Inherits="MySite.Views.Pages.Home"
Or something along the line. Your aspx page markup should have "Inherits" point to your code-behind class name, not the actual class that it is inheriting. The attribute name is rather misleading but its an artifact of earlier days.
Are you using a CodeBehind file, I don't see CodeBehind="" attribute where you are specifying the Inherits from? Then you have to point inherits to the class name of the codebehind.
Example:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication4.Views.Home.Index" %>
Make sure the Inherits is fully qualified. It should be the namespace followed by the class name.
I'm running ASP.NET MVC Beta and also encountered this error.
It came about while I was trying to remove the code behind file for a view. I removed the "CodeBehind" attribute in the #Page directive and changed the "Inherits" attribute to point to System.Web.Mvc.ViewPage, but left the actual aspx.cs code behind file untouched in my project.
At this point, if I tried to run my project, I got the error you mentioned.
I resolved this error by deleting the aspx.cs (code behind) file for the view from my project.
Check your assembly references to System.Web.Mvc in web.config.
Mine were explicitly specifying 2.0.0.0, but my project referenced 3.0.0.0
This error usually indicates a class naming conflict. You are referencing two namespaces or you created a class with the same name in another namespace that you are using. I would start by looking at what that could be.
Inherits="System.Web.Mvc.ViewPage"
I'd imagine that this should be pointed at your View codebehind file class, not at the base ViewPage class.
Open up C:\MyProject\bin\MyProject.DLL in Reflector and look for ViewPage to see if you've defined one by accident.
No this should be a structural error message.
Check http://trikks.wordpress.com/2011/08/26/the-type-is-ambiguous-it-could-come-from-assembly-or-from-assembly-please-specify-the-assembly-explicitly-in-the-type-name/
I had the same exact error this week.
My Webform.aspx file had a generated designer.cs file. In this file the class was actually named "ViewPage". Delete the designer file, or move the class contents to the webform.aspx.cs file and my error was gone.
Just putting it out there in case someone had this error.

Resources