<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Database Consulting Group LLC Blog</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/" />
    <link rel="self" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog/atom.xml" />
   <id>tag:databaseconsultinggroup.com,2009:/blog/1</id>
    <link rel="service.post" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1" title="Database Consulting Group LLC Blog" />
    <updated>2009-11-07T07:44:49Z</updated>
    <subtitle>Observations, opinions, experiences and occasional rants about the software technology industry.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2ysb5-20051201</generator>
 
<entry>
    <title>Silverlight Popup positioning</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/11/silverlight_popup_positioning.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=32" title="Silverlight Popup positioning" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.32</id>
    
    <published>2009-11-07T07:26:44Z</published>
    <updated>2009-11-07T07:44:49Z</updated>
    
    <summary>I found myself frustrated recently with the positioning of Popups in Silverlight. I was surprised that web searches didn&apos;t seem to turn up accurate information, so I&apos;ll offer some things I&apos;ve found about Popups hoping I&apos;ll help those that find...</summary>
    <author>
        <name>Nathan</name>
        
    </author>
            <category term=".NET, WPF, Silverlight" />
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>I found myself frustrated recently with the positioning of Popups in Silverlight. I was surprised that web searches didn't seem to turn up accurate information, so I'll offer some things I've found about Popups hoping I'll help those that find themselves in similar circumstances (surely I'm not alone).&nbsp; The position of the popup seems to be based on the following parameters: </p><ul><li>The type of Parent (if parented)</li><li>The position&nbsp;within the Parent&nbsp;(if parented)</li><li>The VerticalOffset property</li><li>The HorizontalOffset property</li></ul><p>The Silverlight documentation gives the impression that you must always have the Popup parented in the visual tree, which I've found not to be the case.&nbsp; For instance, it seems to work to simply instantiate a Popup, set it's Child to some visual element, and set its IsOpen property to true.&nbsp; I'm releived this is the case, because requiring that the parent actually be in the visual tree of essentially a different layer is a little strange at best, and at worst can lead to circumlocution of the control hierarchy to accomodate such a hack.&nbsp; For instance, if a popup is to appear next to a control hosted by a content control, one would have to group the control into a panel in order to allow the popup, even though the popup doesn't have anything directly to do with the control's layout.</p><p>Anyway, if a Popup is not parented in a visual tree, the VerticalOffset and HorizontalOffset seem to work as published; namely, they represent the position of the top, left corner of the Popup relative to the&nbsp;global Silverlight coordinate system.&nbsp; This is, IMO, the preferred method for dealing with Popup positioning if your situation allows it.&nbsp; Otherwise, read on.</p><p>If the Popup is located in the &quot;main&quot; visual tree (ie&nbsp;isn't in the visual tree of another popup), the offsets are relative to that point within the visual tree.&nbsp; For instance, if a Popup is located in a StackPanel underneath a Button, the Popup will appear at the location it would appear at if the Popup's child were instead at that location.&nbsp; Well actually, that isn't completely precise, note that if the Popup's child were actually at the point the Popup appears, the surrounding layout might be affected by the size of the child.&nbsp; To the hosting layout, the Popup appears to occupy no space.&nbsp; However, the Popup's origin is not located the same as it would be if the Popup were treated as a 0 pixel object.&nbsp; If the popup is given more than isn't needed space (such as in the example case of the StackPanel with a button), the Popup seems to orient itself with the top, left of its given space.&nbsp; I have not experimented to see if this is only done in relation to the extent of the Popup's child size.&nbsp; </p><p>The situation is more complex, however if the Popup is hosted in the visual tree of another Popup, the offset is relative to the parent popup's coordinates.&nbsp; Not the parent popup's actual global coordinate, the parent popup's local coordinates.&nbsp; In order to ensure that a given popup appears where it actually should be relatively to the on-screen visuals, some parent walking is required.&nbsp; Here is what I've found to work:</p><p><pre>
var LPopup = FindParentPopup(this);
if (LPopup != null)
{
	var LParentPopup = FindParentPopup(LPopup);
	var LTransform = LPopup.TransformToVisual(LParentPopup == null ? null : LParentPopup);
	var LOrigin = LTransform.Transform(new Point(0d, 0d));
	Popup.VerticalOffset = LOrigin.Y;
	Popup.HorizontalOffset = LOrigin.X;
}
else
{
	Popup.VerticalOffset = 0d;
	Popup.HorizontalOffset = 0d;
}

<p>public static Popup FindParentPopup(DependencyObject AObject)<br />
{<br />
	var LParent = VisualTreeHelper.GetParent(AObject);<br />
	if (LParent != null)<br />
		return FindParentPopup(LParent);<br />
	else if (AObject is FrameworkElement && ((FrameworkElement)AObject).Parent is Popup)<br />
		return (Popup)((FrameworkElement)AObject).Parent;<br />
	else<br />
		return null;<br />
}<br />
</pre></p></p>]]>
        
    </content>
</entry>
<entry>
    <title>Migrating a Remoting Service to WCF</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/10/migrating_a_remoting_service_t.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=31" title="Migrating a Remoting Service to WCF" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.31</id>
    
    <published>2009-10-09T18:37:08Z</published>
    <updated>2009-10-09T18:39:47Z</updated>
    
    <summary>The Need To MigrateIn extending Dataphor to include a Silverlight client, one of the biggest changes that had to be made was the communication layer. Since its initial version, Dataphor has always used .NET Remoting as the primary communication technology....</summary>
    <author>
        <name>Bryn</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<h1>The Need To Migrate</h1><span>In extending Dataphor to include a Silverlight client, one of the biggest changes that had to be made was the communication layer. Since its initial version, Dataphor has always used .NET Remoting as the primary communication technology. However, since Silverlight does not natively support .NET Remoting, we had a choice to make. We could opt for a more primitive model and drop all the way down to sockets and take care of the messaging and marshaling ourselves, or we could migrate the existing .NET Remoting infrastructure to WCF and take advantage of Silverlight's built-in WCF support. In the end, we chose to migrate to WCF, mostly because it allowed us to increase the potential number of technologies in which a Dataphor client could be built. This post details some of the roadblocks we encountered along the way, and the solutions we came up with. Hopefully, it will shorten someone else's journey.<br /></span><h1>Asynchronicity I</h1><span>The first issue to be tackled was the lack of a synchronous model for invoking a WCF service from Silverlight. The Dataphor CLI was designed as a set of interfaces, somewhat resembling a traditional DBMS CLI, with layers corresponding to the different layers of calls that can be made (such as Server, Session, Process, Cursor, etc.). Each of these layers exposes calls for performing operations against the server, and each call is by design a blocking call. Because the server supports multiple connections, asynchronous operations can be built as a layer above the CLI if necessary. However, because Silverlight does not support synchronous service invocation, we needed a way to wait for the results of every call.<br /></span><span>&nbsp;<br /></span><span>Now, there is no shortage of material on the relative merits of synchronous versus asynchronous calling, and this post is not going to add anything to that debate. Suffice it to say that without completely re-engineering the client side, we need to be able to invoke our CLI calls synchronously. So the first step towards a solution was to verify that a simple service could be synchronously invoked from a Silverlight application. The idea was to use an invocation thread that would perform all the network communication, waiting on the AsyncResult.AsyncWaitHandle returned by the Begin call of the service operation. Once that returns, we invoke the End to get the result and voila, we have a synchronous call. So long as we keep that call off the main thread everything works fine, problem solved:<br /></span><span>&nbsp;<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>IAsyncResult</span> LResult = LService1.BeginGetData(4, <span>null</span>, <span>null</span>);<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>LResult.AsyncWaitHandle.WaitOne();<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>return</span> LService1.EndGetData(LResult);<br /></span><span>&nbsp;<br /></span><span>The reason we have to keep the call off the main thread is that all network traffic in Silverlight appears to be threaded through the main UI thread, so if you block that thread waiting for the result, you'll never get the callback. That's probably an overly simplified description of what's happening, but the solution we've come up with works fine.<br /></span><span>&nbsp;<br /></span><h1>Asynchronicity II</h1><span>One of the things that became clear as we were building this proof-of-concept is that when you define an operation (at least a two-way one) in a service contract, you are really defining both a message and its associated response. As a result, a service can be invoked asynchronously on the client, even if the service contract is defined synchronously on the server. (This is probably obvious to everyone but me, so bear with me). For example, if I define the following service contract:<br /></span><span>&nbsp;<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> </span><span>&lt;summary&gt;<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> Describes the interface for the Dataphor listener.<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> </span><span>&lt;/summary&gt;<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span>ServiceContract</span>(Name = <span>&quot;IListenerService&quot;</span>, <br /></span><span>Namespace = <span>&quot;http://dataphor.org/dataphor/3.0/&quot;</span>)]<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>public</span> <span>interface</span> <span>IListenerService<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> </span><span>&lt;summary&gt;<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> Enumerates the available Dataphor instances.<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> </span><span>&lt;/summary&gt;<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span>OperationContract</span>]<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span>FaultContract</span>(<span>typeof</span>(<span>ListenerFault</span>))]<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>string</span>[] EnumerateInstances();<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<br /></span><span><p class="MsoNormal">I can consume this service synchronously using the IListenerService interface directly, or I can define an asynchronous version:</p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span>ServiceContract</span>(Name = <span>&quot;IListenerService&quot;</span>, <br /></span><span>Namespace = <span>&quot;http://dataphor.org/dataphor/3.0/&quot;</span>)]<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>public</span> <span>interface</span> <span>IClientListenerService<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>{<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> </span><span>&lt;summary&gt;<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> Enumerates the available Dataphor instances.<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>///</span><span> </span><span>&lt;/summary&gt;<br /></span></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span>OperationContract</span>(AsyncPattern = <span>true</span>)]<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>[<span>FaultContract</span>(<span>typeof</span>(<span>ListenerFault</span>))]<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>IAsyncResult</span> BeginEnumerateInstances(<br /></span><span>AsyncCallback</span><span> ACallback, <span>object</span> AState);<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span>string</span>[] EndEnumerateInstances(<span>IAsyncResult</span> AResult);<br /></span><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>}<br /></span><span><p class="MsoNormal">Of course, this is exactly what the Add Service Reference feature of a Silverlight project in Visual Studio is doing, which leads to the conclusion that (unless the Silverlight version of the WCF communication code is substantially different than the standard .NET one) there is no technical reason that a Silverlight client couldn't invoke synchronously. Which leads to the conclusion that so long as the actual service invocation is kept off the main thread, a synchronous version of the service should work. Unfortunately, attempting to feed the synchronous version of the interface to the ChannelFactory in Silverlight gives the error &quot;The contract 'IListenerService' contains synchronous operations, which are not supported in Silverlight&hellip;&quot; I for one am convinced that this is not a technological limitation, just an error thrown in to try to force developers to adopt the asynchronous programming model in Silverlight.</p><h1>Migrating MarshalByRefObject</h1><p class="MsoNormal">The second major issue to be tackled was the fact that the Dataphor CLI uses the instancing and lifetime management services provided by .NET Remoting. Each layer of the Dataphor CLI is modeled by a MarshalByRefObject descendent that implements the interface containing the calls appropriate to that layer. WCF, on the other hand, is essentially solving a different problem, and does not have any facilities for cross-process instancing. As a result, we were faced with another decision. Either we re-engineer the entire CLI to work without instancing, or we recreate the lifetime and instance management facilities provided by .NET Remoting and expose them via a WCF service.</p><p class="MsoNormal">Because the Dataphor CLI was already layered into a 'developer-friendly' version meant to be used directly from code, and a 'network-friendly' version optimized to reduce network traffic, building the instancing and lifetime management facilities could be done relatively easily and would enable all the existing client and server side infrastructure to be used as is.</p><h2>The Way It Was</h2><p class="MsoNormal">First, a little background; the core CLI is defined by the IServerXXX interfaces. This is the development-level interface actually exposed to the code, and is designed to be as easy as possible to use from a development perspective. On the server-side, these interfaces are implemented directly by ServerXXX classes that make up the actual running server.</p><p class="MsoNormal">The network-level CLI is defined by the IRemoteServerXXX interfaces, and is designed to minimize network round-trips and message sizes. On the server-side, these interfaces are implemented by a set of RemoteServerXXX classes that sit on top of the ServerXXX classes and route the calls to and from the network layer.</p><p class="MsoNormal">On the client-side, the IServerXXX interfaces are implemented by the LocalXXX classes, which are responsible for consuming the IRemoteServerXXX proxies returned by the remoting layer and converting the network-level CLI back into the development-level CLI. The result is that whether a client is accessing the Dataphor Server in- or out-of-process, the programming model is identical.</p><h2>The Way It Is</h2><p class="MsoNormal">In order to preserve this programming model (and the mountains of code written on top of it), the WCF-enabled architecture effectively acts as a shim between the server- and client-side implementations of the IRemoteXXX interfaces.</p><p class="MsoNormal">To avoid multiple channels on the client, instead of a group of interfaces, the entire CLI is exposed via the IDataphorService interface, and each level of the CLI is modeled with handles. On the server-side, a DataphorService implements the actual service and simply wraps up the existing RemoteServerXXX classes. Each object that would have been marshaled in .NET Remoting is assigned a Handle and tracked by the DataphorService. Information that would have been marshaled via properties of those objects is now packaged in Descriptor structures.</p><p class="MsoNormal">On the client-side, the IRemoteServerXXX interfaces are implemented by ClientXXX classes that mirror the RemoteServerXXX objects on the server side. All communication is channeled through the DataphorService, and the object state is unpackaged by the ClientXXX and exposed through the IRemoteServerXXX interfaces back to the existing LocalXXX implementations. As a result, all the existing client-side code still works, it just uses WCF now instead of remoting.</p><h1>Watch Out For Out</h1><p class="MsoNormal">Another aspect of the .NET version of the CLI that had to be changed was the use of <em><span>ref</span></em> and <em><span>out </span></em>parameters. Of course, these work fine for the synchronous version of the service, but in the asynchronous version, the ref and out parameters were never being set. Of course, this makes sense if you think about it, but if there was ever a good place for an exception, this would be it. How about: &quot;Ref and out parameters cannot be used with asynchronous invocation.&quot;</p><h1>Lifetime Management</h1><p class="MsoNormal">When the CLI was exposed via .NET Remoting, we were able to take advantage of the fact that .NET tied the lifetime of the proxies to the lifetime of the connection. Using lifetime services, if a remote object failed to renew its lease, the remoting infrastructure would disconnect the object and notify the RemoteServerXXX layer that disconnection had occurred. In the new WCF architecture, no such services exist.</p><p class="MsoNormal">It should be noted that we looked at using WCF sessions to enable this functionality and decided against it for several reasons. First, the session management built in to WCF isn't an exact fit to the way sessions are managed in the Dataphor CLI, so we would have ended up having to build a shim architecture on top of that anyway. Second, the session management required the use of the WsHttpBinding, which at least at the time of the migration, was not supported in Silverlight, our primary target for the migration in the first place.</p><p class="MsoNormal">In the .NET version of the service, we used a client-side thread that simply posted a do-nothing message (a ping, if you will) to the server on a timer. The lifetime lease for each object was set to renew for a little over twice the time of the client timer, and so long as the client could reach the server, the remote object would stay live.</p><p class="MsoNormal">In the WCF version, we left the client-side mechanism alone, and simply added a daemon to the Dataphor Service to check the last 'ping' time for each connection. If the last ping time occurred before the idle timeout, the connection is assumed to be lost and all the sessions it supported are closed.</p><p class="MsoNormal">Because the ping is running on a separate thread in the client, it will occur even when the client is busy, so the service does not need to do anything to track activity occurring below the session.</p><h1>Exception Management</h1><p class="MsoNormal">When the CLI was exposed via .NET Remoting, exception management was fairly simple. All the RemoteServerXXX layers had to do was make sure that any exception that hit a remoting boundary was serializable, and deserializable by the client (i.e. the exception class was available to the client app domain). We did this by making sure that all exceptions thrown across remoting were descended from our own DataphorException class, and that all relevant exception classes were available on the client (that is another story).</p><p class="MsoNormal">In the WCF implementation, however, exceptions always cross the service boundary as a fault. The simplest solution was just to turn on IncludeExceptionDetailInFaults. This was safe from the service perspective because we already knew that every exception coming out of the service was a known-good remotable exception. However, the problem was that when the exception was surfaced on the client-side, it became a FaultException&lt;T&gt;, with T being a basic ExceptionDetail class. There were several problems with this. First, the ExceptionDetail class only has the information carried by the base Exception. Our exception classes carry other information (such as syntax and compiler error line information, system-level error codes, etc.) and this information was being lost. And second, the client-side code downstream from the service was written to expect exceptions to be of the appropriate type.</p><p class="MsoNormal">To solve these problems, we introduced a DataphorFault. This fault class was simply a combination of all the information that could be carried by a DataphorException or any of its descendents. Then each operation contract was marked with a fault contract specifying this fault type. In the implementation of the DataphorService, each call is wrapped with a catch that converts any exception into a FaultException&lt;DataphorFault&gt;. With that in place on the server-side, we no longer need the IncludeExceptionDetailInFaults on the service behavior.</p><p class="MsoNormal">On the client side, each call is also wrapped with a catch block that converts any FaultException&lt;DataphorFault&gt; back in to the appropriate DataphorException descendent with all the relevant information from the fault. In this way, exceptions are transported across the WCF boundary without the server or client ever being the wiser. All the existing exception management code on both sides remains the same.</p><h1>No Configuration Files Required</h1><p class="MsoNormal">An aspect of WCF that we wanted to avoid was the astonishing proliferation of .config files that are required to enable even the simplest WCF scenarios. Of course, configurability is a good thing, but in this case, we already had configuration for the important aspects of the server (host name, server instance, port number, etc.), and we did not want the migration to WCF to add any administrative overhead if we could avoid it.</p><p class="MsoNormal">So rather than specify service behavior and endpoint configurations in config files that would become part of the deployment, we built that in programmatically. We were able to control every aspect of WCF service and hosting behavior programmatically, and added zero configuration to the deployment of a standard, network accessed Dataphor Server.</p><p class="MsoNormal">For Silverlight, we had to tackle the problem of 'cross-domain access'. For this, we simply built a Cross Domain Service to serve up a clientaccesspolicy.xml file. The only tricky part here was figuring out how to get the 'Web' behavior specified so that a URI request coming in would be treated as a web request, rather than a SOAP action. This can be done programmatically by adding a WebHttpBehavior to the behaviors of the newly created Endpoint. However, because we implemented a separate service, it was easier just to use a WebServiceHost rather than a ServiceHost.</p><h1>Conclusions</h1><p class="MsoNormal">So at the end of the day, what did we get out of the migration? Well, besides a deeper understanding of Yet Another Remote Procedure Call Technology From Microsoft (YARPCTFM), we did get some pretty substantial benefits:</p><p class="MsoListParagraphCxSpFirst"><span><span>&middot;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Increased Exposure &ndash; A Dataphor Server can now be exposed via http/s as an industry standard Web Service. Something we never had before. And with both the standard CLI and the new Native CLI exposed, accessing a Dataphor Server is possible from pretty much any technology now known.</p><p class="MsoListParagraphCxSpMiddle"><span><span>&middot;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Network Resilience &ndash; Communications with a Dataphor Server are now stateless from the networking perspective. A dedicated connection is no longer required, with session management being built in the CLI and calling protocol rather than baked into the network layer. This will give Dataphor clients much greater resilience to intermittent network connections.</p><p class="MsoListParagraphCxSpMiddle"><span><span>&middot;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Silverlight Capability &ndash; Following from the increased exposure bullet above, it is now possible to build a Silverlight Dataphor client, a project that is nearing completion.</p><p class="MsoListParagraphCxSpLast"><span><span>&middot;<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>Leverage On Existing Code &ndash; By building the WCF replacement the way we did, we were able to preserve the existing Dataphor code base on both sides of the network boundary. We dropped in an entirely new communication layer and neither side knows the difference. Fantastic.</p></span></span>]]>
        
    </content>
</entry>
<entry>
    <title>Porting a large .NET application to Silverlight</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/10/porting_a_large_net_applicatio.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=30" title="Porting a large .NET application to Silverlight" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.30</id>
    
    <published>2009-10-08T05:18:27Z</published>
    <updated>2009-10-08T15:38:50Z</updated>
    
    <summary><![CDATA[If you've followed the latest in the Dataphor wiki you'll know we're building a Silverlight client for Dataphor.&nbsp; From the sound of &quot;new client&quot;, one would think&nbsp;this effort would involve merely adding a new component to Dataphor, but in truth...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>If you've followed the latest in the <a href="http://dataphor.org/">Dataphor wiki</a> you'll know we're building a Silverlight client for Dataphor.&nbsp; From the sound of &quot;new client&quot;, one would think&nbsp;this effort would involve merely adding a new component to Dataphor, but in truth the effort is basically a port.&nbsp; This is due to the fact that a Dataphor client runs a Dataphor engine, and because Silverlight doesn't support &quot;older&quot; .NET technologies such as remoting.&nbsp; All in all, this &quot;new client&quot; actually entails:</p><ul><li>Modernizing the Dataphor code base.&nbsp; The code now makes use of generics, compiler inferred type declarations, lambda functions, etc.</li><li>Removal of legacy portions.</li><li>Splitting of the Dataphor server into Server and Engine.</li><li>Replacement of Remoting with WCF.</li><li>Adding platform support to libraries.</li><li>Delayed class loading.</li><li>Porting of the engine to Silverlight.</li><li>Oh, and a new Silverlight client.</li></ul><p>This effort represented nothing short of a massive upheaval of the source base, mostly for the better.&nbsp; I've not seen a detailed account of the porting of something as large as a relational database engine to Silverlight, so we kept notes along the way in hopes that this might help others.&nbsp; There are of course many levels at which this port could be discussed, from architecture to syntax.&nbsp; In this post, I'll just give a&nbsp;rough list&nbsp;of the runtime and BCL issues that were encountered in the port.&nbsp; Perhaps we'll expand on some of these in a future post.&nbsp; We may also post more about the architectural issues, such as thread implcations, in a future post.</p><p>Here's the overview:&nbsp;</p><div><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td><p>Issue</p></td><td><p>Resolution</p></td></tr><tr><td><p>Unsafe code for buffer splicing</p></td><td><p>Replaced with safe alternatives.<span>&nbsp; </span>Added ByteArrayUtility to provide services similar to BitConverter and BinaryReader/BinaryWriter</p></td></tr><tr><td><p>Can't reference non-Silverlight projects from Silverlight projects</p></td><td><p>New Silverlight projects with links for each file</p></td></tr><tr><td><p>No HashTable and ArrayList</p></td><td><p>Replaced with Dictionary and List generics</p></td></tr><tr><td><p>Dictionary and List semantic differences</p></td><td><ol><li><span>TryGetValue versus this[] == null</span></li><li><span>No virtuals for added/removed</span></li><li><span>StringComparer won't work on &lt;object, object&gt;</span></li><li><span>DictionaryEntry -&gt; KeyValuePair</span></li><li><span>No ToArray() methods on Keys and Values</span></li></ol></td></tr><tr><td><p>No SerializationAttribute </p></td><td><p>Removed attributes, replaced with DataContract (WCF)</p></td></tr><tr><td><p>No SerializationInfo </p></td><td><p>Removed, exception overloads replaced with FaultContract</p></td></tr><tr><td><p>No StringCollection </p></td><td><p>Replaced with List&lt;string&gt;</p></td></tr><tr><td><p>P/Invoke calls to QueryPerformanceCounter APIs</p></td><td><p>Replaced with calls to Environment.TickCount</p></td></tr><tr><td><p>No Stopwatch class</p></td><td><p>Implemented alternative based on Environment.TickCount</p></td></tr><tr><td><p>No File.GetAttributes()</p></td><td><p>Moved dependency into platform specific assembly</p></td></tr><tr><td><p>No AppDomain.GetAssemblies()</p></td><td><p>Moved dependency into platform specific assembly</p></td></tr><tr><td><p>No Assembly.Load (remaining overloads are security restricted</p></td><td><p>Refactored to use AssemblyPart.Load from a byte[]</p></td></tr><tr><td><p>No WebRequest.GetResponse</p></td><td><p>Removed dependency</p></td></tr><tr><td><p>No WebClient.OpenRead, only async supported</p></td><td><p>No longer dependency</p></td></tr><tr><td><p>No MD5CryptoServiceProvider</p></td><td><p>Used this to replace framework implementation: <a href="http://www.markharris.net.au/blog/2008/10/23/md5cryptoserviceprovider-for-silverlight/">http://www.markharris.net.au/blog/2008/10/23/md5cryptoserviceprovider-for-silverlight/</a></p><p>...Then removed because a comparison was better than a hash in usage case.</p></td></tr><tr><td><p>No XmlTextWriter</p></td><td><p>Replaced with XmlWriter</p></td></tr><tr><td><p>No XmlTextReader</p></td><td><p>Replaced with XmlReader</p></td></tr><tr><td><p>No XmlDocument and related</p></td><td><p>Replaced with XDocument (had to go to 3.5 framework)</p></td></tr><tr><td><p>No TypeDescriptor (thus no GetTypeConverter)</p></td><td><p>Replaced with StringToValue and ValueToString implementations that switch on the type and convert the native and native like types to and from strings</p></td></tr><tr><td><p>No Type.GetInterface overload with one argument</p></td><td><p>Used the two argument version.</p></td></tr><tr><td><p>No Diagnostics.Trace class</p></td><td><p>Used the Debug class instead </p></td></tr><tr><td><p>No String.Compare with case insenstivite</p></td><td><p>Replaced with String.Equals(x, y, StringComparison.OrdinalIgnoreCase) or similar Compare overload</p></td></tr><tr><td><p>No Enum.Parse w/o case specifier</p></td><td><p>Added explicit false third argument.</p></td></tr><tr><td><p>No remoting</p></td><td><p>Replaced with WCF</p></td></tr><tr><td><p>No Diagnostics.TraceLevel</p></td><td><p>Removed usage</p></td></tr><tr><td><p>No UnicodeEncoding.ASCII encoding</p></td><td><p>Replaced with UTF8 encoding</p></td></tr><tr><td><p>No 2 argument Convert.ChangeType</p></td><td><p>Passed Thread.CurrentThread.CurrentCulture as 3rd argument</p></td></tr><tr><td><p>No Assembly.GetType passing ignoreCase</p></td><td><p>Called another overload</p></td></tr><tr><td><p>No Rijndael encryption</p></td><td><p>Replaced with Aes</p></td></tr><tr><td><p>No Thread.Interrupt()</p></td><td><p>Removed usage</p></td></tr><tr><td><p>ThreadInterruptedException not public</p></td><td><p>Rewrote Interrupt pattern with AutoResetEvent()</p></td></tr><tr><td><p>No Environment.MachineName</p></td><td><p>Compiler conditional</p></td></tr><tr><td><p>No BitVector32</p></td><td><p>Removed reference (could have used BitVector)</p></td></tr><tr><td><p>No System.Drawing (Image etc.)</p></td><td><p>Image replaced with Media.Imaging.BitmapImage.<span>&nbsp; </span>Image.Load() becomes BitmapImage.SetSource()</p></td></tr><tr><td><p>No System.Drawing attributes</p></td><td><p>Attributes redefined as dummies;</p></td></tr><tr><td><p>No ComponentModel attributes</p></td><td><p>Attributes redefined as dummies;</p></td></tr><tr><td><p>No ReaderWriterLock</p></td><td><p>Found custom implementation, modified.<span>&nbsp; </span>Then found usage was minor and removed.</p></td></tr><tr><td><p>P/Invoke to Terminal Services API</p></td><td><p>Compiler defined wrapper class</p></td></tr><tr><td><p>ChannelFactory doesn't support overload that takes URI string</p></td><td><p>Constructed EndpointAddress as argument</p></td></tr><tr><td><p>ComponentCollection of IContainer doesn't support enumeration (stub)</p></td><td><p>Compiler defined usage</p></td></tr><tr><td><p>No ManualResetEvent.WaitOne(int, false) overload.</p></td><td><p>Replaced with invocation with just timeout.</p></td></tr><tr><td><p>No Assembly.CreateQualifiedName</p></td><td><p>Replaced with string concatenation of &lt;name&gt;,&lt;assembly name&gt;</p></td></tr><tr><td><p>No Thread.ResetAbort()</p></td><td><p>Removed reference, we no longer use abort (ever) anyway.</p></td></tr><tr><td><p>Assembly.GetName() is marked security critical (can't access)</p></td><td><p>Wrote parser to get Name and Version from the FullName</p></td></tr><tr><td><p>Can't DataMember serialize a private member</p></td><td><p>Changed to internal and used the &quot;friend class&quot; mechanism to allow the System.Runtime.Serialization assembly to access</p></td></tr><tr><td><p>Designer related attributes</p></td><td><p>Created dummy attributes; used the class name (string) overload rather than typeof() overloads to avoid dependency on designer assemblies.</p></td></tr><tr><td><p>No C# compiler</p></td><td><p>Ported Mono*</p></td></tr></tbody></table></div><p>*This is still in-flux.&nbsp; We've ported the mono compiler to Silverlight, but haven't tested it yet.&nbsp; If we run into too much trouble with that, we'll invoke the compiler on the server and load the resulting binary on the client.</p><p>Here are some notes regarding the XmlDocument to XDocument porting:</p><div><table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td><p>Issue</p></td><td><p>Resolution</p></td></tr><tr><td><p>CreateElement </p></td><td><p>new XElement(&hellip;)</p></td></tr><tr><td><p>CreateAttribute</p></td><td><p>Element.SetAttributeValue</p></td></tr><tr><td><p>foreach (XmlAttribute in Element.Attributes)</p></td><td><p>foreach (XAttribute in Element.Attributes())</p></td></tr><tr><td><p>Node.NamespaceUri</p></td><td><p>Node.Name.NamespaceName</p></td></tr><tr><td><p>Node.Name</p></td><td><p>Node.Name.LocalName or Node.Name.NamespaceName</p></td></tr><tr><td><p>Attributes != null</p></td><td><p>HasAttributes</p></td></tr><tr><td><p>FirstChild, Children</p></td><td><p>Elements() enumerator</p></td></tr><tr><td><p>Document.DocumentElement</p></td><td><p>Document.Root</p></td></tr><tr><td><p>XmlDocument.Normalize()</p></td><td><p>XDocument.Normalize (not present in Silverlight)<span>&nbsp; </span></p><p>? may not be necessary any longer</p></td></tr><tr><td><p>Attributes.Remove</p></td><td><p>SetAttributeValue(x, null)</p></td></tr><tr><td><p>Attributes[x]</p></td><td><p>Attribute(x)</p></td></tr><tr><td><p>XDocument.Load(Stream)</p></td><td><p>XDocument.Load(XmlReader.Create(Stream)) </p><p>(BCL doesn't support the overload SL does)</p></td></tr><tr><td><p>Node.Parent.RemoveChild(Node)</p></td><td><p>Node.Remove()</p></td></tr><tr><td><p>ChildNodes</p></td><td><p>Elements() (in most cases)</p></td></tr></tbody></table></div><p>&nbsp;</p>]]>
        
    </content>
</entry>
<entry>
    <title>Progress On Dataphor</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/07/dataphor_progress.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=29" title="Progress On Dataphor" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.29</id>
    
    <published>2009-07-02T22:03:02Z</published>
    <updated>2009-07-02T23:14:56Z</updated>
    
    <summary>Progress on the Dataphor front has been slow but steady for a long time now. Recently, however, thanks to support from the community as well as targeted investment from Dataphor users, we have been able to make some significant progress....</summary>
    <author>
        <name>Bryn</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>Progress on the Dataphor front has been slow but steady for a long time now. Recently, however, thanks to support from the community as well as targeted investment from Dataphor users, we have been able to make some significant progress. In addition to several defect repairs, many new features have been added.</p><h6>Instancing</h6><p>A running Dataphor server has always been called an instance, but recent changes have made configuring and administering multiple instances dramatically easier. Multiple instances can be installed and managed on the same machine without the need to run command-line installations, or manage configurations using config files. A new listener service has been added to make instance discovery possible from the client, and port configuration can now be managed completely server-side. In addition, several changes have been made to consolidate the data used by an instance and enable multiple instances to use the same executable and library directories.</p><h6>Native CLI</h6><p>A new, lightweight, potentially stateless CLI has been built to enable a Dataphor server to be accessed from applications without having to incur the overhead required by the standard CLI. Because it is intended as an alternative, not a replacement, the new CLI is not as feature-rich, but it eliminates the dependencies on the Dataphor code base and can be used virtually stand-alone. This will enable the Dataphor server to be reached from a much broader range of clients, such as mobile applications, Silverlight clients, and other environments where resources are at a premium. In addition, the stateless potential of the new Native CLI enables applications to make scaling decisions that were previously infeasible with the standard CLI.</p><h6>Cross-Instance Query</h6><p>The Dataphor server now supports the configuration of Server Links that can be used to query other running instances of Dataphor servers. The Dataphor Server coordinates transactions between the current instance and any number of connected instances to provide seamless nested distributed transaction support.</p><h6>SQLite Catalog Support</h6><p>The catalog persistence layer was abstracted to provide the ability to plug-in different catalog store implementations, and a SQLite catalog store implementation was built. The Dataphor Server can now be configured to use SQLite, rather than SQL Server Compact Edition to provide catalog persistence.</p><h6>Mono Support</h6><p>In order to enable the Dataphor server to be used on a Mono platform, we have taken steps to remove any platform-specific dependencies in the code base, as well as the client tools.</p><p>All these features are currently implemented in the main development branch of the Dataphor project. To try them out, simply get latest from the open source svn repository and build the Dataphor solution. We have consolidated the projects so that it's easier than ever to build and get up and running quickly.</p><p>For more complete discussion and up-to-date documentation about the latest features available in Dataphor, see the <a title="What's New In 2.2" href="http://www.dataphor.org/WhatsNewIn2.2.ashx" target="_blank">What's New in 2.2</a> page of the dataphor wiki.</p><p>&nbsp;</p>]]>
        
    </content>
</entry>
<entry>
    <title>Simulating SharedSizeGroup in Silverlight</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/05/simulating_sharedsizegroup_in.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=28" title="Simulating SharedSizeGroup in Silverlight" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.28</id>
    
    <published>2009-05-22T22:29:56Z</published>
    <updated>2009-06-05T01:08:36Z</updated>
    
    <summary><![CDATA[There are several features of WPF that are not present in Silverlight, some of which are pretty difficult to work-around or live without.&nbsp; One such feature is the SharedSizeGroup property that WPF has for column and row definitions of a...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>There are several features of WPF that are <a title="Silverlight 2 missing features" href="http://databaseconsultinggroup.com/blog/2009/04/silverlight_2_missing_features.html" target="_blank">not present in Silverlight</a>, some of which are pretty difficult to work-around or live without.&nbsp; One such feature is the <a title="SharedSizeGroup property in WPF" href="http://msdn.microsoft.com/en-us/library/system.windows.controls.definitionbase.sharedsizegroup.aspx" target="_blank">SharedSizeGroup</a> property that WPF has for column and row definitions of a layout grid.&nbsp; This feature made many advanced layout scenarios entirely declarative.&nbsp; Consider, for instance, the situation where an outer grid defines a set of control groupings for a form.&nbsp; Within each of the out grid's cells are text boxes with left aligned labels.</p><p><img width="456" height="234" title="SharedSizeGroup in WPF" alt="SharedSizeGroup in WPF" src="http://databaseconsultinggroup.com/Images/WPFSharedSizeGroup.png" border="0" /></p><p>In this case, the inner grids can use a SharedSizeGroup property&nbsp;on the&nbsp;column containing the labels and the text will be aligned automagically.</p><p>We&nbsp;wanted to be able to accomplish basically the same thing in Silverlight, and maybe even see if&nbsp;we could go about making it a little more general.&nbsp; In particular&nbsp;we wanted to divorce the functionality from the Grid so that it could be used in non-grid situations as well.</p><p>What&nbsp;we came up with was a combination of two classes: SharedSizePanel and SharedSizeGroup.&nbsp; SharedSizePanel is a simple, single element container which has the optional properties WidthGroup and HeightGroup.&nbsp; All panels associated with a particular group will be given the size of the panel with the greatest content size in that dimension.</p><p>&lt;local:SharedSizePanel WidthGroup=&quot;{StaticResource Horizontal}&quot; &gt;<br />&nbsp; &lt;Border Background=&quot;Coral&quot;&gt;<br />&nbsp;&nbsp;&nbsp; &lt;local:ResizeBox Width=&quot;30&quot; Height=&quot;30&quot; /&gt;<br />&nbsp; &lt;/Border&gt;<br />&lt;/local:SharedSizePanel&gt;</p><p>A SharedSizeGroup is a simple class that can easily be instantiated in the resources section:</p><p>&lt;UserControl.Resources&gt;<br />&nbsp; &lt;local:SharedSizeGroup x:Key=&quot;Horizontal&quot; /&gt; <br />&lt;/UserControl.Resources&gt;</p><p>We&nbsp;<em>wanted</em> to allow widths and heights to be synchronized to the same value,&nbsp;which would allow such fanciful things as the width and height of a particular control to be synced.&nbsp; That capability would add quite a bit of complexity to what is presently a very simple implementation so&nbsp;we held off.&nbsp;&nbsp;</p><p>There were a few&nbsp;challenges that were encountered in building this control, including:</p><ul><li>Custom Measure and Arrange logic doesn't seem to work as expected as a descendant of ContentControl.&nbsp;&nbsp;It worked as Panel descendant, but there doesn't seem to be a way to limit the panel to a single child, so fortunately it was found to work as a ContentPresenter.</li><li>The group cannot and must not force measurement of the panels, so it must&nbsp;store what the measurement was when it happened.&nbsp; This is true for several reasons including the fact that the &quot;available size&quot; is only known when passed as an argument to the measure override.</li><li>As a content control, the VisualTreeHelper class must be used to get the actual element that the Content becomes.&nbsp; Content of type object and you can't Measure an object.</li></ul><p>In the end, the solution seems&nbsp;relatively simple and elegant, so fortunately I consider that all of the above worked out favorably.&nbsp;</p><p>I haven't seen any indications that&nbsp;SharedSizeGroup will be introduced in Silverlight 3, and I'm not ready yet to dispose of my Silverlight 2 development environment to find out.&nbsp; Anyone have version 3 installed that wouldn't mind verifying?</p><p><a title="Download the source of SharedSizePanel" href="http://databaseconsultinggroup.com/downloads/SharedSizePanel_6-4-09.zip">Download the code for these classes</a>.&nbsp; <a title="WPF SharedSizeGroup sample" href="http://databaseconsultinggroup.com/downloads/WPFSharedSizeGroup_5-22-09.zip">Download the WPF SharedSizeGroup sample</a>.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Silverlight 2 missing features</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/04/silverlight_2_missing_features.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=27" title="Silverlight 2 missing features" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.27</id>
    
    <published>2009-04-03T05:20:00Z</published>
    <updated>2009-06-11T05:38:10Z</updated>
    
    <summary><![CDATA[I've had this rant rotting in my notes for too long, time to post. &nbsp;The topic is features that were in WPF but are missing from Silverlight 2.&nbsp; Now that Silverlight 3 is in beta, this information may not be...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[I've had this rant rotting in my notes for too long, time to post. <span>&nbsp;</span>The topic is features that were in WPF but are missing from Silverlight 2.<span>&nbsp; </span>Now that Silverlight 3 is in beta, this information may not be as timely or useful, but perhaps still useful to someone.<span>&nbsp; </span>The below excludes items&nbsp;spelled out&nbsp;in the <a href="http://msdn.microsoft.com/en-us/library/cc903925(VS.95).aspx">official documentation on the topic</a>.<span>&nbsp; </span>Note that although the final feature set of Silverlight 3 hasn't been set, many of these items appear missing there too.<br /><ul><li><div>DrawingVisual Brushes &ndash; this doesn&rsquo;t seem like a big deal, but without this, doing something as simple as say, tiling an image, becomes very difficult.</div></li><li><div>Relative source binding &ndash; binding from one property of one entity to a property of another has to be constructed in code.<span>&nbsp; </span>Hard to believe that this didn&rsquo;t make the list, but fortunately is in Silverlight 3.</div></li><li><div>TemplateBinding to anything other than a root dependency property.</div></li><li><div>The DataContext is not inferred from parent to child.</div></li><li><div>SharedSizeGroup &ndash; this subtle, but oh so useful property of the GridColumn and GridRow Grid classes.</div></li><li><div>Popup.PlacementTarget &ndash; Popups have to be absolutely positioned, which is unfortunate given that there are no dialogs or forms, so Popups can be a pretty important element.</div></li><li><div>LayoutTransform &ndash; RenderTransforms are useful, but certainly don&rsquo;t provide for what LayoutTransforms did.</div></li><li><div>Left mouse click &ndash; What were they thinking?!<span>&nbsp; </span>They could have had an instant advantage over flash.</div></li><li><div>OverrideMetadata &ndash; This important aspect of dependency properties can be a pain to live without.</div></li><li><div>AddOwner &ndash; Another pretty useful dependency property trick.</div></li><li><div>Read-only dependency properties &ndash; Another property thing that&rsquo;s been a pain to work-around.</div></li><li><div>Property change notification &ndash; This one is a real bear.<span>&nbsp; </span>There seems to be no programmatic way to know that a DependencyObject&rsquo;s property has changed (ouch).</div></li><li><div>No custom routed events &ndash; This one has been a real pain for me, but might not come up for most apps.</div></li><li><div>GetFlattenedPathGeometry and GetPointAtFractionLength &ndash; path functions that are possible to work around, but a pain.</div></li><li><div>Baseline in FontFamily</div></li><li><div>OnRender &ndash; They seem to have some good arguments for this one, however.</div></li><li><div>Keyboard Key to character code translation - that is, knowing that say Key.D1 translates to character '1'.&nbsp; Once has to also check the Shift state of the keyboard, and basic keys like + are only in the PlatrofmKeyCode, which requires a series of hard-coded assumptions to deal with.</div></li></ul><p>I also had a couple Silverlight 2 gotchas noted:</p><ul><li><div>If you rename a Silverlight project, watch out that the &quot;Startup Object&quot; property of the project is corrected too, or the app will fail to start with no explanation.</div></li><li><div>If you have a web application to go with your Silverlight project, don&rsquo;t add the Silverlight application as a reference, associated it under the Silverlight tab in the web apps configuration dialog.</div></li><li><div>If you will be creating more than one instance of a UserControl, don&rsquo;t name it or you will receive and error when instancing the 2<sup>nd</sup>.<span>&nbsp; </span>This is a royal pain because if it is unnamed it cannot be referenced by the animation objects (or by-name binding in Silverlight 3).<span>&nbsp; </span>Basically you have to programmatically create the binding for anything that binds to the root UserControl.</div></li></ul><p>Links to other similar posts:</p><ul><li><a href="http://silverlight.net/forums/p/10951/35119.aspx">List from Justin Chase on Silverlight forums.</a></li><li><a href="http://stackoverflow.com/questions/554570/workaround-for-some-wpf-features-that-are-missing-in-silverlight">Work-arounds for missing Silverlight features on StackOverflow.</a></li><li><a href="http://joshsmithonwpf.wordpress.com/2008/11/17/emulating-icommandsource-in-silverlight-2/">Emulating CommandSource by Josh Smith</a></li><li><a href="http://msdn.microsoft.com/en-us/library/cc903925(VS.95).aspx">Official list on MSDN</a></li></ul>]]>
        
    </content>
</entry>
<entry>
    <title>State of the UNION</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2009/01/state_of_the_union.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=26" title="State of the UNION" />
    <id>tag:databaseconsultinggroup.com,2009:/blog//1.26</id>
    
    <published>2009-01-13T05:15:43Z</published>
    <updated>2009-06-05T00:00:19Z</updated>
    
    <summary><![CDATA[DCG has been very quiet for some time.&nbsp; Not much activity on any of our sites, and our dataphor.org and alphora.com sites have been down for a couple weeks.&nbsp; Though this doesn't look good, I assure you we're still around...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>DCG has been very quiet for some time.&nbsp; Not much activity on any of our sites, and our dataphor.org and alphora.com sites have been down for a couple weeks.&nbsp; Though this doesn't look good, I assure you we're still around and nutty as ever (speaking at least for myself).</p><p>I'll take this opportunity, being that this is the first blog post of the year, to give an update of where we stand and where we are going:</p><ul><li>Dataphor - Yes we still love Dataphor and continue to support and incrementally improve it.&nbsp; The dataphor.org and alphora.com websites are down because we basically have one server and it was in need of a software rebuild.&nbsp; You can thank&nbsp;all of the nice people&nbsp;who have nothing better to do&nbsp;than troll for vulnerable wikis and web servers.&nbsp; You see, we DO have something better to do than patch and counteract said nice people, which is why our server reached the point of crippled.&nbsp; Anyway, we are trying to do a little better job this time to lock everything down properly and reduce our &quot;surface area&quot;.&nbsp; <br />With some community Tender Loving Care (TCL), Dataphor really could be a big success, but quite frankly with only us it&nbsp;would probably never break out of it's little&nbsp;niche.&nbsp; That said, it's really not a bad niche to be in, and at the end of the day it gives us an advantage regardless of it's popularity, or lack thereof.</li><li>Consulting - Consulting is presently our bread and butter as a company, and we count ourselves lucky to have some nice clients to work with and interesting projects to work on.&nbsp; In the financial service world we're working on a hardware interface, business intelligence, lending systems, and other&nbsp;such things.&nbsp; We're wrapping up a medical records system and starting a medical scheduling system.&nbsp;&nbsp;We have&nbsp;also been doing some other smaller consulting projects.</li><li>Mystery Project - Shh, part of our quietness is related to a secret project.&nbsp; We should be able to make some kind of announcement on it in as early as 2-3 months when we hope to go beta.&nbsp; No this is not some kind of Dataphor replacement.&nbsp; This is an entirely different product for an entirely different purpose.&nbsp; Fine, I'll say one little thing: it is relational, at least in spirit.&nbsp; We are very excited about this project, and&nbsp;hope that we don't take&nbsp;the good idea and botch it up too badly in execution.</li></ul><p>Long term, we still have our sights on big things.&nbsp; We would like to do something about the complete insanity we call modern software; or at least provide a vehicle for those that think the same way.&nbsp; Once you start down the path of realizing&nbsp;that there are fundamentally better ways to do things, you'll never be content with the status quo; thus is our lot.&nbsp; We plan to give options for those seeking more abstract, powerful, and mathematical solutions to data management (hint, all software problems are data management problems).&nbsp; It won't be for everyone, but the rest of the industry can continue to swim in a vat of their own&nbsp;complexity if they so choose.</p><p>Here's to 2009, the best year yet!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Spending Moore&apos;s Dividend</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/07/spending_moores_dividend.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=25" title="Spending Moore's Dividend" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.25</id>
    
    <published>2008-07-02T17:58:33Z</published>
    <updated>2008-07-02T17:58:33Z</updated>
    
    <summary><![CDATA[ftp://ftp.research.microsoft.com/pub/tr/TR-2008-69.pdfThis excellent paper from James Larus at Microsoft Research discusses how software abstractions and raised software expectations have essentially squandered the hardware advances of the last 30 years.&nbsp; Okay, perhaps squandered isn't the term, but the point is that software...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p><a href="ftp://ftp.research.microsoft.com/pub/tr/TR-2008-69.pdf">ftp://ftp.research.microsoft.com/pub/tr/TR-2008-69.pdf</a></p><p>This excellent paper from James Larus at Microsoft Research discusses how software abstractions and raised software expectations have essentially squandered the hardware advances of the last 30 years.&nbsp; Okay, perhaps squandered isn't the term, but the point is that software doesn't run any faster than it used to.&nbsp; James points out legitimate reasons as well as less legitimate reasons for this, and looks to the implications of increased parallelism on all of this.</p><p>My take: On one hand, I am all for&nbsp;meaningful software abstractions.&nbsp; I am also for language features that prevent us from shooting ourselves in the foot in obvious ways.&nbsp;&nbsp;I think we could do much better, however:</p><ul><li>Missed abstractions, particularly relations, has led to excessively complex and bloated software.&nbsp; </li><li>Primitive data model - Today's software runs in a model based on allocating memory chunks and procedural APIs.&nbsp; This leads to countless redundancies in the software stack, as well as poor interoperability and optimizability.</li><li>Physical data&nbsp;dependence - by separating the logic from the implementation, we could continually improve&nbsp;software performance without rearchitecting the logic.</li><li>Memory utilization - Garbage collection introduces more problems than it solves.&nbsp; Value-based semantics&nbsp;and&nbsp;the relational model eliminated the need for GC.&nbsp; Virtual memory is, in hind-site, a bad idea.&nbsp; A much more effective architecture is to utilize memory as a cache for what are conceptually persistent data structures (e.g. DBMS architecture).</li><li>Concurrency - again, if the programming model were shifted from references to memory to shared data structures, the issues with thread, process, and network concurrence are already solved.&nbsp; Much more highly concurrent application are possible in&nbsp;ways that&nbsp;are either transparent or opaque to the developer.</li></ul><p>If you've ever sat there for a minute or two waiting for an application to swap back into memory so that it can close, you probably know something is fundamentally wrong with&nbsp;today's architecture.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Something CAN be done about legacy</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/something_can_be_done_about_legacy.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=24" title="Something CAN be done about legacy" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.24</id>
    
    <published>2008-06-25T06:05:19Z</published>
    <updated>2008-06-25T06:05:19Z</updated>
    
    <summary><![CDATA[It may seem that legacy--that is &quot;old style&quot; systems we've inherited or maybe even built but no longer like--is purely something we must live with now and forever.&nbsp; It seems inevitable that our current systems, languages, and applications are doomed...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>It may seem that legacy--that is &quot;old style&quot; systems we've inherited or maybe even built but no longer like--is purely something we must live with now and forever.&nbsp; It seems inevitable that our current systems, languages, and applications are doomed to eventually collect dust and an occasional deriding comment from some new intern who doesn't even know what it is like to boot&nbsp;a computer using floppies.&nbsp; I say, however, nay!&nbsp; How can I say this considering that it's <strong>always been this way!?</strong>&nbsp; Stay with me.&nbsp; First let's establish that some things never go out of style.&nbsp; Like math for instance.&nbsp; Math hasn't changed much since computers were born, and isn't likely to any time soon... or late.&nbsp; Philosophers are still trying to decide whether math is somehow part of the universe, or if math is merely a cool abstraction we use to predict things about the universe.&nbsp; Regardless, it certainly does give us a useful tool for modelling and predicting actual things.&nbsp; Because of this, it has a timeless nature to it, even though&nbsp;we might change what symbols and tools we use to represent things.&nbsp; </p><p>Computer software abstractions are unavoidably&nbsp;related to math, though in many cases the relation may seem like a cousin-in-law's friend's neighbor&nbsp;once removed.&nbsp; It's actually this distance from more foundational principles that makes software so easily dated.&nbsp; In the name of problem solving us Software&nbsp;mechanics have evolved some awfully patched up monsters.&nbsp; This has&nbsp;been made possible by the kind hardware folks, who have been generous enough to make our obtuse layers of bandage-work actually perform in a reasonable manner (thanks guys).&nbsp; One of the many prices to pay&nbsp;for so&nbsp;much bad software abstraction is the rapid manner in which our systems become legacy.&nbsp; Legacy because they are so difficult and fragile to change that nobody wants to touch them.&nbsp; Legacy because they are&nbsp;so laden with complexity that it&nbsp;is&nbsp;nearly impossible to tease out and salvage the essence as platforms change.&nbsp; Legacy because we've got a newer better technology wheel we've reinvented and we must rebuild the old systems because now they just look old.</p><p>It's all of the non-essence stuff in our systems that makes us have to replace rather than extend or enhance them.&nbsp; Think of any given system as being made up of two parts:&nbsp; One part describes the essence of the problem for which the system was created, something like mortgage amortization, modeling customers and sales, or simulating paper documents.&nbsp; The&nbsp;remainder of the application is a description of how to deal with the other layers of technology, such as the user interface technology, expression of concepts&nbsp;within the&nbsp;programming language, or interoperability with other applications.&nbsp;&nbsp;The former is sometimes called essential complexity, the latter accidental complexity.&nbsp; A math formula doesn't become dated, because it contains minimal &quot;fluff&quot; and maximal &quot;content&quot;.&nbsp; Imagine, however, if every few years we renamed all of the math operators, changed symbols, and required filled pages and pages to define simple equations.&nbsp; It sounds unproductive, but you could probably sell lots of silly little books with cutesy animal pictures on the front of them to help the poor mathematicians keep up.</p><p>The closer we get to systems which describe the essence of their mandate, the less likely they are to become legacy.&nbsp; In fact, it could be argued that as the accidental complexity approaches zero, it becomes impossible for a system to be dubbed legacy as it is merely a model of reality.&nbsp; Yes, of course the facet of reality being modeled could change, and so our VHS tape collection tracking software may no longer be needed, but that's not the kind of legacy I'm talking about.&nbsp; That does lead to a point however.&nbsp; It is the changing &quot;real world&quot; that spurs our need to change our software models.&nbsp; Given the information age, the &quot;real world&quot; for most domains is changing faster than ever.&nbsp; The software abstractions, on the other hand, are more complex than ever, demanding incredible amounts of accidental complexity to achieve anything.&nbsp; The result:&nbsp; J2EE, .NET with CAB, LAMP... and a burnt out industry unable to recruit young people because the job is [raise pitch of voice] &quot;boring.&quot;</p><p>The solution is seemingly simple: minimize accidental complexity.&nbsp; Easier said than done right?&nbsp; Actually not really, but [stepping up on soap box] we must take advantage of the &quot;mathematics of data&quot; when modelling data problems.&nbsp; We must understand that everything we do, at all levels in the software stack, is data management.&nbsp; Missing this fact is tantamount to trying to model physics using basic arithmetic.&nbsp; We must define applications first and foremost in their &quot;timeless&quot; logical form, as a relational schema.&nbsp; I spent the last two days dealing with COM programming.&nbsp; I'll never get these back.&nbsp; We <em>must</em> stop thinking that API based abstractions are somehow going to solve a problem; think REST, SOAP, CORBA, DCOM, RPC, etc.&nbsp; Before I hop off of the soap box, let me vouch for myself.&nbsp; The prescribed approach DOES work and DOES minimize accidental complexity.&nbsp; I've now built several applications in Dataphor, a platform that only begins to realize the potential of declarative development, and I've seen that an application can truly be created from little more than defining structures which model reality.&nbsp; If a system is defined&nbsp;in a high-level, declarative way, let the trendy winds howl as they may, that system will easily evolve, and may not ever need to be replaced.</p><p>As a quick disclaimer, I am of course not naive enough to believe that the best technology wins and that politics aren't a primary force in the dynamics of why we are where we are.&nbsp; Nonetheless, I choose to ignore what I can't control and focus on what can be done&nbsp;in the present.&nbsp; Also note that a declarative softwaretopia is inherently opposed to &quot;hiding&quot; logic.&nbsp; This has all sorts of interesting technical ramifications, but it&nbsp;also has some&nbsp;interesting business ramifications.&nbsp; Perhaps the open source movement is laying&nbsp;useful groundwork.</p>]]>
        
    </content>
</entry>
<entry>
    <title>New exception handling technique!!!</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/new_exception_handling_techniq.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=23" title="New exception handling technique!!!" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.23</id>
    
    <published>2008-06-18T02:14:05Z</published>
    <updated>2008-06-19T16:56:25Z</updated>
    
    <summary>Let me preface this with RANT!!! (just a little frustrated...)I&apos;ve heard arguments against structured exception handling in my day, but never any as convincing as what I encountered in SQL Server Management Studio 2005 recently. [insert sarcasm here] Why bother...</summary>
    <author>
        <name>Rob Reynolds</name>
        <uri>www.alphora.com</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>Let me preface this with RANT!!! (just a little frustrated...)</p><p>I've heard arguments against structured exception handling in my day, but never any as convincing as what I encountered in SQL Server Management Studio 2005 recently. [insert sarcasm here]</p>
<p>Why bother with all that overhead and extra code when all you really need to do is monitor output messages? </p>
<p>For example, say you wanted to know if a certain UPDATE statement violated a constraint?  How could you use this exciting, new technique???</p> 
<p>First we need a problem:</p>
CREATE TABLE EncryptedSecret<br/>
(<br/>&nbsp;&nbsp;&nbsp;ID varchar(3) NOT NULL,<br/>&nbsp;&nbsp;&nbsp;Text varbinary(512) NOT NULL,<br/>&nbsp;&nbsp;&nbsp;CONSTRAINT [PK_EncryptedSecret] PRIMARY KEY CLUSTERED (ID ASC)<br/>)<br/><br/>CREATE VIEW Secret AS<br/>&nbsp;&nbsp;&nbsp;SELECT  ID, CAST(DecryptByPassPhrase(N'pwd', Text) AS  VARCHAR(255)) AS Text<br/>&nbsp;&nbsp;&nbsp;FROM  EncryptedSecret<br/><br/>CREATE TRIGGER Secret_Update
ON Secret<br/>INSTEAD OF UPDATE
AS<br/>BEGIN<br/>&nbsp;&nbsp;&nbsp;UPDATE EncryptedSecret<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SET  Text = EncryptByPassphrase('pwd', CAST(I.Text as nvarchar(255)))<br/>
&nbsp;&nbsp;&nbsp;FROM EncryptedSecret E INNER JOIN inserted I ON  I.ID = E.ID;<br/>
END<br/>
<br/>
INSERT INTO EncryptedSecret (ID, Text) Values('MSG', EncryptByPassphrase('pwd', 'Hello Kitty!'));<br/>
</p>
<p>"Hello Kitty"???  Any self-respecting developer knows the proper test is "Hello World!"…</p> 
<p>So, if someone tries to fix the problem in the UI, how can we ensure the key isn't violated?  By monitoring the return messages, of course!  If the key hasn't been violated then we should get exactly one "(1 row(s) affected)" message, otherwise, we can pop the following modal dialogue:</p> 
<p>"No row was updated.<br/>
The data in row 1 was not committed.<br/>
Error Source: Microsoft.VisualStudio.DataTools.<br/>
Error Message: The row value(s) updated or deleted either do not make the row unique or they alter multiple rows(2 rows).<br/>
Correct the errors and retry or press ESC to cancel the change(s)."</p>
<p>Perfect!</p> 
<p>Wait a minute.  Unless the trigger includes SET NOCOUNT ON the system will "count" the "update" to the view AND the update to the base table…</p> 
<p>Oh well, let them eat cake!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Auto Update Stats</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/auto_update_stats.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=22" title="Auto Update Stats" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.22</id>
    
    <published>2008-06-11T19:48:44Z</published>
    <updated>2008-06-11T19:48:44Z</updated>
    
    <summary>Today I spent several hours troubleshooting a long-running query in a (thankfully) test environment. Yesterday, everything was working fine. In addition, the same executable could be used successfully against a different instance of the database. However, in one particular database,...</summary>
    <author>
        <name>Bryn</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>Today I spent several hours troubleshooting a long-running query in a (thankfully) test environment. Yesterday, everything was working fine. In addition, the same executable could be used successfully against a different instance of the database. However, in one particular database, the application would freeze at certain points, sometimes ending in an 'unspecified error', other times in a timeout.</p><p>The usual suspect in these cases is blocking, so that's the first thing I looked for. No luck though, the process shows as Suspended, but not blocked by any other process. The wait type for the process is PAGEIOLATCH_SH, but the waittime is always just a few milliseconds. The CPU and IO for the process are off the charts however, and increasing with every refresh. So it's doing a whole lot of reading, but there is no clear indication of what. Even more strange, once I was hung up on a certain point in the processing, other users could get past that point, but would hang up in different spots.</p><p>So I trace to find the last query executed by the application and run that in the query analyzer. Sure enough, it returns immediately. So it's reading a huge amount of data, but I only asked for a few rows, what is the server doing? And why is it different from the application versus the query analyzer? So I turned on all SP and query-related events in the profiler, and now the culprit is revealed. An SP:Statement event shows that what is happening is this:</p><p>SELECT StatMan([SC0], [SB0000]) FROM (SELECT TOP 100 PERCENT [SC0], step_direction([SC0] over (order by NULL) AS [SB0000] FROM (SELECT SUBSTRING([Image_Back], 1, 100)++substring([Image_Back], case when datalength([Image_Back])&lt;=200 then 101 else datalength[Image_Back])-99 end, datalength([Image_Back]))&nbsp;AS [SC0] FROM [dbo].[CheckItemImage] WITH (READUNCOMMITTED, SAMPLE 6.712329e+001 PERCENT) ) AS _MS_UPDSTATS_TBL_HELPER ORDER BY [SC0], [SB0000]) AS _MS_UPDSTATS_TBL OPTION (MAXDOP 1)</p><p>This is happening during a recompile of a view involved in the select. The table in question only contains a few hundred thousand rows, but they are check images, so there is a huge amount of binary data involved, and this statistics query is basically reading the whole thing.</p><p>Updating statistics on the database did not resolve the issue, the server still tries to build the statistics to optimize the query. So I turned off Auto Create Statistics, and now the query runs instantly (turning off Auto Update Statistics did not work).</p><p>Of course, I don't want to turn off these features, they are great features. And I'm not faulting SQL Server in the slightest on this one. Query optimization is a difficult problem, and statistics are a great way to help prune the set of potential plans, but I will from this point on immediately suspect this scenario whenever I see a process suspended with a waittype of PAGEIOLATCH_SH.</p><p>To re-enable these features, I'll need to determine why the stats query is taking so long. I may be able to build those particular statistics manually, or it may involve actually archiving some of the older data in the table.</p><p>So why didn't it hang in the query analyzer? Turns out it did if the application wasn't already hanging on the same query, I just never tried that until after I understood what the problem was. I suspect this is because if the server is already computing a particular statistic for another plan, then it will just use the existing statistic or compile the query without statistics. In this case, that resulted in almost instant execution times.</p><p>In a production database, this would have meant several hours of downtime. I hope this post helps others that may be seeing the same behavior find the solution more quickly than I did.</p><p>Bryn Rhodes<br />Alphora</p><p>&nbsp;</p>]]>
        
    </content>
</entry>
<entry>
    <title>A hidden cost of the failure to abstract</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/a_hidden_cost_of_the_failure_t.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=21" title="A hidden cost of the failure to abstract" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.21</id>
    
    <published>2008-06-11T18:49:21Z</published>
    <updated>2008-06-11T18:49:21Z</updated>
    
    <summary><![CDATA[Microsoft has a site where user's can give feedback about the user experience of Windows Vista:&nbsp; http://www.istartedsomething.com/taskforce/Props to them for being brave enough to open Pandora's Box.&nbsp; Looking through all of the issues, however, it is clear how completely distinct...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>Microsoft has a site where user's can give feedback about the user experience of Windows Vista:&nbsp; <a href="http://www.istartedsomething.com/taskforce/">http://www.istartedsomething.com/taskforce/</a></p><p>Props to them for being brave enough to open Pandora's Box.&nbsp; Looking through all of the issues, however, it is clear how completely distinct each of the various applications that make up the user experience in Windows are.&nbsp; It is clear that each application was built directly against the low-level Windows API at the time, rather than against a higher-level &quot;user interface framework&quot;.&nbsp; Looking at office applications, one can see that Microsoft must have at least some such framework there, but apparently decided to restrict its use to Office.</p><p>The point of this posting is that it is&nbsp;often tempting to add new features/applications without abstracting what is common, but this has many costs.&nbsp; In Microsoft's case, the advantages they gleaned from years of adding new features with minimal impact on existing facets has now&nbsp;accumulated and they are faced with&nbsp;the prospect of having to basically re-write virtually every major and minor user interface of their Operating System.&nbsp; ...or live with an even higher pile of bandages and tape, which seems likely but isn't going to help them compete with the likes of OSX.</p><p>My experience confirms that it&nbsp;always pays to abstract when there are at least two cases of something, but never abstract when there is one.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Viva Le Relation</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/viva_le_relation.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=20" title="Viva Le Relation" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.20</id>
    
    <published>2008-06-07T06:58:15Z</published>
    <updated>2008-06-07T07:09:16Z</updated>
    
    <summary><![CDATA[I'm in the mood for a good rant, so sit back and loosen your face muscles as they might be strained making&nbsp;faces for a while.First, let me start with a snippet from a Microsoft exec at Tech-Ed:&quot;...as much as we've...]]></summary>
    <author>
        <name>Nathan</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>I'm in the mood for a good rant, so sit back and loosen your face muscles as they might be strained making&nbsp;faces for a while.</p><p>First, let me start with a snippet from a Microsoft exec at Tech-Ed:</p><p>&quot;...as much as we've expanded the tools and services, the one thing we continue to have is the commitment to a single programming model,&quot; Somasegar said. &quot;The saying used to be write once, run anywhere, well we say 'learn once, run anywhere,' because once you learn the Microsoft programming model you can use it to build applications anywhere&quot; on the platform, he said.</p><p>Is he talking about the same Microsoft I know?!&nbsp; The company that has a development methodology for every mood.&nbsp; Just use Sharepoint to build a... wait no, Infopath because it's XML data and... actually what you need is Expression Blend... er... Web... but no it's going to involve documents so extend Office... wait you're a real developer so you should be using Visual Studio to write VB... er... C#... wait it's a web app so Ruby.NET against&nbsp;SQL Server Express, no Compact Edition... wait the data is coming from different sources, try SQL Server Integration Services, wait, no you need BizTalk... with a slick UI built in ASP.NET... no Windows Forms, er... I mean WPF... using CAB, no wait that's sooo 2 years ago, you need SCSF Contrib, wait Prism with Enterprise Services, hitting web services through WCF, wait, no Entity Framework running on Windows Server, er... Singularity.&nbsp; Sadly, for every one of the&nbsp;mentioned methodologies, there are&nbsp;dozens of&nbsp;others up Microsoft's proverbial sleeves.</p><p>It's great to allow teams to be autonomous and creative to a point, but what ever happened to conceptual integrity?&nbsp; Is everything really just a subjective mess of competing, &quot;different, but not necessarily better&quot; technologies, or is there merit in actually throwing out some ideas, even when the customers&nbsp;are asking for them?</p><p>Why do we have so many competing ideas, and so little conceptual integrity?&nbsp; I blame two major things: missed abstraction and&nbsp;solving the wrong problems.</p><h5>Missed Abstraction</h5><p>Somewhere in the&nbsp;shuffle we discovered addition,&nbsp;then went straight to solving&nbsp;calculus problems.&nbsp; Without multiplication, algebra, geometry, and maybe some trigonometry, we're bound to flounder about in a pool of boggling complexity.&nbsp; What did we miss?&nbsp; The mathematics of data: the Relational Model.&nbsp; No, not SQL, no, not even &quot;Truly&quot; Relational&nbsp;DBMSes, but relations as a first class part of real languages.&nbsp; Instead we have &quot;collections&quot;, &quot;lists&quot;, &quot;dictionaries&quot; and other such low level primitives.&nbsp; Bear with me.</p><p>We've decided that &quot;data&quot; is this stuff we pull out of database systems, exists for a while in some client, then is pushed back into the system for safe keeping.&nbsp; But what of everything else in the computing environment?&nbsp; The controls on forms, the images, messages, documents, hardware state.&nbsp; No, we've decided, that's not data.&nbsp; We have different systems for that stuff, involving complicated structures of 3gl languages.&nbsp; Surely we wouldn't want to &quot;normalize&quot; it down to&nbsp;inefficient table structures&nbsp;and stuff it into a database system, nor would we want to stream it in it's encapsulated form into a database system BLOB where we couldn't query or manipulate it's parts anyway.</p><p>My friends, the database system is the worst thing that ever happened to the Relational Model.&nbsp; The RM is nothing short of the mathematics of data, and a DBMS is just one kind of calculator.&nbsp; SQL Systems of today are perhaps abacus' in the analogy.&nbsp; Not only is SQL about the worst imaginable embodiment of the Relational Model, the notion of&nbsp;Database Systems in general&nbsp;has crippled our thinking about how to manage and think about&nbsp;data.&nbsp; Relations should be an integral part of every modern language.&nbsp;&nbsp;Queries should just be ordinary&nbsp;expressions of the language.&nbsp; &quot;Database Systems&quot; simply become one kind of runtime in which the data can be shared and stored persistently.</p><p>The Relational Model gave us a) a formal basis for declaratively managing <em>any</em> kind of data; and b) a way to talk about logical things independent of physical things.&nbsp; We've&nbsp;hardly begun&nbsp;to tap either of these benefits.&nbsp;&nbsp;&nbsp;Consider every variety of application that doesn't use a general purpose DBMS, from Word Processors to Games.&nbsp; Now consider the problems faced by the engineers of these applications including: concurrency, persistence, durability, integrity, remote access, consistency, querying,&nbsp;security, data manipulation, scaling up, and scaling out.&nbsp; Everything... EVERYTHING we do is data management.&nbsp; A conceptual model which raises the level of abstraction in which we can do data management is going to help us!</p><h5>Solving the wrong problems</h5><p>We don't need another method for invoking functions remotely.&nbsp; That was not the problem.&nbsp; Just look at SOAP.&nbsp; We're&nbsp;encoding&nbsp;a procedure call into a highly inefficient language&nbsp;designed for text mark-up, hailed as unreadability, for the sake of&nbsp;human readability (XML).&nbsp; Then we are sending that information to an HTTP server, which is nothing less than a protocol for invoking remote functions.&nbsp; In return, we'll either get an error from HTTP or we'll get a SOAP response&nbsp;containing the error or results in XML format.</p><p>We don't need garbage collectors to sweep up all of our abandoned pointers.&nbsp; GC doesn't actually solve problems such as memory leaks and seems to succeed only in limiting the scalability of applications.&nbsp; I know I just offended&nbsp;some sensibilities, but I've been down some long an painful roads for this perspective.&nbsp; Besides with proper utilization of value semantics, we wouldn't be so concerned with heap management.</p><p>We certainly don't need a another &quot;post-relational&quot;&nbsp;DBMS based on ideas that&nbsp;predate the Relational Model.&nbsp; Though languages such as SQL seem ancient, the relational model will not become old any more than the notion of an integer will.&nbsp; Okay, think of it as old and wise if you must.</p><p>We don't need more integration &quot;solutions&quot;.&nbsp; ETL has been done... and done... and done.&nbsp; Nor is it the &quot;answer&quot;.&nbsp; If there was one way to look at all data, then suddenly integration looks no different&nbsp;than construction.&nbsp; I'm talking about federation... another thing enabled by our friend the Relational Model.</p><p>We don't need another registry, repository, directory, or other pseudo database system.&nbsp; These things have been around since the dark ages of computing and they've always been a blight.&nbsp; The operating system itself should provide&nbsp;a consistent data management platform; used all the way from the core of the OS, all the way up to the highest levels of application logic.&nbsp; The data structure of&nbsp;today's operating system is without a doubt the C struct.&nbsp; The data structure of the future OS is the Relation.&nbsp; Picture the Woodstock of software, with applications and systems holding hands and singing the same tune.&nbsp; Picture full visibility into every code and data facet of every application and system.&nbsp; Now *that's* open.</p><p>We don't need yet another method of querying, sorting,&nbsp;searching,&nbsp;and presenting data.&nbsp; How many times are we doing to have to work out the logic to refresh forms properly at all the right points?!&nbsp; Even still, people remain skeptical that&nbsp;such&nbsp;things can be automated; that it is somehow different from application to application.&nbsp; I assert that it is not different.&nbsp; Even the cleverest human interaction examples are mere&nbsp;specializations of the same, age old, patterns for the presentation and manipulation of data.&nbsp; Yet developers are handed framework after framework with gaping holes where&nbsp;data presentation and manipulation happens.</p><h6>Conclusion... finally!&nbsp;</h6><p>I've been accused of often being preachy and leaving people on a downer.&nbsp; I realize that I am guilty of both of these things in this posting.&nbsp; Frankly I'm not sure how to fix that other than to re-assure the reader that I hardly consider the situation hopeless.&nbsp; As long as I am able, I will be working towards solving these issues.&nbsp;&nbsp;In fact, I must admit a certain joy I receive in seeing such large scale problems because I&nbsp;believe that&nbsp;they are&nbsp;fixable, and I thoroughly enjoy working towards&nbsp;a solution.</p>]]>
        
    </content>
</entry>
<entry>
    <title>My Favorite Vista Feature</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/my_favorite_vista_feature.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=19" title="My Favorite Vista Feature" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.19</id>
    
    <published>2008-06-06T19:46:16Z</published>
    <updated>2008-06-06T19:46:16Z</updated>
    
    <summary>With so many great new features, it&apos;s hard to pick my favorite one, but I think today I finally made up my mind: My favorite new feature of Windows Vista is that you have to reboot to delete files. Sure...</summary>
    <author>
        <name>Bryn</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>With so many great new features, it's hard to pick my favorite one, but I think today I finally made up my mind: My favorite new feature of Windows Vista is that you have to reboot to delete files. Sure the Windows Explorer will let you delete files, but most of the time, what you really want is to have a shadow of those files remain and to get an access denied error whenever you try to select them. Microsoft knew this is what users really wanted and built this functionality right into the core of the operating system. Only after a good healthy reboot will the files actually be gone.</p><p>And speaking of the reboot, it's not a big deal because Microsoft knew that I wanted to eat lunch at this time anyway, so they made the reboot take about twenty minutes, just enough time for me to grab a sandwich!</p><p>Another great feature is that once it does come back up, the operating system knows that my favorite game is dual monitor roulette! I just love wondering which monitor is gong to be recognized! Which one will be selected as my main monitor? And best of all, which one is going to have it's resolution randomly changed? Always keeps me on my toes, I just love it!</p><p>Oh and where is my sidebar anyway? I swear I had that docked to my other monitor. Guess it's time for another round of 'configure your desktop'!</p><p>Bryn Rhodes<br />Alphora</p><p>&nbsp;</p>]]>
        
    </content>
</entry>
<entry>
    <title>Credit Where Due...Almost</title>
    <link rel="alternate" type="text/html" href="http://databaseconsultinggroup.com/blog/2008/06/credit_where_duealmost.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://databaseconsultinggroup.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=18" title="Credit Where Due...Almost" />
    <id>tag:databaseconsultinggroup.com,2008:/blog//1.18</id>
    
    <published>2008-06-06T03:09:56Z</published>
    <updated>2008-06-06T03:09:56Z</updated>
    
    <summary>So today I had the opportunity to discover how the new AT clause of the EXECUTE command in SQL Server 2005 works. The clause allows a statement to be executed &apos;at&apos; a specified linked server. Pretty useful, because I couldn&apos;t...</summary>
    <author>
        <name>Bryn</name>
        
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://databaseconsultinggroup.com/blog/">
        <![CDATA[<p>So today I had the opportunity to discover how the new AT clause of the EXECUTE command in SQL Server 2005 works. The clause allows a statement to be executed 'at' a specified linked server. Pretty useful, because I couldn't connect to the server in question, but I could access it as a linked server. </p><p>There's a gotcha though, the AT clause only allows you to specify the name of a linked server, not the database in which the statement will run. As with most new features of SQL Server over the years, it's useful until you actually need to use it, then there's some exception to the rule that prevents you from using it in exactly the scenario that you need it most.</p><p>Of course, you can execute a 'use' statement remotely and this correctly sets the context, but if you need to recreate a stored procedure, no dice. A create procedure statement must be the first statement in a batch.</p><p>So I tried to actually set the Catalog of the linked server. After a painful stint of researching 'documentation' (which in the end consisted of using sp_helptext to read the relevant procs myself), I found that 1) in order to configure a linked server, you just add it again with the new properties (of course, why didn't I think of that), and 2) you can't set the property I wanted to set if your linked server happens to be a SQL Server anyway! Grrr....</p><p>So I wondered whether wrapping the whole thing in an explicit transaction would force the server to use the same connection and result in the effects of the database context switch from one execute statement to remain in effect for subsequent execute statements. Voila!</p><p>At the root of this problem is the almost unbelievable complexity of T-SQL as a language. And it's not because the problem space is actually that complicated, it's because the language has so many inconsistencies and special cases that no two features work together in the expected way. Over the years of my involvement with T-SQL the problem has only gotten worse as every new feature that is added brings its own set of special case scenarios, which is exactly what happened here.</p><p>So thanks for adding the ability to execute a statement on a linked server, but didn't anyone ask the question 'Which database is this going to run in?'</p><p>Bryn Rhodes<br />Alphora</p><p>&nbsp;</p>]]>
        
    </content>
</entry>

</feed> 

