Set Up IIS For An MVC App: When All Else Fails, Check View Config

by Jon Davis 29. April 2009 17:22

I got stumped today when trying to set up a CruiseControl.NET+RoboCopy powered development server deployment for an ASP.NET MVC web app. I set up MVC Framework (gets MVC into the GAC), did the wildcarding in the IIS app config, and everything worked fine, except for strongly typed views. I was confounded. The Event Viewer showed:

Exception information:
    Exception type: HttpParseException
    Exception message: Could not load type 'MyMvcApp.ViewPage<MyModel>'.

This turned out to be caused by a simple mistake. After cc.net compiles the app, RoboCopy copies all the .aspx files over to the web app, and ignores the .cs files, the .config files, etc., so that the .config files don’t get overwritten. I had manually deployed the main web.config file for the app, but I forgot that the Views directory also has a web.config.

Why there is a web.config in the Views directory, I don’t know yet. But the extra .config file in the Views directory is absolutely mandatory to get an MVC app working on IIS, or at least on IIS 6 anyway (haven’t tried 7).

Visual Studio 2008 Crashes When Using ASP.NET MVC (Nasty, NASTY Bug!)

by Jon Davis 16. April 2009 10:05

Some people (like me) have had issues with Visual Studio 2008 suddenly disappearing without errors when the developer user opens up an .aspx file, a .master file, or some other code file in an ASP.NET MVC project.

Had this show stopping issue beat me black and blue over the last 24 hours. I finally got past it when I used the /safemode switch with devenv.exe, but that disables all my lovely add-ins like Resharper. :(

Finally, one of the team members pointed me to “NDP20SP2-KB963676-x86.exe”. He had the same issue and tried to run this hotfix and it worked for him.

It seems to be working so far for me, too. The hotfix is here:

https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=16827&wa=wsignin1.0

File for Windows XP: NDP20SP2-KB963676-x86.exe

More info here: http://www.google.com/search?q=KB963676

AJAX Deferred Loader for ASP.NET

by Jon Davis 11. April 2009 14:19

Here’s a simple ASP.NET control that takes a URL parameter, renders a placeholder on the page, and uses Javascript to “lazy-load” the view content for that placeholder area. It basically does what my sprinkle.js did a long while back, but it takes advantage of ASP.NET controls and jQuery simplicity with its load() function.

It also has self-refreshing. This is good for updating a section of a page with progress information, without refreshing the entire page.

To use it,

  1. Compile the source code (below) to your Web Application project’s assembly, or create an assembly and reference the assembly in your project. You should put this control in its own namespace or in a “.Controls” namespace because of #2 below.
  2. Add a header to any page that would use it to explicitly import all controls under the namespace for which you’re using this control.
    <%@ Register Assembly="MvcApplication1" Namespace="MvcApplication1.Controls" TagPrefix="demo" %>
  3. Be sure jQuery is referenced on the page, ideally in the <head> tag. If you’re using Web Forms and <head runat=”server”>, the process of getting it in there is a little complicated but that’s a different topic. I’m using ASP.NET MVC and I just put it in the Master page. Ultimately, jQuery needs to be loaded before anything else loads, that’s your objective, so you figure it out.
    <html><!-- ... -->
    <head>
      <!-- ... -->
      <script language="javascript" type="text/javascript" src="../../Scripts/jquery-1.3.2.min-vsdoc.js"></script>
      <script language="javascript" type="text/javascript" src="<%=ResolveUrl("~/Scripts/jquery-1.3.2.min.js") %>"></script>
      <!-- ... -->
    </head>
    <body><!-- ... -->
    </body>
    </html>
  4. Now you can reference inline. Note the “RefreshInterval” setting, which is an integer that indicates, in seconds, how often to refresh the region. In this sample, it updates every two seconds. Note also that the HTML that comes back from the referenced URL can include script markup that cancels the interval, such as if a process has completed.
     
    <demo:AjaxDeferredView runat="server" ViewUrl="~/Deferred" RefreshInterval="2">
        <asp:Panel runat="server">Please wait ...</asp:Panel>
    </demo:AjaxDeferredView>
  5. This is what gets outputted with the above tag. Note the “undefined, undefined” are there because the PostData and the Callback optional properties are not set on the control tag.
    <div id="ctl00_MainContent_ctl00">
        <div>
    		Please wait ...
        </div>
    </div>
    <script language="javascript" type="text/javascript"><!--
    $(document).ready(function() {
    	window['ctl00_MainContent_ctl00_interval'] = setInterval(function() {
    		$('#ctl00_MainContent_ctl00').load('http://localhost:5577/Deferred', undefined, undefined);
    	}, 2000);
    	$('#ctl00_MainContent_ctl00').load('http://localhost:5577/Deferred');
    });
    --></script>
  6. And finally, what the end user will actually see is a momentary, split-second, or too-fast-to-see placeholder being swapped out for the content at the loaded URL.
  7. Here’s an example of how to clear that interval in the sample ~/Deferred view that comes back, such as if a process has completed, or in this case after the 5th hit (from any visitor). This sample might be the actual page that is invoked from the AJAX call.  Note the ClearParentInterval control, and that the logic that changes its ClearInterval property precedes its position on the page.
    <%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
    <%@ Register Assembly="MvcApplication1" Namespace="MvcApplication1.Controls" TagPrefix="demo" %>
    <% Response.Cache.SetCacheability(HttpCacheability.NoCache); %>
    Welcome to my deferred content. 
    <%
        
        //live counter
        var i = (int)(Context.Application["defercnt"] ?? 0);
        i++;
        Context.Application["defercnt"] = i;
        %><%=i %>
        
    <% if (i >= 5) // shutdown interval after 5 views
     {
         ClearIntervalControl.ClearInterval = true;
     } %>
     <demo:ClearParentInterval runat="server" ID="ClearIntervalControl" />
    

    This outputs the following when ClearInterval is set to true. The point of the example is in the ID’ing of the <span> tag and in the <script> tag’s contents. It basically walks up the DOM tree by one parent to get the placeholder’s ID in the DOM, then tacks on “_interval” and assumes that to be the name of the interval (which it is).
    <div>Welcome to my deferred content. 5</div>
        
    <span id="ClearIntervalControl">
    </span>
    <script type="text/javascript" language="javascript">
    	var ClearIntervalControl_ClearIntervalParentRef = $('#ClearIntervalControl').parent().attr('id') + '_interval';
    	if (window[ClearIntervalControl_ClearIntervalParentRef]) {
    		clearInterval(window[ClearIntervalControl_ClearIntervalParentRef]);
    	}
    </script>
    

Here’s the control source:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;

namespace MvcApplication1.Controls
{
    public class AjaxDeferredView : System.Web.UI.Control
    {
        protected override void OnInit(EventArgs e)
        {
            if (string.IsNullOrEmpty(ContainerTag))
                ContainerTag = "div";
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.WriteLine();
            writer.WriteBeginTag(ContainerTag);
            writer.WriteAttribute("id", ClientID);
            writer.Write(">");
            base.Render(writer);
            writer.WriteEndTag(ContainerTag);
            writer.WriteLine();
            writer.WriteLine("<script language=\"javascript\" type=\"text/javascript\"><!--");
            writer.WriteLine("$(document).ready(function() {");
            if (RefreshInterval > 0)
            {
                writer.WriteLine("\twindow['" + this.ClientID + "_interval']"
                    + " = setInterval(function() {");
                writer.WriteLine("\t\t$('#" + this.ClientID + "').load('"
                    + ResolveFullUrl(this.ViewUrl) + "', " 
                    + GetDataArg() + ", " + GetCallbackArg() + ");");
                writer.WriteLine("\t}, " + RefreshInterval * 1000 + ");");
            }
            writer.WriteLine("\t$('#" + this.ClientID + "').load('"
                + ResolveFullUrl(this.ViewUrl) + "');");
            writer.WriteLine("});");
            writer.WriteLine("--></script>");
        }

        [PersistenceMode(PersistenceMode.Attribute)]
        public object PostData { get; set; }

        [PersistenceMode(PersistenceMode.Attribute)]
        public string Callback { get; set; }

        [PersistenceMode(PersistenceMode.Attribute)]
        public string ViewUrl { get; set; }

        [PersistenceMode(PersistenceMode.Attribute)]
        public string ContainerTag { get; set; }

        [PersistenceMode(PersistenceMode.Attribute)]
        public int RefreshInterval { get; set; }

        private string GetDataArg()
        {
            if (PostData == null) return "undefined";
            // todo: convert complex class to JSON
            return PostData.ToString();
        }

        private string GetCallbackArg()
        {
            if (string.IsNullOrEmpty(Callback)) return "undefined";
            return Callback;
        }

        private string ResolveFullUrl(string url)
        {
            var ret = new Uri(Request.Url, Page.ResolveUrl(url));
            return ret.ToString();
        }

        private HttpResponse Response
        {
            get { return HttpContext.Current.Response; }
        }

        private HttpRequest Request
        {
            get { return HttpContext.Current.Request; }
        }
    }

    public class ClearParentInterval : Control
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if (string.IsNullOrEmpty(ContainerTag))
                ContainerTag = "span";
        }
        protected override void Render(HtmlTextWriter writer)
        {
            writer.WriteBeginTag(ContainerTag);
            writer.WriteAttribute("id", this.ClientID);
            writer.WriteLine(">");
            base.Render(writer);
            writer.WriteEndTag(ContainerTag);
            writer.WriteLine();
            if (ClearInterval.HasValue && ClearInterval.Value)
            {
                writer.WriteLine("<script type=\"text/javascript\" language=\"javascript\">");
                writer.WriteLine("\tvar " + ClientID + "_ClearIntervalParentRef = $('#" + this.ClientID +
                                 "').parent().attr('id') + '_interval';");
                writer.WriteLine("\tif (window[" + ClientID + "_ClearIntervalParentRef]) {");
                writer.WriteLine("\t\tclearInterval(window[" + ClientID + "_ClearIntervalParentRef]);");
                writer.WriteLine("\t}");
                writer.WriteLine("</script>");
            }
        }
        [PersistenceMode(PersistenceMode.Attribute)]
        public string ContainerTag { get; set; }

        public bool? ClearInterval { get; set; }
    }
}

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

Web Development

TDD: Here I Go!!

by Jon Davis 4. April 2009 11:57

About a week and a half ago I finally started breaking ground (that is, created a Visual Studio soluton and started writing code, with the intention of it being used in production) on a big composite pet project I've been considering for a very long time. I won't get into what the project is going to be about (at least not now), but I will say parts of it are multi-faceted software foundation / framework. So, once I'm done, I'll be able to take a bunch of the code I wrote here and re-apply it on a completely different project. This is important to me as I am seriously in need of gaining some inertia in pet project development and deployments.

So right away I started writing tests to "prove out" each little piece of code as I wrote it. I'd heard the TDD gospel and wanted to convert, but I don't have a lot of TDD practice under my belt. But right away I had about 75% code coverage, which I felt was pretty good compared to 0% of projects in the past. Every time I wrote a little bit of code, I hit Ctrl+R, A to be sure nothing I just did failed. This worked fine, at the beginning, while working with simple, lightweight objects.

Pretty soon I found myself implementing abstract provider/service classes, and then create at least one or two implementations of them. And then I wrote this big dependency object that gets passed around back and forth. By the time I had some prototype code written, I realized that my tests would not break because I hadn't been writing code around my tests, I had been writing my tests around the code I had been writing. And at this point I was clueless as to whether the code I had just written would work, because this was all plumbing code. I wanted to at least try something and see if the basics were working, so I created a console application and wrote some code with Console.Write()'s to get a visual on the output. But at this point things were getting messy. My dependency object I had created was created for the one implementation class of my abstract provider/service object. I now had a throw-away console app in my solution that didn't belong. And my test coverage was down to something like 5%.

That's when I realized I was going about this all wrong. For months I had a hard time understanding why TDD proponents argued that writing code before their tests is "putting the cart before the horse", when writing tests before code seemed so backwards to me. But now it started to click. For many years, I've been designing code in my head, then implementing those designs in code, and if it works, great, if not, I fix the bugs. I'm starting to see now how I need to retrain myself. It's okay to design code in your head. You just need to document those designs in tests. At first, they won't even compile. Fine. But at least document your designs in tests.

Funny, I haven't ever heard anyone make the connection, but writing tests with mocks of the way you want your code to work is exactly the same to a programmer as wireframes are to web design. One should not design a web page by throwing some HTML into a web site, trying to make it look nice and complete, and then showing it to the customer for the first time and saying, "Here you go, it's done. Now tell me what's wrong with it." Rather, a professional web production team would first collect the requirements (in workflow verbiage) of the web site, throw together some wireframe mock-ups, create Photoshop design comps in parallel, and then go to implementation, all the while following up with the customer for feedback during each and every step along the way. TDD is exactly the same but for the programmer. The tests are wireframes and business rules, just like a web application spec has bullet-point business rule text that serves as manual tests for all parties involved to both define and validate the implementation.

Even if there is no third party customer who would approve your "wireframes" and you're working solo, the analogy of "wireframing a web design" should still apply. A web designer/engineer can, but shouldn't, create a web site before wireframing it. He should start with a napkin, and go from there. Likewise, one can, but shouldn't, write code before writing tests for that code, because tests are not just validations that assumed functionality works but are also definitions of assumed functionality, and without definitions of assumed functionality there are really no coding objectives.

The hardest part for me to do TDD so far in this new experience is realizing I wasn't doing TDD in the first place, and then going back and scrapping all the code I had just written, whether it was good or not. I knew it had a little bit of 'bad' mixed in with the good, and that should not be acceptable. Awareness of "a little bit of bad code buried in there" typically means mostly bad code in the long run, and a lot of wasted time, because bad code cascades and affects everything else, like yeast.

One other thing about these incidents is that I've also been re-learning the theory of YAGNI (you ain't gonna need it!). I was getting too comfortable with the idea of introducing extra method signatures on objects that were not getting properly tested to begin with, and for which my use cases were purely theoretical, and not truely intentional. I've argued here in this blog in the past that YAGNI is extremely naive and not the appropriate attitude when writing software in smaller shops (like one or two man bands) because the multi-role developer often knows exacty what he needs and should not be withheld from adding what he needs in order to do his job. That's great, ignore YAGNI, so long as you're taking an "undisciplined", less-formal approach to software or are writing software that is not intended to be reused such as a framework. However, in my case, I'm writing framework bits, and I must balance ease of use by way of high versatility versus ease of use by way of simplicity. Other programmers, including myself at some later point in time, should not be confused with options. Programmers are software users, just like their end-users are software users. So the end-users use the mouse and click simple things, whereas programmers use framework code to write code, fine, either way, they're all users. The Apple and Google approaches are to keep it simple, stupid (KISS). Don't overwhelm the user with options, especially if either of two options reach the same outcome. I should define one "best practices" path and only introduce the other path when it is needed, not when it is slightly and occasionally convenient.

Part of the reason why I write like such is to drive it into my head. I still settle for less than what I preach sometimes.

There's one other thing; tests are a part of the TDD strategy, but I'm also beginning to think that once I have made some headway into these framework bits to be able to actually write some code that passes tests, I might also start writing some application/implementation project code. Call it a manual test if you like. The tests themselves should not lose priority. But I think it makes sense, to an extent, to see code written in action as soon as it's feasible in order to prove out code design prototypes. Writing application code should NOT actually be additional tests but rather take advantage of what's alreay passing and help guide the tests as the tests are being written. In this light, the only problem I have with TDD is that TDD is spoken of too often in terms of unit and integration tests, whereas the whole lifecycle of designing with tests and of testing must be much broader than unit and intgration tests. TDD starts with unit tests, but unit tests, by definition, only test one tiny unit of functionality. In order to really drive your design and development through tests, you need to be able to test workflows, too. Starting from Point A, given n parameters, we should ultimately arrive at B, and this might involve several steps.

Oh, I still need to watch Rob Conery's MVC Storefront videos where he, too, learned TDD. I got about ten or so videos in until I caught up, and then stopped watching while he kept streaming them out.

Tags:

C#

Terabyte(s) SSD On Servers and Now On Laptops

by Jon Davis 3. April 2009 00:29

http://www.engadget.com/tag/pcie%2Cssd

I first found out about 1TB super-super-SUPER fast SSD storage when EVE Online announced that they upgraded their database server with these puppies.

Tonight I just spotted this mention of a laptop with such a thing.
http://www.engadget.com/2009/03/02/asus-slaps-1tb-ssd-within-lamborghini-vx5-laptop/
http://www.engadget.com/2009/03/03/hands-on-asus-lamborghini-vx5-laptop/

"A state of disbelief" doesn't state my feelings enough.


 

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About the author

Jon Davis (aka "stimpy77") has been a programmer, developer, and consultant for web and Windows software solutions professionally since 1997, with experience ranging from OS and hardware support to DHTML programming to IIS/ASP web apps to Java network programming to Visual Basic applications to C# desktop apps.
 
Software in all forms is also his sole hobby, whether playing PC games or tinkering with programming them. "I was playing Defender on the Commodore 64," he reminisces, "when I decided at the age of 12 or so that I want to be a computer programmer when I grow up."

Jon was previously employed as a senior .NET developer at a very well-known Internet services company whom you're more likely than not to have directly done business with. However, this blog and all of jondavis.net have no affiliation with, and are not representative of, his former employer in any way.

Contact Me 


Tag cloud

Calendar

<<  April 2014  >>
MoTuWeThFrSaSu
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar