Scott Hanselman

ASP.NET MVC Preview 4 - Using Ajax and Ajax.Form

July 16, '08 Comments [51] Posted in ASP.NET | ASP.NET MVC
Sponsored By

ASP.NET MVC Preview 4 is up on CodePlex. The Gu has all the exquisite Gu-Like Detail on his blog. Phil Haack has some notes on this release on his blog.

If you take a look at the generated "changes" document, it shows a bunch of new stuff like AjaxHelpers and AjaxExtensions that set the stage for some interesting things the community could do with ASP.NET MVC and Ajax. I'd like to see some JQuery love in there, maybe with some MVCContrib as they've been quiet lately.

Using the new Preview 4 bits, here's what I was able to get running in just a few minutes.

Given a ViewPage that has a TextBox and a Button on it, when I click the button (and submit the form) I'll call back to the server and get some text that should then go in the div next to the button.

mvcpreview4ajax

The View looks like:

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<p>
<%using (Ajax.Form("ExamineTextBox", new AjaxOptions { UpdateTargetId = "result" }))
{ %>
<%= Html.TextBox("textBox1")%>
<input type="submit" value="Button"/>
<span id="result"/>
<% } %>
</p>
</asp:Content>

Notice the Ajax.Form helper and the UpdateTargetID that refers to the span. There's more AjaxOptions in there to explore as well, that we'll see in a second. The controller action looks like this:

public class HomeController : Controller
{
public string ExamineTextBox(string textBox1)
{
if (textBox1 != "Initial Data")
{
return "This text is MVC different from before!";
}
return String.Empty;
}
}

Notice that the return method of the ExamineTextBox isn't an ActionResult, it's a string. In fact, the string result is being wrapped for you into a ContentResult. You could certainly make a ContentResult yourself, but this makes for a nicer looking method signature.

The result of that method is returned via the AJAX call, then put into that span via magic and pixie dust. Actually, the request looks like this:

POST /Home/ExamineTextBox HTTP/1.1
Referer: http://localhost.:45210/Home
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Accept-Encoding: gzip, deflate
Host: localhost.:45210
Content-Length: 28
Connection: Keep-Alive
Pragma: no-cache

textBox1=dude&__MVCAJAX=true

and the Response like this:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/9.0.0.0
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 39
Connection: Close

This text is MVC different from before!

And that UpdateTargetID (the span) mentioned in the Ajax Form helper above? That's swapped in via the magic in MicrosoftMvcAjax.debug.js. There are options for before, after and replace.

// Insert the results into the target element
if (targetElement) {
switch (insertionMode) {
case Sys.Mvc.InsertionMode.Replace:
targetElement.innerHTML = executor.get_responseData();
break;
case Sys.Mvc.InsertionMode.InsertBefore:
targetElement.innerHTML = executor.get_responseData() + targetElement.innerHTML;
break;
case Sys.Mvc.InsertionMode.InsertAfter:
targetElement.innerHTML = targetElement.innerHTML + executor.get_responseData();
break;
}
}

Note that I had to manually (for now) add the JavaScript libraries, so I put them in my Site.Master View.

<script src="/Content/MicrosoftAjax.debug.js" type="text/javascript"></script>
<script src="/Content/MicrosoftMvcAjax.debug.js" type="text/javascript"></script>

Also, notice that the MicrosoftMvcAjax.js is new and it's in your /Content folder if you make a new MVC Application. Congrats to Phil and Eilon and the team for this release!

Related Links

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Learning Opportunity - .NET Terrarium is back!

July 16, '08 Comments [17] Posted in Back to Basics | Learning .NET
Sponsored By

Bil Simser has just done the .NET Community a huge solid. Bil has dug up and re-released Terrarium to CodePlex wtih the intent to update it to use new language features and new usability features like ClickOnce.

If you're newish to the .NET Community (<3-5 years?) you might not have heard of Terrarium. There was a time when it was the tool for getting newbies excited about learning .NET. I showed dozens of high-school and college students how to program using Terrarium. Back at my last company one of our engineers did brown bag lunches on good bug design and ran a Terrarium Server internally.

terriarium

Terrarium hasn't been even looked at by the Microsoft SDK team in two years, as live happens, you know. Bil hunted them down, did a bunch of paperwork and it's back. You can check out the source or download the release.

You can run it alone, just a world in a box, or you can hook it up to a server and that's where it gets interesting, as your bugs all live in a connected world.

Your animals have Idle (event-based) loops that you can react to, and who amongst us hasn't wanted to write these lines of code at least once?

// Reproduce as often as possible 
if (CanReproduce)
BeginReproduction(null);

Now you have the chance.

A great lunchtime project is to get a bunch of the nerds from your company in a room, teach them Terrarium and have a battle!

Personally, I'm a lover, not a fighter, so I run away when attacked.

private void MyAnimal_Attacked(object sender, AttackedEventArgs e)
{
if (e.Attacker.IsAlive)
{
AnimalState TheAttacker = e.Attacker;

BeginDefending(TheAttacker); //defend against the attacker
WriteTrace("Run away to some random point");

int X = OrganismRandom.Next(0, WorldWidth - 1);
int Y = OrganismRandom.Next(0, WorldHeight - 1);

BeginMoving(new MovementVector(new Point(X, Y), 10));
}
}

Go check out the release of Terrarium and download the app, SDK and server. There will be more to come on Bil's Blog, I'm sure. He'll also be running a public Terrarium Server. It's exciting to see this blast from the past. Now I think it's time for me to visit a local High School Computer Science class again some lunchtime...

One of the things I think will be interesting to see, is if folks come up with better patterns for managing state within these animals. Many Terrarium animals end up with Idle loops that look like Arrow Code.

if
if
if
if
do something
endif
endif
endif
endif

This isn't nice to look at, and it would promote bad habits if it was the first kind of code someone new to programming ever saw.

The world has changed since this was released in 2002. The race is on and now I ask:

  • Who will write the first aesthetically pleasing (from a code perspective) Terrarium Animal?
  • The first F# Terrarium animal?
  • The first Ruby (DLR) Terrarium animal?
  • Boo? Nemerle? IronPython?

Enjoy!

UPDATE: I've got this running on my XP machine and my XP VMs but because of missing DirectX 6/7 DLLs I can't get it running under Vista. Possible workaround in the comments below. It'll likely be faster to just recompile it. I'll talk to Bil and see what's up.

 

Related Links

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

New Modules for IIS7: Application Request Routing - Proxy and Load Balancing Module

July 15, '08 Comments [12] Posted in IIS
Sponsored By

image I really like the IIS7 team at Microsoft. They're cool people, but the what I like is that IIS7 is so freaking modular (I've talked about this at conferences before when showing how to use PHP and Ruby under IIS7 using FastCGI) that the group keeps bringing out new functionality as "OOB" or Out Of Band releases.

Bill Staples as a good post on how IIS7 ships software now. There's a big list of all the Release to Web (RTW) modules for IIS7. I demo'ed a the Bit Rate Throttler at TechEd and talked about it in a post on"Squeezing the most out of IIS7 Media Bit Rate Throttling which can help people save bandwidth money while hosting downloadable files/media.

This week the IIS7 team put out three new preview releases for download.

  • IIS7 PowerShell Provider CTP2
    • This provider marries the two technologies and makes administrating IIS7 feel more natural to PowerShell folks. To put it bluntly, you can "cd" into iis:\ as if it were a drive, the type "dir" to see your websites. Drink that in. It's the bomb. I loves me some Powershell.
  • URL Rewrite Module CTP1
    • Just what it sounds like. Unlike ISAPI_Rewrite (which I love) this is an HTTP Module rather than an ISAPI Filter, and it includes an integrated UI for management within the IIS Manager.
  • OSIApplication Request Routing CTP1
    • This is the real dark-horse release. It's got that bland "huh?" name that might cause you to just blow it off or ignore it in the middle of these three modules' release. However, it's deceptively powerful and worth checking out.
      • It requires the URL Rewrite Module above, and hugely builds on its functionality. If you get an error while installing ARR, you need to go install the URL Rewrite Module first.
      • IMPORTANT NOTE: You have to run the MSI from an Administrator Command Prompt. Just running the MSI by double clicking doesn't work. This is a known bug in this CTP. Bummer.

Application Request Routing is interesting. At first I thought it was like NLB (Network Load Balancing), that feature of NT 4.0 that used to be called "Wolfpack." I figured that the great Load Balancing Wars of the '90s were won, and the winner was hardware. I've used Cisco LocalDirector and F5's BigIP in my previous jobs.

ARR is basically a proxy module with load balancing capability that does its routing at Layer 7, rather than Layer 4. That means you make decisions at the HTTP level rather than the IP level. It sits on top of the URL rewrite module, so you can write routing or load balancing rules that can key off of HTTP Headers or Server Vars. You can do Client Affinity via cookie to differentiate between clients behind NAT.  These rules mean it could compliment a system that has an existing hardware load balancer.

If you're familiar with Apache, IIS7's ARR Module kind of combines the functionality you'd find in modproxy, modloadbalance, modproxyhttp along with some other goodness.

It's also a nice reverse proxy if you've ever wanted to do have a smarter IIS7 app router in your home to sit on the outside of your network and route traffic to machines or services inside.

For example, this screenshot shows a routing condition where we want to route folks who have .NET 3.5 on their systems to a separate server. Perhaps a beta site, or a site that has ClickOnce apps or some different functionality. It's totally up to you. You could route folks with certain cookie values, browsers, or  based on path requested.

image

If we had 3 machines in the farm, one IIS7+ARR for routing in front and two other IIS7 machines behind it, I could write a rule that said "don't route requests for images." In this example, I'll have the /images folder served by the ARR machine up front instead.

image

It also has Health Monitoring to check on boxes being down, and you can decide what "healthy" means to you.

ARR is a free download and it plus into IIS7 Manager using the new UI extensibility stuff in IIS7, so it just looks like part of IIS and is managed the same way you manage everything else.

Download

Check 'em out. I'm looking into how I can use ARR to expose my internal Subversion server in a more secure and easily configurable way.

Related Links

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

July 22nd - Seattle/Redmond/Bellevue Nerd Dinner

July 15, '08 Comments [36] Posted in ASP.NET | Microsoft | Musings
Sponsored By

iStock_000002684567XSmall Are you in King County/Seattle/Redmond/Bellevue Washington and surrounding areas? Are you a huge nerd? Perhaps a geek? No? Maybe a spaz, dork, dweeb or wonk. Maybe you're in town for an SDR (Software Design Review) or the ASPInsiders meeting. Quite possibly you're just a normal person.

Regardless, why not join us for some Mall Food at the Crossroads Bellevue Mall Food Court on Tuesday, July 22nd around 6:30pm?

Here's some links to help you remember and add this to your calendar, or head over to http://nerddinner.events.live.com. There's photos of previous Nerd Dinners up on Flickr thanks to Orcmid.

Add to your calendar

I hope to see you there!

NOTE: Even though I told Live Events this was an Open To Anyone Event, it seems to want invitations. Just leave a comment here and show up on July 22nd at 6:30pm! Everyone is welcome, Microsoft employee or not. The more the merrier.

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Back To Basics - Everyone Remember Where We Parked (that memory)!

July 11, '08 Comments [37] Posted in BabySmash | Back to Basics
Sponsored By

I added a new feature to BabySmash during lunch, so that if your (baby's) mouse wheel is over a shape and they scroll the wheel, the system will play a sound and zoom that object in or out. The mouse wheel events come REALLY fast, as do most mouse events.

The general idea is this. I've got the PInvoke/DllImport call to the PlaySound API and a couple of helper methods. If the WAV wasn't cached, I'd go get it and store it away. All this code was kind of written on auto-pilot, you know? It's called very quickly in the MouseWheel event and works fine...until it totally doesn't work at all.

I found that when I wheeled the mouse REALLY fast, sometimes it'd get a nasty burst of loud static instead of the nice WAV file playing as I expected.

I store my WAV files inside the resources of BabySmash.exe (for now) so I just hold them in memory. Initially I would pull them out of the resource every time, but then I added some basic caching. (I probably should have used Chad and Jeremy's cache, but anyway)

[DllImport("winmm.dll")]
public static extern bool PlaySound(byte[] data, IntPtr hMod, UInt32 dwFlags);

public static void PlayWavResource(string wav)
{
byte[] b = GetWavResource(wav);
PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY);
}

public static void PlayWavResourceYield(string wav)
{
byte[] b = GetWavResource(wav);
PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY | SND_NOSTOP);
}

private static byte[] GetWavResource(string wav)
{
//TODO: Is this valid double-check caching?
byte[] b = null;
if (cachedWavs.ContainsKey(wav))
b = cachedWavs[wav];
if (b == null)
{
lock (cachedWavsLock)
{
// get the namespace
string strNameSpace = Assembly.GetExecutingAssembly().GetName().Name;

// get the resource into a stream
using (Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + wav))
{
if (str == null)
throw new ArgumentException(wav + " not found!");
// bring stream into a byte array
var bStr = new Byte[str.Length];
str.Read(bStr, 0, (int)str.Length);
cachedWavs.Add(wav, bStr);
return bStr;
}
}
}
return b;
}

Anyway, I kind of forgot that byte was a value type and in a chat this afternoon Larry made this comment. You might remember that the man responsible for the PlaySound() API is none other than Larry Osterman, who I interviewed last year. Here's our chat transcript:

Larry Osterman‎‎:
My guess is that you're deleting the array b before the PlaySound has completed.
or rather the CLR is.

‎‎Scott Hanselman:
even though it's on the stack?
ah
I get it
the GC is getting to it

‎‎Larry Osterman‎‎:
when you say snd_async, it queues the actual playsound operation to a worker thread.
Yup, GC makes it go away.

When I started going really fast with dozens of calls to PlaySound() a second, I was piling these up and eventually hit the point where one byte[] that was being played would disappear (get garbage collected) and I'd hear the sound of zeros being played. Which sounds much like static. (kidding) ;) I could have made the sound play synchronously, but that doesn't fit well with BabySmash's free-form maniacal button pressing.

Larry suggested I copy the WAV files to a temporary location so they'd be "pinned" down, as there wasn't really a good way to pin these in memory that either of us could come up with. Here's what I did. I grabbed a TempFileName, put the WAV files on disk there and switched the call to PlaySound to the filename overloaded version, rather than the byte[] version. I use TempFileCollection which is helpful because it automatically tries to delete the temporary files when its finalizer runs.

[DllImport("winmm.dll", SetLastError = true)]
static extern bool PlaySound(string pszSound, IntPtr hmod, UInt32 fdwSound);

public void PlayWavResource(string wav)
{
string s = GetWavResource(wav);
PlaySound(s, IntPtr.Zero, SND_ASYNC);
}

public void PlayWavResourceYield(string wav)
{
string s = GetWavResource(wav);
PlaySound(s, IntPtr.Zero, SND_ASYNC | SND_NOSTOP);
}

TempFileCollection tempFiles = new TempFileCollection();

private string GetWavResource(string wav)
{
//TODO: Is this valid double-check caching?
string retVal = null;
if (cachedWavs.ContainsKey(wav))
retVal = cachedWavs[wav];
if (retVal == null)
{
lock (cachedWavsLock)
{
// get the namespace
string strNameSpace = Assembly.GetExecutingAssembly().GetName().Name;

// get the resource into a stream
using (Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + wav))
{
string tempfile = System.IO.Path.GetTempFileName();
tempFiles.AddFile(tempfile,false);
var bStr = new Byte[str.Length];
str.Read(bStr, 0, (int)str.Length);
File.WriteAllBytes(tempfile, bStr);
cachedWavs.Add(wav, tempfile);
return tempfile;
}
}
}
return retVal;
}

It's coarse, but it works, and now I can move on to some cleanup with this bug behind me. The Back to Basics lesson for me is:

  • Don't forget there is a Garbage Collector out there, doing just that.
    • It's easy to forget all about it, but it's so important to know who has a finger on your memory when you're moving back and forth over the unmanaged/managed boundary.
  • Edge cases are no fun.
    • There are always edge cases, race conditions and deadlocks to be found, and I'm sure I've got more left to find! (notice my lack of surety around the lock() call in the comments?)
    • Know your patterns for best practices or, better yet, know where to go to find the answers.
  • Your software typically runs exactly as you wrote it.
    • Even though this was a GC doing something I didn't expect, it was doing its job with the code I provided it. Given how I was using the byte array, it's very deterministic in its behavior.
  • Know what's going wrong before you try to fix it.
    • Once I understood the bug, I was able to reproduce the bug much more easily. "Flakies" are scary, but Bugs are just bugs. If I tried to fix it without understanding it, I'd just be programming by coincidence. (And I may still be! That's the rub.)

Have a nice day!

Technorati Tags: ,,

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.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.