My new Visual Studio Dev workhorse: Macbook Pro
I'm just starting some new contract work that requires a bit more on-site than usual and instead of syncing up my various dev environments all the time, I decided that it's time for a new laptop. My current laptop is a 15" Powerbook G4. It's been a great machine, but for the past couple of years it's mostly been an expensive Email/Browser appliance with the occasional Eclipse/Java diversion.
This time I needed something to let me do VS.NET development and all the other MS related things that come across my path. Now, obviously my previous laptop choice shows i'm not impartial, but I certainly wasn't going to settle for less that what I had. I went through this last time as well and the conclusion is not only the same, but decidedly more in favor of a Macbook this time around.
Go ahead, try it.. Find a laptop like this: slim profile, powerful CPU, large widescreen LCD, light and sturdy. By the time you find the PC equivalents, you don't get to be cheaper. And for some reason, PCs still come mostly in two flavors: 1) light and small screen or low power and 2) giant hulking powerhouses that are not that much more convenient than the original PC Portable's. Add to that, that I have yet to find another laptop that comes with a sturdy shell like the Macs -- If you look at some of the dents my old Powerbook has sustained, then you'd realize that I would have cracked open any plastic shelled laptop a long time ago.
Ok, enough with the rationalization already, buy your Mac, be a fanboy. Don't come whining when it can't cut it as your dev machine...
I have to admit that the last 3 days have included more reboots than I'd care to admit, but I finally have everything configured just right and I don't mind saying that this rig is freakin' sweet!
The setup is as follows: 15" 2.4GHz Core Duo Macbook Pro w/ 2GB RAM & 160MB HD. 140GB Leopard partition. 20GB bootcamp partition (short-sighted mistake on sizing) with Win XP Pro, Visual Studio Orcas, etc. Vmware Fusion 1.1 Beta running boot camp partition as VPC image under Leopard.
So what pitfalls have I come across?
Bootcamp was a pain to get going
Vmware fusion was just about the most painless windows install I've ever done. It asked me for the key before it started and took care of everything until it booted into XP. Bravo!
Boot camp on the other hand complained about my disk being corrupt (Brand new mac, mind you). Rebooted from CD, ran disk repair, was told there was nothing to repair. Tried boot camp again. Success! Started XP install on the formatted partition that boot camp set up. Got to the reboot early in the install, Mac rebooted, complained it couldn't boot from CD and the HD had errors, please press any key, but no keys produced results. Hard rebooted, ejected CD, tried to restart install via bootcamp, but same problem. Removed bootcamp partition, started over, this time manually formatting the disk during install to be sure. Some more issues aside, finally boot camp installed. Only then do I find out that VMware Fusion can use the boot camp partition as a virtual image. Now that's useful. Except I had sized it as the emergency fall back windows install. Doh.. Well, I'll just mount the Mac disk on the windows side for storage. Then all my files are inside the FileVault as well.
XP Activation with bootcamp/vmware fusion
After finding out I could use a single install as a full native and a virtual instance, I was thrilled and started up the bootcamp partition. VMware had to tweak it some, but it came up. XP Activation got invalidated because I apparently changed the hardware too much. Same happened when I rebooted into XP directly. Now it seems ok, but Redmond has received about 4 activations from the same XP install in 2 days. No, I'm not frantically installing on all my friend's PCs, I'm just trying to get one install stable.
Vmware Fusion Unity and Leopard Spaces have some issues
Now, I have no right to expect something as funky as Unity to work with an OS feaure that was released 4 days ago, so I'm not really bitching, just warning. For me using Unity and Spaces caused spaces to switch back and forth automatically at about twice a second several times when I had two Win windows in different spaces. And my Mac apps all lost their windows. So for now, XP runs fullscreen in its own Space and it's all wonderfully stable.
WPF likes hardware acceleration
So in the middle of the night I wake up in a panic. Everything was working so wonderfully, but had I missed something? Well, I kept saying
"i don't care that virtualization doesn't support the GPU, i'm not planning to play games on this machine". Hahaha.. But what about WPF? It uses the GPU to render all that fancy vector goodness! Did I just buy another email appliance? I fired up some WPF samples and it worked fine. As they got fancier, things got a bit choppier and the 3D was a slideshow. But work, it did. So, WPF gracefully falls back to software only mode. I rebooted into native XP and WPF was running in all its glory. Yay, all is good.
Ok, this is day 3 with my new rig and I'm very happy on both the Mac and Windows side. I even have a single dev machine that can test all browsers currently supported by Silverlight. And once Moonlight drops, I'll just fire up a VM of Fedora and cover that use case as well. Let's see if the euphoria lasts.
Labels: boot camp, macbook, vmware fusion, VS.NET
DynamicProxy rocks!
Recently, I've had a need to create proxy objects in two unrelated projects. What they had in common was that they both dealt with .NET Remoting. In one it was traditional Remoting between machines, in the other working with multiple AppDomains for Assembly flexibility. In both scenarios, I had a need for additional proxies other than the Remoting created Transparent proxy and the
Castle project's
DynamicProxy proved invaluable and versatile. It's a bit sparse on documentation, but for the most part, you should be able to figure things out by playing with it and lurking around their
forum.
If you're not familiar with the Castle project, check it out, because DynamicProxy is really only a supporting player in an excellent collection of useful tools. From their Inversion of Control Containers MicroKernel/Windsor to MonoRail and ActiveRecord (built on NHibernate), there is a lot there that can make your life easier.
But why would I need to create proxies, when the Remoting infrastructure in .NET takes care of this for you with Transparent Proxies? Well, let me describe both scenarios:
Resilient Client/Server operations with Remoting
From my experience with .NET Remoting, it's dead simple to do something simple. But it really is best suited for WebService stateless calls, because there isn't a whole lot exposed to add quality of service plumbing. The transparent proxy truly is transparent until something fails. Same is true on the server side, where you don't get a lot of insight into the clients connected to you.
And then there are events, which, imho, are one of the greatest thing about doing client/server programming with Remoting. Those are painful in two ways, having to have a MarshalByRefObject helper proxy the event calls and pruning dead clients on the server which you won't find out about until you try to invoke their event handler.
But those shortcomings are not enough reason to fall back to sockets and custom/stateful wire protocols. Instead I like to wrap my transparent proxy in another proxy that has all the plumbing for maintaining the connection, pinging the server and intelligently handling failure. Originally I created them by hand, but I just converted my codebase over to use DynamicProxy the other day.
Using CreateInterfaceProxyWithoutTarget and having the proxy derive from my plumbing baseclass automagically provides me with an object that looks like my target interface by wraps the Remoting proxy with my quality of service code.
public static RemotingClient<T> GetClient(Uri uri)
{
Type t = typeof(T);
ProxyGenerator g = new ProxyGenerator();
ProxyGenerationOptions options = new ProxyGenerationOptions();
options.BaseTypeForInterfaceProxy = typeof(RemotingClient<T>);
RemotingClient<T> proxy =
(RemotingClient<T>)g.CreateInterfaceProxyWithoutTarget(
t, new Type[0], options, new ProxyInterceptor<T>());
proxy.Uri = uri;
return proxy;
}
I'll do another post later just on Remoting, since the whole business of getting events to work was a bit of a labor and isn't documented that well.
Loading and unloading Assemblies on the fly
The second project started with wanting to be able to load and unload plug-ins dynamically and has now devolved into a framework for auto-updating components of an App at runtime.
This involves loading the assemblies providing the dynamic components into new AppDomains, so that we can unload the assemblies again by unloading the AppDomain. Instances of the components class are then marshaled across the AppDomain boundary by reference so that the main AppDomain never loads the dynamic assembly. This way, when a component needs to be updated, I can dump that AppDomain and recreate it.
The resilience of the connection isn't in question here, although there is need for quite a bit of plumbing to get references to the remoted components disposed before the AppDomain can be unloaded. Again, a DynamicProxy can help on the main AppDomain side by acting as a facade to the actual reference, so that you can reload the underlying assembly and recreate the reference without the main application having to be aware of it.
But I haven't gotten that far, nor have I decided whether that would be the best way, rather than an explicit disposal and recreation of the references.
Where DynamicProxy comes to a rescue here is when your object to be passed across the boundary isn't derived from MarshalByRefObject. This could be a scenario, where you are trying to use a component that's already derived from another baseclass, so adding MarshalByRefObjectisn't an option. Now DynamicProxy with its ability to provide a baseclass for the proxy gives you a sort of virtual multiple inheritance.
This is also an ideal scenario for using Castle.Windsor as the provider of the component. Using IoC, I was able to create a generic common dll that contains all the interfaces as well as a utility class for managing the components that need to be passed across the boundary, this class never has to know anything about the dynamic assembly, other than that the assembly stuffs its components into the AppDomain's Windsor container.
The resulting logic for creating an instance that can be marshaled across AppDomain boundaries looks something like this:
public T GetInstance<T>()
{
Type t = typeof(T);
if (!t.IsInterface)
{
throw new ArgumentException("Type must be an interface");
}
try
{
T instance = container.Resolve<T>();
if (typeof(MarshalByRefObject).IsAssignableFrom(instance.GetType()))
{
return instance;
}
else
{
ProxyGenerator generator = new ProxyGenerator();
ProxyGenerationOptions generatorOptions = new ProxyGenerationOptions();
generatorOptions.BaseTypeForInterfaceProxy = typeof(MarshalByRefObject);
return (T)generator.CreateInterfaceProxyWithTarget(t, instance, generatorOptions);
}
}
catch (Castle.MicroKernel.ComponentNotFoundException)
{
return default(T);
}
}
All in all, DynamicProxy is something that really should be part of the .NET framework. Proxying and Facading patterns are just too common to only support them via the heavier and MarshalByRefObject dependent remoting infrastructure.
The version of DynamicProxy I was using was DynamicProxy2, which is part of the Castle 1.0 RC3 install. It's a lot more versatile than the first DynamicProxy and deals with generics, but mix-ins are not yet implemented in this version. However, if you just need a single mix-in, specifying the base class for your proxy can go a long way to solving that limitation.
Labels: AppDomain, Castle, Dynamic Proxy, IoC, Remoting