0 Comments

I went to the free DDDSW developer conference on Saturday in Bristol which was excellent. Kudos to all the organisers and speakers and sponsors who made it happen.

One of the sessions I attended though stood out because the speaker, although apparently experienced, had a pretty tough time, especially with some of the comments submitted to an audience feedback web app being used by attendees at the conference. But actually I found myself agreeing with many of the sentiments of these comments (as did the person I sat next to) and felt the session didn't go well, although it actually contained some great content. Here’s my take on it.

Starting a session by saying how tired you are and how you haven’t slept for days is effectively saying: “sorry, this might be a bit shit”. You may feel justified in saying this because you are delivering the session for no fee and indeed may have incurred substantial expense in traveling to the conference. Nobody cares. It rubs your audience up the wrong way because they also may have incurred considerable expense in getting there too. In fact it’s their free time you’re saying you may be about to waste. They may start to feel their time would have been better spent in another session. Also, consider that your slot at the conference may have been at the expense of someone else, maybe a newbie who would have loved their first opportunity in the spotlight.

Doing too many “hands up if you...” audience questions can get tedious quickly. Indeed, don’t continually ask people to put their hands up if you’re going to say they’re wrong. It might be OK once, but more than that and people are going to feel uncomfortable and antagonised.

If someone walks out, ignore it. Making a point of it makes you look petty. Just maybe they actually had valid reasons for leaving, or indeed, maybe they weren’t enjoying the session. Just let it go.

Finally, there’s a distinction between being “passionate and opinionated” and coming across as a blowhard.

4 Comments

With the release of IronJS 0.2, the code below is the result of a 30-minute play I had this morning, which shows how easy it is to embed a fully .NET JavaScript runtime in your application by simply referencing IronJS.dll.

It’s changed quite a from prior versions and I think you’ll see it has become much easier to host since  Dan Newcombe’s experiments last year.

//reference IronJS.dll
using System;
using System.IO;

class IronJsDoodles
{
    static void Simple()
    {
        var context = new IronJS.Hosting.CSharp.Context();
        object result = context.Execute("1 + 2;");

        Console.WriteLine("{0} ({1})", result, result.GetType());
        // "3 (System.Double)"
    }

    static void InteractingWithGlobal()
    {
        var context = new IronJS.Hosting.CSharp.Context();

        context.SetGlobal("a", 1d);
        context.SetGlobal("b", 2d);
        context.Execute("foo = a + b;");

        double foo = context.GetGlobalAs<double>("foo");

        Console.WriteLine(foo);
        // "3"
    }

    static void AddingHostFunctions()
    {
        var context = new IronJS.Hosting.CSharp.Context();

        // Effectively the same as context.CreatePrintFunction() :-)
        var print = IronJS.Native.Utils.createHostFunction<Action<string>>(context.Environment,
            delegate(string str)
            {
                Console.WriteLine(str);
            });
        context.SetGlobal("print", print);

        context.Execute("print('Hello IronJS!')");
    }
}

Hope it helps you get started.

0 Comments

While working from home I was trying to use MSDeploy (aka Web Deploy, or the Publish Web command in Visual Studio 2010) to update an internal site. Whilst this would work perfectly when I was physically in the office, when working from home via the VPN it would fail with the following error:

Remote agent (URL http://myserver.example.com/MSDEPLOYAGENTSERVICE) could not be contacted.  Make sure the remote agent service is installed and started on the target computer.
An unsupported response was received. The response header 'MSDeploy.Response' was '' but 'v1' was expected.
The remote server returned an error: (400) Bad Request.

To see what was going on I started Fiddler and tried the publish again. (One crucial thing I had to do for Fiddler to capture traffic when connected via the VPN was to fully qualify the machine name, so instead of http://myserver, use http://myserver.your-corp.net as the service URL, otherwise it didn’t capture the traffic.)

This is what the exchange looked like:

POST http://myserver.example.com/MSDEPLOYAGENTSERVICE HTTP/1.1
MSDeploy.VersionMin: 7.1.600.0
MSDeploy.VersionMax: 7.1.1042.1
MSDeploy.RequestUICulture: en-US
MSDeploy.RequestCulture: en-GB
Version: 8.0.0.0
MSDeploy.Method: Sync
MSDeploy.RequestId: fde03509-b23e-4759-9353-e8dbf19a2293
Content-Type: application/msdeploy
MSDeploy.ProviderOptions: H4sIAAAAAAAEAO29B2AcSZYlJi9tynt...
MSDeploy.BaseOptions: H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvV...
MSDeploy.SyncOptions: H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvV...
Host: myserver.example.com
Transfer-Encoding: chunked
Expect: 100-continue
...

And in response:

HTTP/1.1 400 Bad Request (The HTTP request includes a non-supported header. Contact your ISA Server administrator.)
Via: 1.1 IBISA2
Connection: Keep-Alive
Proxy-Connection: Keep-Alive
Pragma: no-cache
Cache-Control: no-cache
Content-Type: text/html
...

There in the clear was the crucial error information that MSDeploy was failing to relay: those whacky MSDeploy HTTP Headers were being blocked by our ISA Server. (Note to the developers of MSDeploy: showing this information in debug or verbose modes would be very useful!)

After specifying an access rule on the ISA server to not filter proxied requests to the server in question based on HTTP headers, it all started working again.

3 Comments

Using the scaffolding in MVC makes it easy to knock up CRUD applications without too much difficulty. Typically you end up with something like this – note the PascalCase field names taken straight from the model generated by Html.LabelFor:

camelcase before

So now the obvious thing is to add DisplayName attributes metadata to your model, for example:

[DisplayName("Assigned To")]
public int AssignedToId { get; set; }

[DisplayName("Customer Name")]
public string CustomerName { get; set; }

Meh, donkey work. In most cases it just needs better default labels in the absence of explicit DisplayName annotations. Nine times out of ten field names such as AssignedToId and CustomerName would be simply expanded to Assigned To and Customer Name. (Of course, they don’t do this out of the box because these simple rules wouldn’t hold true for all languages.)

In MVC you can hook into the metadata discovery/generation process by implementing a ModelMetadataProvider, the default one of which is the DataAnnotationsModelMetadataProvider. So all I did was inherit from the latter and override the GetMetadataForProperty method and if no DisplayName has been specified on the model, create one based on the model’s camel-cased property name.

class MyFabulousModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
   // Uppercase followed by lowercase but not on existing word boundary (eg. the start)
   Regex _camelCaseRegex = new Regex(@"\B\p{Lu}\p{Ll}", RegexOptions.Compiled);

   // Creates a nice DisplayName from the model’s property name if one hasn't been specified
   protected override ModelMetadata GetMetadataForProperty(
      Func<object> modelAccessor,
      Type containerType,
      PropertyDescriptor propertyDescriptor)
   {
      ModelMetadata metadata = base.GetMetadataForProperty(modelAccessor, containerType, propertyDescriptor);

      if (metadata.DisplayName == null)
         metadata.DisplayName = displayNameFromCamelCase(metadata.GetDisplayName());

      return metadata;
   }

   string displayNameFromCamelCase(string name)
   {
      name = _camelCaseRegex.Replace(name, " $0");
      if (name.EndsWith(" Id"))
          name = name.Substring(0, name.Length - 3);
      return name;
   }
}

Hook the provider up in Application_Start by assigning an instance of it to ModelMetadataProviders.Current.

It’s pretty effective I think:

camelcase after

Anything that isn’t quite right can be overridden simply my explicitly adding DisplayNames to the model.

2 Comments

TL;DR: No – it’s just SQL Profiler not telling you the entire truth.

In evaluating Entity Framework 4.1 (aka EF Code-First or “Magic Unicorn” Edition) I’ve been keeping an eye on what SQL it’s actually executing against SQL Server (how’s that for a leaky abstraction?). Here I saw something slightly worrying which was that it appeared that the client was logging in, executing a query and then logging out as seemingly indicated by the Audit Login and Audit Logout events:

image

The same thing happens without EF using basic SqlCommand queries. To tell you the truth I’d noticed this a while ago but hadn’t got round to investigating.

Rather than assume that connection pooling was broken on my machine, I had a hunch that SQL Profiler was somewhat misrepresenting what was really going on.

Indeed Markus Erickson on StackOverflow mentions the EventSubClass column you can add to SQL Profiler’s output to see if those Audit Logon/Logout events are actually connections being pulled from the pool or fresh connections.

Here’s how you show the EventSubClass column in SQL Profiler (I’m running SQL 2005 on this machine, I can only assume it’s similar on 2008):

  • Go to the Trace Properties window and switch to the Events Selection tab.
  • Click on the Show all columns checkbox
  • Scroll to the right and locate the EventSubClass column and check both checkboxes:

  • Then go to Organize Columns and move the EventSubClass column up so that it’s next to EventClass:

image

Now you can re-run your trace and hopefully be reassured that connection pooling after all is functioning correctly!

image

Hope that helps!