ASP.NET MVC Beta and RC Upgrades - Confirm your Expectations and Version Numbers in Production Environments
I was working on an app locally using a daily build (newer than the currently released one) of ASP.NET MVC and deployed it to a host. I noticed this weird CSS issue. See how the text box on the left running on localhost is small and not styled while the one on the right running on the host is the correct width? You can click on the screenshot if you need to see more.
I dug around a little and using the F12 browser developer tools (as well as good old View Source) I noticed the HTML being created was different! My local app was producing one bit of markup, then when I deployed the same app to my host I would get different markup!
Here's the app's markup running locally:
<input class="text-box single-line" data-val="true"
data-val-date="The field EventDate must be a date."
data-val-required="The EventDate field is required."
id="EventDate" name="EventDate" type="datetime" value="5/29/2012 1:48:23 AM" />
Here's while running on the host:
<input class="text-box single-line" data-val="true"
data-val-date="The field EventDate must be a date."
data-val-required="The EventDate field is required."
id="EventDate" name="EventDate" type="text" value="5/29/2012 1:48:23 AM" />
I realize I could have made it more obvious for this but I wanted to make the point that it took a second to notice that my standard ASP.NET MVC Helper call...
<div class="editor-field">
@Html.EditorFor(model => model.EventDate)
@Html.ValidationMessageFor(model => model.EventDate)
</div>
...was returning type="text" on the host but type="datetime" on my local machine and that difference was picked up CSS that targeted specific input tags. Weird. Now, EditorFor() can have its behavior overridden with custom files in ~\Shared\EditorTemplates so if there was a DateTime.cshtml in there that would make sense. There wasn't. I wasn't using the very lovely MvcHtml5Templates NuGet package by Scott Kirkland, so that wasn't it.
My spider-sense was telling me this must be a versioning issue but everything looked right. My only explanation was that somehow what was running on the host was different from what was running on my local machine.
I asked around work and Eilon Lipton suggested I run this snippet to check the version of ASP.NET MVC. He's basically saying "Hey, where did this well known type come from?"
public ActionResult ShowVersion()
{
Type t = null;
try
{
t = Type.GetType("System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35");
}
catch (Exception e)
{
Response.Write("Error finding MVC: " + e.ToString());
}
if (t == null)
{
Response.Write("Can't find MVC");
}
else
{
Response.Write("Found MVC at " + t.Assembly.CodeBase + ", IsInGac = " + t.Assembly.GlobalAssemblyCache + "<br>");
var verAttr = t.Assembly.GetCustomAttributes(typeof(System.Reflection.AssemblyFileVersionAttribute), true)[0] as System.Reflection.AssemblyFileVersionAttribute;
Response.Write("Version = " + verAttr.Version + "<br>");
}
return null;
}
Even better, rather than using this code, I can use the MvcDiagnostics NuGet Package and get THIS useful data from Brad Wilson. Hopefully he will update it for ASP.NET MVC 4 although it worked well.
This package gives you lots of useful information for debugging weird situations.
Anyway, I put the diagnostic code in a controller and ran it and got this (this version is faked):
Found MVC at file:///C:/mysite/bin/System.Web.Mvc.DLL, IsInGac = False
Version = 4.0.77777.0
Hang on, but my local result was this:
Found MVC at file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Web.Mvc/v4.0_4.0.0.0__31bf3856ad364e35/System.Web.Mvc.dll, IsInGac = True
Version = 4.0.99999.0
My local version was newer and was running from the GAC (Global Assembly Cache) but the hosted version was older and running locally. That means I had older ASP.NET MVC files floating around that my project referenced and deployed to the host.
Aside: The specific change that "got" me here was actually the first external contribution accepted to ASP.NET MVC. It's the one that Miguel de Icaza sent a pull request for while I was on stage at DevConnections. The change is to output HTML5 input types for common default data types, like <input type="datetime"> for System.DateTime when using EditorFor().
It took me a moment to remember that I hadn't added the reference to ASP.NET MVC manually but rather via the NuGet Package Manager. This became crystal clear when I used the built-in NuGet Package Visualizer (from Tools | Library Package Manager) to see the package dependency chain:
Basically I needed to either update my out of date NuGet packages or add the assembly references manually without NuGet.
Since I was working on a daily build I did it manually. When you update your ASP.NET MVC 4 Beta applications to a newer build (like ASP.NET MVC 4 Release Candidate (whenever that comes out) or the final Release) you'll want to do update all your packages via NuGet and confirm you're getting the versions and behavior you expect. The NuGet Package Visualizer is a hidden gem indeed.
So, a general reminder to folks (and a specific lesson when upgrading between ASP.NET MVC builds):
- know your version numbers, what you want, what you're referencing.
- confirm your version numbers in your debug and production environment.
- Perhaps a health-check page or a runnable Integration Test to assert your assumptions
- update your NuGet packages keep your references, and thus your ~\bin up to date
- know where your assemblies are being loaded from (the GAC or locally)
Hope this helps!
Sponsor: I want to thank my friends at DevExpress for sponsoring this week's feed. Take a moment and check out their stuff! Touch-enabled apps require developers to re-think design & user experiences. DevExpress tools help you take on these new challenges using your existing skills & today’s technologies.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
1. You use IE to debug web applications?!
2. When .Net was first released everyone was touting 'no more DLL hell', what you didn't tell us was that it would now be called 'Assembly hell'.
:-)
The NuGet Package Visualizer is a hidden gem indeed.
No as useful as it can be:
This feature takes advantage of the DGML support in Visual Studio. Creating the visualization is only supported in Visual Studio Ultimate. Viewing a DGML diagram is only supported in Visual Studio Premium or Higher.
I'm trying to send all fields from a cshtml to the controller method (Edit) to save all fields that I have on a edit page.
For example:
I have a method:
public ActionResult Edit(companiaentities ciaentity)
{
code here to send that ciaentity that should receive from cshtml to send to another class to update compania.
}
but I don't know how.
can you help me on this please?
Thanks a lot.
That binding should happen automatically if the view page is referencing that entity. What kind of trouble are you having?
If you are having trouble getting started why not check out some of the MVC3 Tutorials?
Anyone know of a DGML -> GraphViz bit?
Might not be too hard to write one...
Scott, you're obviously sharp and you were able to quickly sort through this. Imagine some poor schmoe working in IT somewhere who runs into something similar - but who isn't a developer and can't figure this out. Something like this is and will be the perfect example of how end-users in the 'trenches' will end up with a VERY sour taste in their mouths against how MS is handling versioning.
And... I'll say it again: it's fine to include bug-fixes into the in-place replacement for .NET 4.5. But once you start adding new features (async, datetime editors, and other APIs) then pretending that these highly distinct versions of the .NET Framework are both the same or equal is just silly.
And, sadly, it kind of makes your general reminders almost moot - as your first reminder is to 'know' your version numbers. Only, we can't - because the CLR team has decided that two distinct versions of the framework are allowed to masquerade around as the same version of the framework.
And if it sounds like i'm cranky, well, i am. Because no one would try to allow two totally different sets of APIs to pass themselves off as the same version of something. It completely violates the basic purpose and intent of even having versions.
And, long story short, i'm sure we'll get fairly used to being 'burned' by crap like this that takes tons of time to sort out.
--Mike
Thanks a lot for answer me.
My problem is that I'm not working with SQL server, so I must have a classes to implement update, create, delete and so on.
I have to method for edit:
1.- public ActionResult Edit(string strCodigo)
{
this method works very well
}
[HTTPPOST]
2.- public ActionResult Edit(classEntities ciaEntity)
{
here is the problem, I don't know tell to the cshtml that send here the entity.
}
I thought that I could tell in the cshtml the follow:
@html.ActionLink("Edit", "Edit", here the @Model, to send back to the controller the data that I modify to update it.
Thanks.
Don't use Scotts blog post on DLL diagnostics as a discussion forum for a razor template's issue, try stack overflow!!
@Scott, helpful post - a classic "works on my machine" scenario!
Hope to see better results in the future.
P. S. I cudn't find a place to put my feedback so putting it here in comments section.
Please stop promoting that horrible browser!!!
https://www.google.com/chrome
@Naveed: I love Opera Mini (85% less data usage!), but it's not a browser in the traditional sense - content is rendered on a proxy server. With no rendering engine on the device, it will always have problems with some things, especially on-the-fly DOM manipulation. Not sure what the problem is with the snippets (maybe Mini can't handle overflow:auto), but they do appear in Opera Mobile.
I think the bigger problem here is NuGet, or rather how NuGet handles updates. The only way to really force updates on NuGet is to remove the packages and re-add them or - as I did - create a new project and copy the new package reference version numbers and then kill the package folder.
But as you say somebody not that familiar with NuGet and how it works will never discover that. It's a pain in the ass.
NuGet needs an easier mechanism to easily see what version you're running and what version is available. Visual Studio should also provide some sort of indicator where an assembly is coming from. Managing NuGet assemblies across multiple projects that use the same packages too is painful. Really hard to see what's going where.
Comments are closed.