Monthly Archives: March 2007

Boat Street Café (Seattle, WA)

Rating:

Tonight Lauren and I indulged ourselves with massages at Ananda Spa (which is deserving of its own space for a review). Across the patio of the Northwest Work Lofts from Ananda Spa is the Boat Street Café. It turns out that the name comes from when the café was located on Boat Street (they were forced to relocate when that building was torn down). The food always smelled fantastic, and we often thought of stopping by for a post-massage meal. Tonight (at long last) we were able to check it out.

The menu is French-inspired, as is the café’s ambience — slate tables, fresh flowers, and minimalist touches. The very friendly waitress brought us some fresh bread to start off the meal. Yes this is a common occurrence, but the fresh mini-baguette that came straight from the oven to our table was worth calling out. I was tempted to make a meal of the baguette and butter…

But I needed to save room for the Black Cod with Pickled Peppers. Rich, silky, and buttery, the cod was matched well with the peppers and onions. Very tasty, but not meant for those looking for “lighter fare”.

Our other entree took advance notice (“30 minutes from oven to table” according to the waitress): Leek and Goat Cheese Flan. It was worth the wait, though one look at the overflowing dish that could feed a small family and I knew what we’d be having for breakfast tomorrow 🙂 This souffle contained a relatively mild goat cheese, and a fluffy texture overlaying the leeks and onions.

Overall the food was very good, and the waitstaff very pleasant. Given the richness of the cuisine however, it would be a difficult place to frequent more than once a month or so. Lunch did look like a more casual, order from the counter-based affair. I’ll report back when we have a chance to check that out!

Boat Street Café
3131 Western Ave., Suite 301
Seattle, WA 98121
206-632-4602

Tues-Sat: 11:00AM-2:00PM, 5:00PM-10:00PM (Lunch and Dinner)

Client (TCP and Named Pipe) Connection Pooling

Using the TCP and Named Pipe bindings give you a very clean mapping between IDuplexSessionChannel and the underlying network resource (socket or pipe). Namely, you can effectively treat a channel as 1-1 to a socket (I will use socket as shorthand for the generic “network resource” for the remainder of this post :)).

That being said, the lifetime of the underlying socket is not necessarily 1-1 with the lifetime of the channel. Due to our connection pooling feature in WCF, a connection can be reused over the lifetime of multiple channels. We perform connection pooling for both buffered and streaming channels. Our connection pool is configurable through TcpConnectionPoolSettings/NamedPipeConnectionPoolSettings. These settings include a GroupName that we use for isolation, an upper bound on our cache size (MaxOutboundConnectionsPerEndpoint), and timeout values for reliability and NLB support

The way connection pooling works on the client is as follows:

  • When you open a channel we will first look for a connection in our pool. This lookup is performed based on IP+port for sockets and based on endpoint Uri name for Pipes.
  • If we find an available connection in our pool then we will attempt our open handshake using .Net Framing. If this succeeds then we will associate the connection with the new channel and return from Open. If it fails then we’ll discard the connection. If we have not yet exceeded the binding’s OpenTimeout then we will repeat the “look in pool” process.
  • If no [valid] connections are found in our pool then we will establish a new connection (again, using up to the time remaining in OpenTimeout).
  • When you close a channel, after we perform our close handshake we will consider returning the connection to our pool. If we already have reached MaxOutboundConnectionsPerEndpoint, or the connection’s lifetime has exceeded LeaseTimeout then we will close the connection instead. The connection that is returned to the pool is the “raw” connection (the one that was initially accepted, prior to any security upgrades). In this way we can provide a transparent pool without leaking any security or other information.

I was going to cover the server-side usage of connection pooling in this same post, but the process of accepting and reusing connections on the server is worthy of its own topic next time 😉

Thai Tom Faceoff, Round 2

Eight months ago, Lauren and I started on an NCAA-style tournament through the 16 dishes on Thai Tom’s menu. Today began round 2, and I expect the last few meals to come out in rapid succession. This is an inexact science, as 3 chefs rotate through Thai Tom’s burners. For example, while #10 was a clear favorite based on previous tastings, today it fell short. Was it due to the change in chefs? A bad delivery of eggplant? Who knows, but it just didn’t have the gusto needed to hold up against the sassy Swimming Rama’s peanut sauce.

It is becoming clear that there are two classes of dishes at Thai Tom (Division I and Division II if you will). Dishes such as Sweet and Sour Chicken are solidly in division II, and Garlic Beansprouts is permanently disqualified (a mini-dead kenny for it). If we decide to re-stage the tournament again, we would restrict entry to Division I (I’ll provide a full breakdown when all is said and done). A recap of the current state of affairs follows:

Thai Tom Tournament

UPDATE (04/11/2007): After a break for Passover, Panang Curry handly overran #4 (Thai Sauce Chicken) as the quarter finals continue.

UPDATE (04/17/2007): Cashew Chicken cruised to an easy win over the popular, but less exciting, Pad Thai.

UPDATE (04/24/2007): Completing round 2 was a close match between #9 and #12. At the end the garlic was king for Garlic Pepper Chicken.

UPDATE (05/02/2007): They were out of Panang Curry (next time I’m instituting a forfeit rule!). So it was a back-to-back Garlic Pepper Chicken appearance, but it was no match for Cashew Chicken.

UPDATE (05/12/2007): In the closest match yet, Panang Curry squeaked by Swimming Rama (probably #1 and #2 seeds in next year’s match :))

UPDATE (06/20/2007): The winner of the 2006-07 Thai Tom crown is….Panang Curry!

Boilerplate code for custom Encoder Binding Elements

Part of the process involved in writing a custom MessageEncoder is hooking your encoder up to a binding stack. This is accomplished using a subclass of MessageEncodingBindingElement. The way our build process works is that we will take the first BindingElement within a Binding, and call [Can]CreateChannel[Factory|Listener]() on it. By default, these 4 calls will simply delegate to the BindingElement “below” them in the stack.

This default behavior is not exactly what you want in your MessageEncodingBindingElement. While most binding elements add an item to the channel stack, Message Encoders are an “adjunct” binding element. That is, they provide parameters to other binding elements (in this case the transport). The way that parameters are provided to other parts of the build process is through BindingParameters. For example, a MessageEncodingBindingElement can add itself to the BindingParameters collection:

context.BindingParameters.Add(this);

And later the TransportBindingElement can fish out the encoder when it is building the relevant factory/listener:

Collection<MessageEncodingBindingElement>messageEncoderBindingElements
= context.BindingParameters.FindAll<
MessageEncodingBindingElement>();

Unfortunately, the base MessageEncodingBindingElement does not take care of adding itself to the BindingParameters collection in its default [Can]Build methods. Therefore, every subclass needs to add the following four boilerplate overrides. Furthermore, it will be a breaking change to fix this in V2, so it’s unclear if we will be able to fix this in the next release 🙁

public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.BuildInnerChannelFactory<TChannel>();
}

public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.BuildInnerChannelListener<TChannel>();
}

public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.CanBuildInnerChannelFactory<TChannel>();
}

public override bool CanBuildChannelListener<TChannel>(BindingContext context)
{
  
if (context == null)
  {
    
throw new ArgumentNullException("context");
  }

  context.BindingParameters.Add(this);
  
return context.CanBuildInnerChannelListener<TChannel>();
}