OdeToCode IC Logo

Trying Out Persistence Ignorance with LINQ (Part I)

Monday, August 27, 2007 by scott

In June, Ian Cooper wrote an article (Being Ignorant With LINQ to SQL) that provided marvelous details about using POCOs with persistence ignorant repositories. Ian's conclusion: "LINQ to SQL is usable with a TDD/DDD approach to development. Indeed the ability to swap between LINQ to Objects and LINQ to SQL promises to make much more of the code easily testable via unit tests than before."

I've been tinkering along the same lines as Ian, and although I think I started working at the other end of the problem first, I'm reaching the same conclusions (and ended up with much of the same code).

I started working with a trivial case, thinking if the trivial case becomes difficult, the topic isn't worth pursuing. Let's suppose we have the following class.

public class FoodFact
{
    
public int ID
    {
        
get { return _id; }
        
set { _id = value; }
    }
    
    
public string Name
    {
        
get { return _name; }
        
set { _name = value; }

    }

    
public int Calories
    {
        
get { return _calories; }
        
set { _calories = value; }
    }

    
int _id;
    
int _calories;
    
string _name;
}

The idea is that each FoodFact object will ultimately be persisted as a row in a SQL Server database, but I don't want to clutter up the FoodFact class with unrelated attribute decorations or other database nonsense. To get into the database, I do need some sort of gateway, or class that can track POCO objects and determine if they need persisted. In LINQ, this class is the System.Data.Linq.DataContext class. The DataContext class itself doesn't implement any interesting interfaces, so my plan was to abstract the DataContext in a a stubable, fakeable, mockable fashion.

public interface IUnitOfWork : IDisposable
{
    
IDataSource<T> GetDataSource<T>() where T : class;
    
void SubmitChanges();
}

We have not looked at IDataSource yet, but there will be at least two implementations of IUnitOfWork. One implementation will work against a real database using a persistent data source (where FoodDB is a class derived from DataContext):

public class UnitOfWork : IUnitOfWork
{
    
public UnitOfWork()
    {
        _context =
FoodDB.Create();
    }

    
public IDataSource<T> GetDataSource<T>() where T : class
    {
        
return new PersistentDataSource<T>(_context);
    }
  
    
public void SubmitChanges()
    {
        _context.SubmitChanges();
    }

    
public void Dispose()
    {
        _context.Dispose();
    }

   
FoodDB _context = null;
}

Another implementation will work with an "in memory data source". This class would be defined in a unit test project.

class InMemoryUnitOfWork : IUnitOfWork
{
    
public IDataSource<T> GetDataSource<T>() where T : class
    {
        
return new InMemoryDataStore<T>();
    }
    
    
public void SubmitChanges()
    {
        
    }

    
public void Dispose()
    {
        
    }
}

The goal is to consume IUnitOfWork along these lines:

public class FoodFactRepository
    :
IRepository<FoodFact>
{
    
IDataSource<FoodFact> _dataSource;
    
IUnitOfWork _context;
    
    
public FoodFactRepository(IUnitOfWork context)
    {
        
Check.ArgIsNotNull(context, "context");
        
        _context = context;
        _dataSource = _context.GetDataSource<
FoodFact>();

        
Check.IsNotNull(_dataSource, "Could not retrieve a data source");
    }

    
public FoodFact FindByID(int ID)
    {
        
return
            (
                
from fact in FoodFacts
                
where fact.ID == ID
                
select fact
            ).FirstOrDefault();
    }

    
public FoodFact Add(FoodFact fact)
    {
        
Check.ArgIsNotNull(fact, "fact");

        _dataSource.Add(fact);
        
return fact;
    }

    
public IDataSource<FoodFact> FoodFacts
    {
        
get { return _dataSource; }
    }        

    
// ...

What are these data sources? Stay tuned for part II ...

Handling Faults in Windows Workflow Custom Activities

Friday, August 24, 2007 by scott

Here is one I had to track down recently.

The code in the following activity is trivial, but FaultyActivity represents any activity that might throw an exception during Execute and overrides HandleFault (which the WF runtime will schedule to run when it catches the exception tossed up by Execute).

public partial class FaultyActivity: Activity
{
   
public FaultyActivity()
   {
      InitializeComponent();
   }

    
protected override ActivityExecutionStatus Execute(
                        
ActivityExecutionContext Context)
    {
        
// something went wrong
        throw new InvalidOperationException();
    }

    
protected override ActivityExecutionStatus HandleFault(
                        
ActivityExecutionContext context,
                        
Exception exception)
    {
        
// something still went wrong
        throw new InvalidOperationException();
    }
}

The problem is that once an activity enters the Faulting state, it can only transition to Closed or back to Faulting. If another exception escapes during fault handling, the activity transitions back into the Faulting state, and WF schedules HandleFault to execute again - it’s an infinite loop if the exception continues to occur.

Adding some tracing to the app config file..

<system.diagnostics>
    <
switches>
        <
add name="System.Workflow.Runtime" value="All" />
    </
switches>
</
system.diagnostics>

.. confirms the problem (abridged version):

Activity Status Change - Activity: faultyActivity1 Old:Initialized; New:Executing
Scheduling entry: ActivityOperation((1)faultyActivity1, Execute)
Execute of Activity faultyActivity1 threw System.InvalidOperationException
Activity Status Change - Activity: faultyActivity1 Old:Executing; New:Faulting
Scheduling entry: ActivityOperation((1)faultyActivity1, HandleFault)
Compensate of Activity faultyActivity1 threw System.InvalidOperationException
Activity Status Change - Activity: faultyActivity1 Old:Faulting; New:Faulting
Scheduling entry: ActivityOperation((1)faultyActivity1, HandleFault)
Compensate of Activity faultyActivity1 threw System.InvalidOperationException
Activity Status Change - Activity: faultyActivity1 Old:Faulting; New:Faulting
Scheduling entry: ActivityOperation((1)faultyActivity1, HandleFault)
Compensate of Activity faultyActivity1 threw System.InvalidOperationException ...

The sinister aspect to this behavior is that if enough workflows get into the infinite faulting loop, the threadpool becomes starved and the entire application just sits and spins with no work getting done.

Moral of the story – never let an exception escape from HandleFault.

Images That Strike Fear In A Developer's Heart

Thursday, August 23, 2007 by scott

Anytime you open up a design tool, and see something like this ...

... you know you'll need stiff drink at the end of the day. It doesn't matter if the boxes represent tables or classes – it's a complicated mess. In this case, the screenshot is from a Visual Studio 2005 Analysis Services project.

Anyone have some aspirin to spare?

What's Wrong With This Well?

Wednesday, August 22, 2007 by scott

Water . When you don't have it - you can find out who your true friends are. Your true friends are the ones who open the door when you are standing outside with a towel, toothbrush, razor, and clean pair of underwear in hand.

Last week I turned the tap at the kitchen sink and .... nothing happened. Plumbing is far beyond my area of expertise, so I called for professional help. The plumber poked around and decided everything from the well pump to the kitchen tap was in perfect working order. Like any good debugging session, there was only one possibility left – not enough water left in the well.

There are about 20 million people in the United States drawing water from private wells. These wells can go dry for a number of reasons. A lack of rain is one reason, but there is also overdraft (removing too much water from the ground) and the mysteries of geological change.

I had three options:

  1. Fill the well.
  2. Drill a new well.
  3. Frack the existing well.

In option 1, I call someone who can pour a truckload of water into the well. This solution is viable when there is a severe drought and the water table has dropped below the well. The standard 15 cm diameter well can hold about 1.5 gallons of water per foot of depth. I'd be hoping that heavy rains can once again raise the water table and the well will begin a natural recovery before exhausting the pumped in water. We've been dry, but it didn't sound like this was a long term solution to my problem.

In option 2, I faced a few unknowns. Nobody can tell me how deep someone will need to drill before reaching an aquifer. Wells in my area can range from 100 feet to 900 feet (30m to 270m) in depth. Since a well driller might charge anywhere from $20 to $40 a foot, there is a lot of variability in the cost.

Option 3 is something I hadn't previously heard of. In fact, when someone suggested "fracking" my well, I took it as a euphemism for "screw it - fuggetaboutit - it's dead". As it turns out, "fracking" means "hydro-fracturing" - a technology adopted from the oil and gas industries. The frackers can give you a set cost ($2k - $4k), and fracking works 97% of the time. Fracking is the option I took. Fracking uses high pressure to clean the rock fissures of sediment and create new fractures in the rock, thus allowing more water into the well.

The fracking took about 4 hours. First, the frackers have to remove the pump, hose, and cables from the well. Next, the frackers lower a packer into the well, and inflate the packer (think of a packer as a heavy-duty balloon). The frackers then fill the area under the packer with potable, chlorinated water and add pressure. Tremendous amounts of pressure – typically 1000 to 3000 psi. The frackers continue to add water and raise the pressure until the pressure drops off and stabilizes. For my well, the drop-off happened at 1500 psi. After that point, there is the reinstallation of the pump and the cleanup.

Water flows once again!

Here are two of the links I found interesting during this process.

Wellowner.org – informing consumers about ground water and water wells.

USGS – Ground Water and the Rural Homeowner

Configuration Free JSON with WCF and AJAX in Visual Studio 2008 Beta 2

Tuesday, July 31, 2007 by scott

With all the out-of-band technology releases we've had (ASP.NET AJAX, .NET 3.0), it's nice to reach a point where we can bring them all together.

As an example...

Create a new web site in Visual Studio 2008. This will have to be a website under IIS, unfortunately, for reasons I'll point out later. Once the web site is up, add a new item – a WCF service. The service contract can look like the following:

[ServiceContract(Namespace="https://odetocode.com/ws",
                 Name=
"ServerProcessInfo")]
public interface IServerProcessInfo
{
   [
OperationContract]
    
IEnumerable<ProcessInfo> GetRunningProcesses();
}

The data contract can look like so:

[DataContract]
public class ProcessInfo
{
    [
DataMember]
    
public string Name { get; set; }

    [
DataMember]
    
public long WorkingSet { get; set; }
}

Finally, the LINQish implementation:

public class ServerProcessInfo : IServerProcessInfo
{
    
public IEnumerable<ProcessInfo> GetRunningProcesses()
    {
        
return
              (
                
from p in Process.GetProcesses()
                
orderby p.WorkingSet64 descending
                 select new ProcessInfo
                 {
                     Name = p.ProcessName,
                     WorkingSet = p.WorkingSet64
                 }
              ).Take(10);
    }
}

We can entirely remove any WCF <system.serviceModel> configuration from web.config. Instead of all the XML configuration goo, we just need a Factory attribute in our .svc file:

<%@ ServiceHost Language="C#" Debug="true" Service="ServerProcessInfo"
  
...
  Factory
="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>

What magic does this factory give us? Well, we can add a ServiceReference via a ScriptManager (it's nice that AJAX extensions are in the toolbox by default), and write some script:

<asp:ScriptManager ID="ScriptManager1" runat="server">
  <Services>
    <asp:ServiceReference Path="~/ServerProcessInfo.svc" />
  </Services>
</
asp:ScriptManager>
        
<script type="text/javascript">

var
ws = new odetocode.com.ws.ServerProcessInfo();
ws.GetRunningProcesses(getRunningProcessesComplete);

function getRunningProcessesComplete(result)
{      
    
for(var i = 0; i < result.length; i++)
    {
         document.write(result[i].Name,
" ", result[i].WorkingSet);
         document.write(
"<br />");

    }    
}

Voila! Zero configuration and we have JSON on the wire!

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.0
X-Powered-By: ASP.NET
Date: Tue, 31 Jul 2007 03:08:10 GMT
Content-Length: 662

{"d":[{"__type":"ProcessInfo:#","Name":"devenv","WorkingSet":51011584},
{"__type":"ProcessInfo:#","Name":"w3wp","WorkingSet":44748800},
{"__type":"ProcessInfo:#","Name":"Fiddler","WorkingSet":34213888},
...
}

Note: there is a problem in Beta 2 that prevents this magic from working with WebDev.exe. The error you'll see with WebDev (aka Cassini) is:

"IIS specified authentication schemes 'Ntlm, Anonymous', but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used."

Unfortunately, twiddling with the NTLM checkbox for WebDev doesn't help. Thus, the current need for IIS.

Some Cool Software You Might Not Know About

Thursday, July 26, 2007 by scott

Sahil's post on "Things I can't live without" got me thinking about some software I use that might not be so well known. XM Radio Studio

XaMp Studio plays XM Radio from a desktop application. Looks like Winamp and offers more features than the XM web interface. There is a toast notification to tell you when your favorite artist or tune is streaming. Note: don't download the "desktop" edition, as it seems incompatible with Vista and Windows Media Player 11.

DynDNS Updater coupled with the DynDNS service can give any computer a name – even if your ISP hands out dynamic IP addresses. The Updater can run as a Windows service to keep addresses in synch.

FoxIt Reader is a small, fast PDF reader. Scott Hanselman first mentioned Foxit a couple years ago, and the feature list has grown since that time. The only downside is that Foxit does not seem to decrypt password protected PDF files, so no e-book reading with Foxit.  

Robocopy now comes standard in Windows Vista. It's the tool I use for large file operations, particularly when moving bits over the network. Robocopy easily beats copying files using Windows Explorer, after all, the "robo" is short for robust.

There is only one weakness with robocopy. Try copying an Outlook PST file when Outlook is running:


PS> robocopy C:\Users\bitmask\appdata\Local\Microsoft\Outlook d:\temp outlook.pst

-------------------------------------------------------------------------------
   ROBOCOPY     ::     Robust File Copy for Windows
-------------------------------------------------------------------------------

  Started : Tue Jul 24 12:33:20 2007

   Source : C:\Users\bitmask\appdata\Local\Microsoft\Outlook\
     Dest : d:\temp\

    Files : outlook.pst

  Options : /COPY:DAT /R:1000000 /W:30

------------------------------------------------------------------------------

                           1    C:\Users\bitmask\appdata\Local\Microsoft\Outlook\
  0.0%      New File             856.3 m        Outlook.pst
2007/07/24 12:33:20 ERROR 33 (0x00000021) Copying File C:\Users\bitmask\appdata\Local\Microsoft\Outlook\Outlook.pst
The process cannot access the file because another process has locked a portion of the file.
Waiting 30 seconds...

Which brings me to my "last but not least" entry: Hobocopy.

PS> .\hobocopy C:\users\bitmask\appdata\local\microsoft\outlook\ d:\temp outlook.pst
HoboCopy (c) 2006 Wangdera Corporation. hobocopy @ wangdera.com

Starting a full copy from C:\users\bitmask\appdata\local\microsoft\outlook\ to d:\temp
Copied directory
Backup successfully completed.
Backup started at 2007-07-22 12:46:25, completed at 2007-07-22 12:47:48.
1 files (856.39 MB, 1 directories) copied, 7 files skipped

Hobocopy is Craig Andera's tool that uses the Volume Shadow Service to copy locked files. Pure goodness.

ASP.NET and Separating Concerns

Wednesday, July 25, 2007 by scott

Ayende had a recent post with the following quote from Nicholas Piasecki:

To me, this discussion all boils down to one thing: the foreach loop. Let's say you want to display a table of sales reports, but after every tenth row, you want to print out an extra row that displays a running total of sales to that point. And you want negative numbers to appear in red, positive numbers to appear in green, and zeros to appear in black. In MonoRail, this is easy; with WebForm's declarative syntax, just shoot yourself in the face right now. Most solutions I've seen end up doing lots of manipulation in the code-behind and then slamming it into a Literal or something, which to me defeats the purpose of the code separation.

Ayende says this is the essence of why he dislikes WebForms. In the comments, someone proposed a rails solution ...

#set ($i = 0)
#set ($running_total = 0)
#foreach ($report in $reports)
#each
    <tr>
        <td>$report.name</td>
        #if ($report.ammount > 0)
            
<div class="green">
        #elseif ($report.ammount < 0)
            
<div class="red">
        #else
            
<div class="black">
        #end
        $report.ammount
</td>
    </tr>

    #set ($running_total = $running_total + $report.ammount)
    #set ($i = $i + 1)
    #between
    #if (($i % 10 ) == 1)
    
<tr class="Running Total">
        <td>$running_total</td>
    </tr>
    #end
#end

... which received praise for elegance. I'm thinking if you really want to intermingle code and markup, than open up an .aspx page and have at it:

<%@ Page Language="C#" %>
<%  
    SalesReport report = new SomeApplicationService().GetSalesReport();
    int rowCount = 0;
    
int runningTotal = 0;
%>
<table>
  <% foreach (Salesperson p in report.SalesPeople) {
     rowCount++;
     runningTotal += p.TotalSales;
  %>
  
<tr>
    <td><%= p.Name %></td>
    
<td>
      <div class="<%= p.TotalSales < 0 ? "red" : p.TotalSales > 0 ? "green" : "black" %>">
        <%= p.TotalSales.ToString("c")  %>
      
</div>
    </td>        
  
</tr>
        
  <%
if(rowCount % 10 == 0) { %>
  
<tr>
    <td>SubTotal:</td>
    <td><%= runningTotal.ToString("c") %></td>
  </tr>
  <% } // end if %>  
<% }
// end foreach %>
</table>

Why throw out the baby with the bathwater?