Thursday, February 21, 2013

INotifyPropertyChanged: Worst. Interface. Ever

As any .Net UI developer will tell you, INotifyPropertyChanged is a fundamental part of 'binding' an object to a UI control. Without it binding is essentially one-way: changes in the control change the object, but if this has a ripple effect on other properties, or properties are changed by other 'below the UI' processes, the UI can't know to repaint. This is essentially an implementation of the Observer pattern[1].

Unfortunately it's not for free - you have to implement it yourself - and that's where the problems start. So much has been written on the pain of implementing INotifyPropertyChanged (INPC for short) that I need not repeat it all here. It's generated so many questions on StackOverflow you'd think it's due its own StackExchange site by now.

The principal complaints are around all the boilerplate code and magic strings required to implement, so for the sake of completeness I'll summarize some of the solutions available:

Pick one of these, stick with it and you're done. Ok, there's still a bit of griping about separation of concerns, and whether this is an anti-pattern, but you're done right?

No.

It's so much worse than that.

Do you remember the first time you implemented GetHashCode(), and later when you realized you'd done it wrong? And later when you really realized you'd done it wrong, that there was no good way you could override Equals() for a mutable object, and the sneaking realization that this whole problem existed only for the benefit of Hashtables? It's a bit like that.

What we have with INotifyPropertyChanged is an implicit contract, that is to say that a large part of the contract can't be formally defined in code. Which means you have to validate your implementation manually. In this case the implicit bit is about threading. INotifyPropertyChanged exists to support UI frameworks and (bizarrely, in this day-and-age) they are still single threaded, and can only execute on the thread that constructed them – including event handlers. Think about this a bit, and you will eventually conclude:
An object that implements INotifyPropertyChanged must raise the PropertyChanged event only on the thread that was originally used to construct any registered subscribers for that event

Now there's a problem[2].

Clearly this is something that's just not possible to check for at runtime, so your design has to cater for this. Passing objects that might have been bound to business logic that might mutate them? UI thread please. Adding an item into a collection that might be ObservableCollection? UI thread please. Doing some calculations in the background to pass back to an object that may have been bound? Marshal via UI thread please. And so on. And don't even get me started on what you do if you have two (or more) 'UI' threads[3].

This is a horrible, horrible creeping plague of uncertainty that spreads through your UI, where the validity of an operation can't be determined at the callsite, but must also take into account the underlying type of an object (violating polymorphism), where that object came from (violating encapsulation), and what thread is being used to process the call (violating all that is sacred). These are aspects that we just can't model or visualize well with current tooling, at least not at design time, and none of the solutions above will save you here.

So there you go. INotifyPropertyChanged: far, far worse than you imagined.


[1] ok, any use of .net events could be argued is Observer, but the intent here is the relevant bit: the object is explicitly signalling that it's changed state.
[2] Actually I've over-simplified, because you can have whole chains of objects listening to each other, and if any one of them is listened to by an object with some type of thread-affinity, that's the constraint you have to consider.
[3] Don’t try this at home. There are any number of lessons you’ll learn the hard way.

Wednesday, February 20, 2013

Crazy reference leakage using extension methods and generics

It appears that if you have an extension method, that is in-scope (i.e. namespace included), even if you don't use it you have to reference all the assemblies that are part of the generic type constraint.

This kinda sucks.

Normally if you use a type from another assembly, and that type has as part of its interface another type in another assembly, you have to reference both assembly. Fine. But only if you use it.

eg: if you reference assembly 'Animal' and use a class 'Cow' that has a property 'Color', and the type of Color is defined somewhere else (System.Windows.Forms) you have to reference that too. But if you get the cow via the IBovine interface, and that doesn't expose Color, you don't need the reference (at least not statically).

If, however, in the same namespace, there's an extension method that you're not using, and that extension method has some type constraints, you have to reference all the assemblies for all the type constraint parameters.

For example, if you put this in one assembly, in a namespace you merely import:


  public static class NotUsed{
        public static void DefinatelyNotUsed(this TContext context, Action thing)
            where TContext : DataContext
        {
            
        }
  }
... then you'll also have to pull in System.Data.Linq to get the 'importing' assembly to compile.

Doesn't this strike you as odd? I'm sure I can hear a gestalt Eric Lippert in my head explaining why, but I was certainly surprised.

Get-Member on empty collections

PowerShell's pipeline just loves to unravel collections, with the result that sometimes, when you want to do something on the collection itself, you can't. Like with Get-Member:
$blah.Catalogs | Get-Member Get-Member : No object has been specified to the get-member cmdlet.
What happened? Did $object.Catalogs return null, or did it return an empty IEnumerable? This has bitten me a few times, especially when poking around in an API for the first time (ie: at this point I have no idea what 'Catalogs' is, whether it's ICollection or whatever).

The answer, I realize, is to avoid the pipeline:
Get-Member -inputObject:$blah.Catalogs TypeName: BlahNamespace.BlahCollection Name MemberType Definition ---- ---------- ---------- Add Method System.Void Add(Microsoft.SqlServer.Management.IntegrationSer... Clear Method System.Void Clear()
Much better

Monday, February 04, 2013

SQL 2012 Data Tier Applications explained

You: So what are these DACPAC things then?
Microsoft:
"A DAC is a database lifecycle management and productivity tool that enables declarative database development to simplify deployment and management. A developer can author a database in SQL Server Data Tool database project and then build the database into a DACPAC for handoff to a DBA"
http://msdn.microsoft.com/en-us/library/ee210546.aspx 

You: Hey, that sounds familiar. How is that different from Visual Studio 2010 Database Edition aka DataDude aka GDR aka VSDBCMD.exe?
Microsoft: They're, like, totally different ok.

You: How so?
Microsoft: Well they just are. DACPACs replace all that GDR stuff. That was just crazy stuff the Visual Studio guys came up with you know. This is the real deal from the SQL product team. And we can package data too, in BACPACs.

You: Awesome. So this'll solve that problem about also upgrading reference data when I push out a new version of the schema?
Microsoft: Oh no. BACPACs can't be used to upgrade an existing database instance. Just to load data into new databases. They're for moving databases between servers.

You: Like a backup
Microsoft: Exactly like a backup, yes.

You: ...so... can't you just use a backup?
Microsoft: No. DACPACs and BACPACs don't just contain the database. They encapsulate the whole data tier application, so they include other items you'd need to deploy, like logins.

You: Cool. And agent jobs as well I guess?
Microsoft: Oh no. Just logins and ... well logins anyway. Try doing that with GDR. And you wouldn't be using sql_variant anyway would you? No.

You: Come again?
Microsoft: Oh nothing.


The author notes this conversation was imaginary, and any resemblance to reality is entirely coincidental

Tuesday, January 08, 2013

The Windows RT desktop. For why?

I still don't understand Windows 8 RT (aka Microsoft Surface, aka Windows on Arm), or more specifically it's desktop mode.

On Windows 8 Pro (the x86 version) it all makes sense: desktop mode opens the door to all the 'legacy' apps you know and love, whilst the device itself weans you onto the world of RT/store apps. As an enterprise developer you can target either, most likely running existing corporate apps on the desktop whilst mulling the trade-offs (and $) involved in rewriting the front end to target Metro.

But on Arm it's crippled: running only Microsoft-sanctioned apps (Office, Notepad and explorer) without jailbreaking. Why?

Clearly you can't expect it to run existing x86 apps, but for enterprise developers working in .Net this is a slap in the face. You're barred from running existing .net 4 desktop apps on the Surface RT desktop, and you can't build desktop apps using the Win RT runtime either.

This is a crazy situation that smacks of half-baked.

If the desktop mode on Arm is useful - and I'd argue it is - it should be possible for more than just Microsoft to write for it. Ideally enterprises could run existing .Net apps unmodified, but there's clearly advantages (re: capability, performance and battery life) in encouraging them to embrace the Win RT APIs.

Conversely if the desktop mode is redundant, Microsoft need to seriously pull their finger out replicating all that functionality in the Metro interface, including a Metro version.

I would like for the former to be the case. I suspect Microsoft's roadmap is the latter, that the desktop's just there till Office gets ported proper. Whichever way, we have a ridiculous situation where if an enterprise developer wants to target Windows 7 and both Windows 8's they have to ... write a web app. Way-to-go Microsoft![1]

I keenly await Xamarin's Mono-Surface[2], which will let you run .Net apps on the Microsoft Platform. Now that would be progress.


[1] Sure they gave the enterprise the finger with the phone too. I guess we shouldn't be surprised. But perhaps this is just Sinofsky's 'my way or the high way' showing through
[2] This is a fictitious product, and any resemblance to actual products planned or otherwise is entirely coincidental

Tuesday, October 23, 2012

Avoid XmlConvert.ToString(DateTime)

XmlConvert is the utility class that controls fundamental .Net data types being converted to/from their XML representations. For dates, the DateTimeOffset overloads are less ambigious than the DateTime ones, and as a result the latter have been depricated. But you'd still expect it to basically work for the fundamental scenarios.

Nope. For DateTimeKind=UTC dates, it's totally broken.

Ttry this (in Linqpad):



	var localTime = DateTime.Now;
	var utcTime = localTime.ToUniversalTime();
	
	localTime.Dump("Local Time");
	utcTime.Dump("UTC time");
	utcTime.Kind.Dump("UTC Kind");
	utcTime.ToString("yyyy-MM-ddTHH:mm:ss K").Dump("Expected XML");
	XmlConvert.ToString(utcTime).Dump("Actual XML from XML Convert");

Gives:

Local Time 23/10/2012 11:11:11 AM
UTC time 23/10/2012 3:11:11 AM
UTC Kind UTC
Expected XML 2012-10-23T03:11:11 Z
Actual XML from XML Convert 2012-10-23T03:11:11.0773940+08:00


You'll notice immediately (because of the highlighting), that it's done something really really dumb. It's made out that the UTC time is actually a local time in my local timezone offset (+8). It's screwed up the XML representation, and as a result changed the actual time value being passed, even though it knows (based on DateTime.Kind==DateTimeKind.Utc, that the ToUniversalTime() method always gives you) that it's a UTC date.

This is because internally that method does this:

[Obsolete("Use XmlConvert.ToString() that takes in XmlDateTimeSerializationMode")]
public static string ToString(DateTime value)
{
    return XmlConvert.ToString(value"yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz");
}

...and those z's add the local timezone offset from your PC. This is wrong for a DateTime with Kind=UTC. A better implementation would be as per my example above, ie:

    return XmlConvert.ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffK");

The K specifier is not so dumb, and adds the time zone to local time datetime instances, and adds the Z to UTC instances. Or alternatively an if{}else{} based on value.Kind==DateTimeKind.UTC.

Anything but what it does right now.

Why do I care? Well WCF generates webservices proxies using DateTime, not DateTimeOffset, so I want to make damn sure it's not making the same mistake.

Monday, September 17, 2012

Nuget Package Restore with internet-restricted build servers

The first time I enabled nuget package restore I had a nasty shock: the TeamCity build server didn't have internet access (and wasn't getting any).

I initially went back to storing-packages-in-source-control, but when I created a spike ASP.Net MVC 4 project, which wanted to add some 30 packages, I decided I needed to address the root problem.

A few people suggested I should setup a local nuget repository, the simplest version of which is just to dump all the packages you need into a file share. But how to point the build server at the share, rather than the standard nuget feed URL? Short of logging in as the build server user and changing the settings through Visual Studio (lame), there appear to be a couple of ways:

Editing %appdata%\nuget\nuget.config (for the build server user)

This achieves the same as the above, but you don't have to log in as that user. It's reliable, but because it doesn't 'carry' with the solution in source control it's brittle (needs doing again if the build server user changes etc...) and you can't vary it on a project by project basis, which is a bit limiting.

Editing the generated nuget.targets file that package restore adds to your solution

This looks like the go, and even has comments in there to show you what to change. But I didn't find this reliable. On my local machine (under a no-internet user) this worked just fine, but on my build server I kept having package resolution errors (from a Silverlight 4 project).

Setting the PackageSources build parameter

What the above did show is what MSBuild properties are involved, so I was able to specify that property on the MSBuild command line and that seems to work consistently:
MSBuild mysolution /p:PackageSources=\\server\fileshare
...now finally I have a green light on TeamCity and can go and do something actually productive instead.

Tuesday, July 17, 2012

Creating SQL Credentials for Network Service account

It’s fairly normal in production environments to find the SQL Server configured to disallow use of the SQL Agent account for the execution of certain types of job steps: SSIS packages and CmdExec for example. Instead you have to configure an explicit SQL Agent proxy, which requires first storing credentials within SQL’s credential store.

For domain accounts this is fairly straightforward, but if you attempt to add credentials from one of the ‘virtual accounts’ (such as Network Service), you’ll get the following error: “The secret stored in the password field is blank”

image

The solution is (eventually) obvious: add the credential using TSQL (or SMO), and avoid the UI validation:

USE [master]
GO

CREATE CREDENTIAL [Network Service] WITH IDENTITY = N'NT AUTHORITY\NETWORK SERVICE'
GO

et, voila:

image

Saturday, May 26, 2012

vsdbcmd 'built by a runtime newer than the currently loaded runtime and cannot be loaded'

When deploying the latest version of our application to the Production server we got this error:
Unhandled Exception: System.BadImageFormatException: Could not load file or assembly 'vsdbcmd.exe' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded. File name: 'vsdbcmd.exe'
Oh god, I thought. Yet more VSDBCMD wierdness. But this box had SQL Server installed, so the normal 'needs SMO / Batch Parser' caveats didn't apply. Eventually I ILSpy'd the assemblies to check the bittyness, and guess what! The error message was completely accurate. I'd accidentally picked up the VSDBCMD not from the VS 2008 folder (9.0) but instead from the VS 2010 folder (10.0). Which is .Net 4. Which really is a more recent version of the runtime than was installed on the Windows 2008 R2 server. Embarrasing to be caught out by a completely accurate error message (though if it listed the versions involved I might have paid attention)

Thursday, May 17, 2012

Analysis Services 2008 R2 breaking change when deploying from the command line

As collegues of mine will attest, I will script anything that has to be deployed. Some things are easier than others.

In the case of Analysis Services, the .asdatabase file that comes out of the build needs to be futher transformed to create the XMLA that you need to run on the server to deploy your (updated) cube definition. Rather than attempt to replicate this transformation, I have previously chosen to get the Analysis Services deployment utility to do this for me, since this can supplied with command line arguments:
write-host "Generating XMLA"
$asDeploy = "$programfiles32\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\Microsoft.AnalysisServices.Deployment.exe"
& $asDeploy "$pwd\..\bin\MyCube\MyCube.asdatabase" /d /o:"$pwd\MyCube.xmla"
Which works just nicely. Except when we migrated that project to SQL 2008 R2, when it stopped working.

Well, actually that's not true. We'd been deploying to a 2008 R2 server for ages, it was when we changed the deployment script to use the 2008 version of the deployment tool that it all broke.

Basically the next line in the script kept complaining that 'MyCube.xmla' didn't exist, but I'd look in the folder after the script had run and the file was there. So it seemed like maybe there was a race condition.

Which there was.

If you examine the PE headers for the Sql 2005 version of the deployment util (using a tool like dumpbin) you'll see it's marked as a command line application:

C:\>dumpbin /headers "C:\Program Files (x86)\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\Microsoft.AnalysisServices.Deployment.exe" | find /i "subsystem"
            4.00 subsystem version
               3 subsystem (Windows CUI)


...but the 2008 R2 version is marked as a gui application:
C:\>dumpbin /headers "C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.AnalysisServices.Deployment.exe" | find /i "subsystem"
            4.00 subsystem version
               2 subsystem (Windows GUI)

What? Can't see the difference? One is marked CUI with a 'C', the other is GUI with a 'G'. An unfortunately high degree of visual similarity given what a fundamental difference it makes: launch the first from the command line and you wait for it, launch the second and you don't. When scripting it's pretty important to know which one you've got, or you're going to get race conditiions.

In this case the answer was to control the process launching, so we can explicitly decide to wait:
     start-process -FilePath:$asDeploy -ArgumentList:$asdatabase,"/d","/o:$xmla" -Wait;
Maybe I should just do that all the time to be safe, but just being able to use other command line tools within a script without a whole lot of ceremony is one of the really nice bits about powershell, so I tend not to. In this case the launch semantics of an existing utility changing between versions seems like a really nasty thing to be caught out by.
Good reference sources:
Stack Overflow: Can one executable be both a console and GUI app?
MSDN: A Tour of the Win32 Portable Executable File Format

Monday, May 07, 2012

Sql 2008, virtual accounts and a breaking security change from 2005

Interesting gotcha today regarding the different ways Sql 2005 and Sql 2008 grant permissions to the service account they are running under. Interesting, because the differences broke my app, and exposed my complete lack of understanding of a key Windows 2008 R2 security concept - virtual accounts.
In Sql 2005, to simplfy management of the service account's permissions against SQL itself (specifically with regard to changing which account SQL is running under) the product team started creating local Windows security groups, of the form:
computername\SQLServer2005MSSQLUser$computername$MSSQLSERVER
This group is configured by the installer to contain the service account (eg Network Service), and a corresponding SQL login is created (for the windows group) granting sysadmin rights:


I'm a big fan of running services as Network Service. Not having to create explicit service accounts means less admin overhead (both creation, and password expiry maintanance) and a lower overall attack footprint for your enterprise. But there is a downside - a lack of permissions isolation between services also running as Network Service on the same box. In this case, because of the above, anything else on that box that runs as Network Service is automatically sysadmin on your SQL instance.

In Sql 2008 on Windows 2008 R2 the situation is a bit different, because Windows 2008 R2 introduces so-called virtual accounts. I'm still a bit hazy on these, but one of the things this enables you to do is grant permissions to a service without knowing which account it's running under. The actual permissions the service has at runtime are then the union of permissions explicitly granted to the service account as well as the permissions granted to the service itself.
Which is cool. If a bit freaky at first.
So whilst Sql 2008 still has one of those local Windows groups created for it's service accounts, the contents of this are now, somewhat tautologically:

NT SERVICE\MSSQL$SQL2008

...and at the database level, the group is actually ignored, and the login (and SA grant) is given directly to itself, not the group:


(note: i've got SQL 2008 as a non-default instance, hence the specific naming. But you get the idea).

What does all this mean? Put simply (and somewhat recursively):
  • Only the SQL 2008 service itself is setup as an adminstrator on the SQL 2008 service. The principal (service account) that runs it is not - by itself - an administrator on that instance.
  • It is no longer the case that other applications running under the SQL Server service account are sysadmins on any SQL instances running under those same credentials.
It was the second bullet that broke my app. This is illustrative of poor original design, for sure, but giving Analysis Service carte blanche over the SQL instance on that same box seemed like a fairly safe call originally. But it exposed a really cool security improvement in Windows 2008 R2.

In this case the problem is the solution: I can just go an add a grant for the virtual service account for Analysis Services, give it enough SQL permissions to do what it needs and the problem goes away.

More on virtual accounts from the Sql 2012 doco, and from Technet articles Managed Service Accounts (MSAs) Versus Virtual Accounts in Windows Server 2008 R2 and What's New in Service Accounts

Sunday, November 20, 2011

Gotchas with the Kinect SDK for Windows

Playing with the Kinect SDK for Windows, and having a ball, but the doco is (understandably) a bit rubbish in places, or to be more specific – lacks critical details around the form that a parameter takes, where that detail is important.

Anyway, this is my list of gotchas so far:

Depth Data Inverted when Player Index tracking enabled

Bizarrely, whether you initialize and open your depth image stream with ImageType.Depth or ImageType.DepthAndPlayerIndex makes the difference between whether what you get is ‘right way round’ or horizontally inverted.

Inverted is generally more useful, because it matches with the ‘mirror image’ video stream. So why isn’t the stream like that always? Seems like an unnecessary inconsistency to me, and one you might want to spell out in the doco.

Different Depth Data Pixel Values when Player Index Tracking Enabled

When you do turn player index tracking on, the depth stream ‘pixels’ are lshifted 3 positions, leaving the lower 3 bits for the player index. This is documented, and I understand you’ve got to put the player index somewhere, but why not make the format consistent in both cases, and just leave the lower bits zero if tracking not enabled? Better still, why not put the (optional) player index in the high bits?

This is especially irritating because...

GetColorPixelCoordinatesFromDepthPixel() Requires Bit-Shifted Input

The nuiCamera.GetColorPixelCoordinatesFromDepthPixel() mapping method expects the ‘depthValue’ parameter to be in the format it would have been if you had player tracking enabled. If you don’t, you’ll have to lshift 3 places to the left yourself, just to make it work. So depending on how you setup the runtime, the pixels from one part of the API can or can’t be passed to another part of the API. That’s poor form, if you ask me.

Not that you’ll find that in the doco of course, least of all the parameter doco.

No GetDepthPixelFromColorPixelCoordinates Method

Ok, so I understand that the depth to video coordinate space translation is a lossy one, but I still don’t see why this method doesn’t exist.

I picked up the Kinect SDK and the first thing I wanted to do was depth-clipping background removal. And the easy way to do this is to loop through the video pixels, and for each find the corresponding depth pixel and see what its depth was. And you can’t do that.

Instead you have to loop through the depth pixels and call the API method to translate to video pixels, but because there are less of them compared to the video pixels, you have to paint them out as a 2x2 block, and even then there’ll be lots of video pixels you don’t processes, so many you have to run the loop twice: once to set all the video pixels to some kind of default state, and once for those that map to depth pixels to put the depth ‘on’.

Just didn’t feel right.

Thursday, September 22, 2011

Geolocation in HTML 5

Ok, so it’s not actually part of HTML 5 (the spec), but conceptually at least it’s definitely part of HTML 5 (the brand).

So what’s actually involved. Hmm. OH MY GOD IS IT THAT EASY !?
function showMap(position) {
// Show a map centered at (position.coords.latitude, position.coords.longitude).
}

// One-shot position request.
navigator.geolocation.getCurrentPosition(showMap);


[from the W3 geolocation spec]

So you just rock up to html5demos.com/geo and ...
image

Holy crap. I won’t show you the resulting map because it shows where I live. What’s really freaky about that is this netbook doesn’t have a GPS. So either Windows 7 or IE 9 has fallen back to IP-based location inference, and somehow still got me only one house out.

I’m totally freaked out.

Anyway, the point of all this is that IE 9 is the browser for Windows Phone 7.5 (Mango), which – if it actually supports this API (and Wikipedia says yes it does) - means you can write location-aware mobile apps targeting Mango without having to ‘go native’. And for the demo I want to put together, this can only be a good thing...

Thursday, September 15, 2011

Windows 8: First Impressions

Q: "Your first impression? Love or hate?"

Well that's a really good question.

I was always horribly dissapointed with my HP TX2 multitouch laptop, and whislt some of that was about the hardware (rubbish battery life, noisy fan), some of it was just how non-touch capable Windows 7 was to actually use. Windows Media Center achieves many of my 'media center kiosk' wants, but doesn't let me Skype or browse the web without dropping back to the desktop and so forth. Then you've got to go and find the mouse and all that crap. I realised that, like Media Center, a different usage type required a very different UI experience.

So in many ways what I was after was absolutely where Windows 8 is going. And (in the 30 mins I've actually played with it) I love it for that.

That being said, they're going to have to be really careful they don't throw the baby out with the bath water. Ok the desktop's still there for 'traditional' apps, but the Start bar is gone, as is apparently ALT-TAB task switching. And without a touch screen, that metro UI really sucks actually.

It'd be more than a shame if embracing a device/cloud future required ditching 10 years worth of desktop productivity, it'd be a Vista-scale corporate-desktop disaster.

Wednesday, September 14, 2011

Yes, Silverlight is Dead

Not exactly quick off the block predicting this, but I didn't want to rush to judgement. But yes, Silverlight is dead, on the desktop at least.[1]

Why? Reach. Silverlight was always going to be playing catchup to Flash, which took pretty much a decade, remember, to get ubiquity. Silverlight just didn't have time on its side. Today if you build an app in Silverlight you can target contemporary browsers on Windows/Mac. By contrast if you build it in HTML you can target Macs, Linux, iPods, iPads, Android, Windows Phone, Kindles, PS3... the list goes on.

To put Silverlight out to all those individual devices is going to take Microsoft a heap of time and effort. By contrast all of those devices have web browsers already, most of them pretty good ones, and getting better all the time.

It's a numbers game. The browsers finally won.

But can HTML realistically replace Silverlight? Absolutely. Not entirely, not today, but surprisingly close, and getting closer by the day. The foundations for mature, maintainable web-client development are finally being put down. And the tooling. Visual Studio 2010's javascript IntelliSense is pretty damn impressive, and already supports jquery for example. Add support for MVVM development (ala knockout.js) and you've got a decent development workflow to rival what you might be used to in WPF/Silverlight/Winforms land (we'll probably see more about this out of Build this week). And don't forget there's a JS version of RX.

Sure, browser-based javascript is somewhat limited compared to the Silverlight runtime. The touch support isn't quite there yet, for example. But it's more than enough to support UI interaction, and the gap's closing awfully fast.

As a developer who started in web, then moved to the desktop I'm really excited about all of this because I can see a future that finally blends the best of both worlds.


[1] I'll clarify before I get flamed: Silverlight is not dead today. I'll be starting a new project using it real soon actually. But the transition is going to be pretty abrupt. I'll be amazed if you start any new Silverlight projects next year.

Saturday, September 03, 2011

#AUTechEd 2011

The condensed version

Updated Links now point to Channel 9 site, where the videos will end up

Tuesday, August 23, 2011

IIS WebAdministration module failing with 80040154

Apart from the normal stuff about the IIS 7 powershell module failing because it's not registered, elevated or you've not allowed the execution of scripts in your powershell session, there's one more little gotcha:

Get-Website : Retrieving the COM class factory for component with CLSID {688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} failed due to the following error: 80040154.

...which is that the COM objects are only registered for x64 (if on an x64 machine), so if you're running a 32 bit PowerShell prompt (for various reasons related to VS GDR) you'll get the error above :-(

See http://stackoverflow.com/questions/3501001/windows-powershell-snap-in-for-iis-fails-on-32-bit for some unsavory workarounds, or just run as x64 if you want it to actually work :-(

What proxy is 'automatically detect settings' actually giving me?

Chrome doesn't seem to like the 'automatically detect settings' (at least not where I am right now), so I have to change over to have an explicitly configured proxy.

But what to enter? PowerShell to the rescue:

[System.Net.WebRequest]::DefaultWebProxy.GetProxy("http://www.test.com")

...tells you what proxy the system will use for the uri provided, and that's pretty much the only one you ever have to worry about.

Friday, August 19, 2011

Clustered Hyper-V Live Migration for $450

Well, ok, not counting the MSDN licence I had to play with this, but the point is thanks to the iSCSI support in Windows 2008 R2 (initiator and target), you can now build test clusters without having to have a ‘real’ (as in expensive) shared disk array, so you too can amaze your friends by live-migrating a virtual machine in front of their very eyes, or dispel your own lingering doubts that this stuff is all smoke and mirrors.

I used:

  • 3x old Dell Optiplex 745’s that we got for a song
  • A 100mb hub I borrowed from IT
  • Er… that’s it

Using the Microsoft iSCSI target for Windows Server 2008 R2, one box pretends to be a SAN. You could use Windows Storage Server, or a high-end NAS that supported iSCSI also.

The other two boxes I stuck Windows 2008 R2 with Hyper-V role. I could have used Hyper-V server. Using the out-of-the-box iSCSI initiator, I bound both of them to virtual drives I fronted up from the storage server, and after a few goes made a cluster.

I’m not going to do the blow by blow, because there’s actually a couple of really good posts on doing this:

…though you will have to wade through them a bit, because the landscape has been changing, but before you know (well, it took maybe a few days, on and off) you have a VM flitting from box to box like a sprite[1].

Couple of things I will mention:

  • The doco says you can’t do this with only one NIC per box, but you can. Wouldn’t want to in production, sure, but you can
  • Though experience I suggest that the safest course is to only have the quorum disk target attached when creating the cluster (and add more disks later). That’ll prevent the wrong disk being used as the quorum disk, which I couldn’t work out how to prevent otherwise
  • If you destroy the cluster (as I did, several times, when it kept getting the disks round the wrong way) and find your machines don’t talk to each other any more, try removing them from the domain and re-adding. Worked for me
  • If something doesn’t work, don’t be an idiot like me and later try exactly the same thing again and waste a whole day rebuilding everything. Try it a different way :-/

[1] The actual moment of cut-over took the VM out for about 4 seconds, which isn’t terrible considering the appallingly low-spec setup I was running: disk, heartbeat and client access all hitting one NIC though 100mb hub. It was only getting about 7Mb/s on the disk too.

Tuesday, August 16, 2011

Custom Folders in SQL Server Management Studio

It’s about bloody time, but it took a 3rd party to hack it together. This really should be out-of-the-box behaviour.

I like the way he’s used extended properties as the persistence medium, rather than, say, a table with a special name. It’s an approach I’ve used myself for other extensions to the standard schema metadata, like for my Upsert View Generator (which is long overdue an updated post).

Popular Posts