Aug 29, 2009

WS-Discovery 101: Basic Discovery

I could talk at you all day about why this is cool and why you need this, but how about a sample, shall we?  To start, we’ll convert an existing simple Client/Server application to use discovery to allow the client to find its service.

Service Modifications

These are the modifications that need to be done to the service to get it to respond to probe requests.  It is 100% configuration driven (nice!).

Add Discovery Service Behavior

In the demo service, we were already exposing metadata using a service behavior, so we can just add the behavior to the existing behavior configuration

<behavior name="MyServiceBehavior">
    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
    <serviceDiscovery />
</behavior>

So what we’ve done is instructed the service to publish endpoint information to clients that send a probe request, but we don’t get any use out of that until we tell the service what endpoints are important enough to tell anyone who asks about them.

Add Discovery Endpoint Behavior

The discovery endpoint behavior identifies those endpoints that need to be made available through WS-Discovery probe requests.

<system.serviceModel>
    <behaviors>
        <endpointBehaviors>
            <behavior name="PublishEndpoint">
                <endpointDiscovery />
            </behavior>
        </endpointBehaviors>

And here we are applying this behavior to the only endpoint we have:

<service behaviorConfiguration="MyServiceBehavior" name="BasicSample.Service.EchoService">
    <endpoint address="http://localhost:8080/EchoService/svc" 
              behaviorConfiguration="PublishEndpoint"
              binding="basicHttpBinding"
              name="httpEndpoint"
              contract="BasicSample.Service.IEchoService" />

Add UDP Endpoint for “Discoverers”

Without an endpoint to talk on, a service would never be free to handle incoming probe requests.  To do this, we simply add a UDP discovery endpoint longside the existing “httpEndpoint”.

<endpoint name="udpDisco" kind="udpDiscoveryEndpoint" />

That’s it!  When your service starts up, it’s ready to respond to WS-Discovery probe requests.

None of this is any good unless your client uses it.

Client Side Changes

Clients will send out a message to the network, looking for an appropriate service.  Unfortunately, this portion is not config-driven, however this process almost always will be slightly customized for the needs of the client, so it makes sense to do a bit of this discovery in code.

Remove the address and add a Dicovery Endpoint

First step is to prove to yourself that this works.  Delete the address!

When we are probing the network for a service, we need an endpoint capable of sending out these messages.

<client>
    <endpoint name="udpDisco" kind="udpDiscoveryEndpoint" />
    <!-- No address information! -->
    <endpoint binding="basicHttpBinding" contract="EchoProxy.IEchoService"
      name="BasicHttpBinding_IEchoService" />
</client>

Add Discovery Code

We need to add a reference in our client project to “System.ServiceModel.Discovery”.  This will give us access to a few classes we will need.

The only things left is to write the method that will search the network for the address of the service.  This will look something like this.

private static System.ServiceModel.EndpointAddress FindAddress()
{
    FindCriteria criteria = new FindCriteria(typeof(IEchoService));
    DiscoveryClient client = new DiscoveryClient();
    FindResponse response = client.Find(criteria);

    Console.WriteLine("Found {0} service(s).", response.Endpoints.Count);
    if (response.Endpoints.Count > 0)
    {
        return response.Endpoints[0].Address;
    }
    return null;
}

Notice here that we are searching the network for some pretty simple criteria (the service contract type) and that’s all.

Tying it all together

Now all we have to do is modify our typical client call to use the address that is returned from our FindAddress method.

private static void SendEcho(string textToEcho)
{
    EndpointAddress address = FindAddress();
    if (address != null)
    {
        using (EchoProxy.EchoServiceClient client = new EchoProxy.EchoServiceClient())
        {
            //use our newly found address
            client.Endpoint.Address = address;
            string result = client.Echo(textToEcho);
            Console.WriteLine(result);
        }
    }
}

That’s it!

Those of you following along at home will notice that this method takes some time to complete.  In the next post in the series, We’ll go over some ways you can optimize the time it takes for a probe to happen.

The code for this article is available here:

Aug 26, 2009

WS-Discovery 101: What is this thing?

This is a continuation of a series of posts on the new WS-Discovery features coming in WCF in NET 4.0. For the entire series, see here.

Windows Communication Foundation has had one of the most profound effects to the type of applications I see written since .NET 1.0 in my opinion. It made creating a Service Oriented Architecture that much more attainable.

If you look at any list of SOA Principles, there is (arguably) only one thing missing from Microsoft’s WCF strategy where it applies to SOA: Discoverability. This is what makes the addition of WS-Discovery so important to WCF. It paints a complete picture of a path to service orientation that was previously a lot of work to implement.

This is not to say that only those shooting for the lofty and often “enterprise” specific goal of SOA is the only reason to use WS-Discovery. You’d use WS-Discovery if you like any of these things:

  • Client finds endpoints that host a service without pre-configuration or a central store of endpoint information
  • Client finds all endpoints across a network that match certain criteria (contract, scope, etc).
  • Service is able to publish additional metadata about its endpoints to clients prior to use
  • Clients or a central service are notified when a service goes up or down

These are just a few of the features you get from WS-Discovery out of the box with very little configuration or coding.

Let’s talk about a few key words that will help when reading future articles.

Probing

Probing is the process of sending out a request to either an entire network subnet via a UDP multicast message (referred to as “Ad-Hoc discovery”) or to a central discovery proxy (proxies will be described at length in a later article).

Basically we are sending out a request saying “here’s what I’m looking for… is anyone out there that matches this criteria?”. Here’s a (hopefully) helpful diagram.

Any services that either don’t respond to discovery probes or aren’t a match for the criteria simply don’t respond to the probe request.

Announcement

Announcement is the process by which a service that has newly come up announces its availability to either a central discovery proxy or to all clients on the subnet. In this case, the client can take advantage of “push” notification messages from services coming online, rather than probing the network to find a matching service. Here’s another basic diagram.

Now we have a common language we can work with for the rest of the series.

Aug 25, 2009

WS-Discovery Presentation for DFWCSUG

I gave a presentation recently at Dallas / Ft. Worth Connected Systems User Group on the new WS-Discovery related features in .NET 4.0. I had a good time and I hope everyone learned something. I promised I would post my code and notes. Better late than never, so here is that post.

If you didn’t make it to the meeting, I’ll be posting a series of WS-Discovery posts that go over the various parts of the talk.

All demos are .NET 4.0 / Visual Studio 2010 solutions built for VS 2010 Beta 1, available here.

Slides

Demos

I had essentially two demos.

1. WS-Discovery basics. Converting an existing Client/Server application using WCF to use WS-Discovery to get address information and options for optimizing the performance. Includes discovery by probing and by announcement.

2. WS-Discovery Proxies. Creating an intermediary between clients and services that both caches discovery requests and routes discovery requests and announcements outside of the local subnet.

To keep tabs on my posts on these samples as they become available, see this web page: WS-Disco 101.

Next WS-Discovery Article: What is this thing?

Mar 23, 2009

I Will Pay for Usability

The last phone that I purchased was the Samsung Blackjack II.  I had never owned a Windows Mobile device before, but I had been wanting a smartphone-like device for some time.  At the time this had Windows Mobile 6.0 on it.
I gave it one month.  Things that I observed that irked me to no end:
  • The browser was sort of silly...  felt like it was a checkmark on the features list... "Has Browser of a sort".
  • It took 9 keystrokes to call someone in my contact list (no exaggeration).
  • Buttons were too small w/ no auto correct.
  • There is a Start menu with things you need to get to a lot, and then in there is another "folder" with options that you actually need to get to more often.
  • Try calling "1-800-GOOG-411" on a Blackjack.  Just try.  You cannot enter letters using the keyboard in the dialer and the numbers don't show the corresponding touch-tone letters.  So unless you have either memorized the letter layout on a touchtone phone or have another phone with the letters on the buttons close by, you aren't getting anywhere.
  • To unlock the phone, you press "power, asterisk, 1".  The power button is on the top, almost requiring this to be a two-handed operation, aside from the fact that the asterisk and 1 keys are impossible to find on the tiny keyboard, especially when driving.
The thing in a nutshell was, though, that this was not a good phone or a good PDA or a good computer.
The whole thing came to a head when my wife was trying to call someone on my phone while I was driving and after several minutes of frustration trying to dial someone in my contacts list she said "you must get rid of this phone."  My wife is the Keeper of The Money, so for her to say I need to get rid of my phone and pay for a new one is darn rare.
When I used the Blackjack II I would always think about Alan Cooper's book The Inmates are Running the Asylum.  Most people I talk to who own one say it's "great", but what they don't realize is that they are comparing bad to worse.  Cooper calls this "Dancing Bearware":
"The sad thing about dancing bearware is that most people are quite satisfied with the lumbering beast. Only when they see some real dancing do they begin to suspect that there is a world beyond ursine shuffling.  So few software-based products have exhibited any real dancing ability that most people are honestly unaware that things could be better - a lot better."
The thing about the Blackjack was it was cheap: I paid $30 for it.  A friend of mine, Nicolas Webb, had just bought an iPhone for $400.  I thought he was nuts.  After playing with it for about 15 minutes I was hooked.
This is obviously a common reaction.  Bruce "Tog" Tognazzini of the Nielson Norman Group, a usability expert and a sometimes harsh critic of Apple design decisions, put it like this:
The iPhone really is a study in "delight." It really is wonderful that, in an industry rife with companies striving for mediocrity, one company is still doing things right. Those of us who flocked to Apple in the beginning did so not to build computers, but to change the world. Apple is once again doing just that.
Apple is now entering the consumer electronics world, where the lackluster attitude of "we'll fix it in the next release" is not good enough. The iPhone proves they are more than ready.
I think "delight" is a very accurate description of the experiences I have with the iPhone.  Pulling up a map of a friend's new house to get directions, then being able to add that address to their contact information with two clicks directly from the map is a "delight".
I can think of no better advertisement for the iPhone's usability than my 17 month old daughters using it.
There's not a snowball's chance in hell my daughter would have been able to do that with a Blackjack II.
I've since decided that it's worth it to me to pay extra for something that will not frustrate me.  It's not always the case that something has to be expensive to be usable.
I like to grill on charcoal.  Not those briquette things... the real charcoal.  I don't own one of those fancy propane grills.  One of the things that turns people off from charcoal grilling is that you have to make fire.  If you do it wrong, you'll be missing some eyebrows and your steak will taste like gasoline.  This is why I use a Weber Chimney Starter for my charcoal.
It's well-designed, with a conical grate which increases the surface area the burning newspaper will contact the coals, ensuring they light the first time every time. It also features a second handle, decreasing the chance you'll lose your red-hot coals on your foot.  It's well-built and will cost you a cool $10 at your local Home Depot, putting it right in line with other chimney starters price points, but far superior.  I never have to buy lighter fluid and my steak tastes like steak.  I would pay more, but in this case I didn't have to.
The bottom line is I and many people like me will pay to be delighted when using a product and I hope more manufacturers take note of this and stop producing Dancing Bearware and start producing products I can't wait to use.
Or pay for.

Feb 23, 2009

Type Conversion

I ran into a bit of confusing code recently while I was trolling through some code.  Here’s a simple example.

What Not To Do

This code had two classes that were very similar, but in terms of inheritance were not directly related.  Here I have a similar setup with two classes, Mammal and Table.

ClassDiagram1

Notice that they have identical properties, but you could safely say they had nothing to do with each other.  What’s why I found it odd that the code author was somehow able to get away with this:

Mammal dog = new Mammal();
dog.Color = "Brown";
dog.NumberOfLegs = 4;

//What??
Table dogTable = dog;

Now, I’ve seen some strange stuff in my time, but never have I seen someone get away from that assignment.  That shouldn’t even compile.

I looked into it further and the programmer had done something clever… a little too clever.

public static implicit operator Table(Mammal m)
{
  Table t = new Table();
  t.Color = m.Color;
  t.NumberOfLegs = m.NumberOfLegs;
  return t;
}

The programmer had overloaded the implicit cast operator for that type to allow implicit casting between the two types instead of writing some sort of helper method for conversion.

Several things are wrong with this approach, but the most obvious is the violation of the Principle of Least Surprise.  Kudos to the programmer for trying to simplify code, though.

What To Do

It’s fairly common to need to adapt from one type to another at runtime.  It’s very common these days to need to convert a data entity from a data store to a type that can be served from a service interface, for example.  There are quite a few ways to skin this particular cat.  I’ll show you two I use commonly.

The simple solution is to use a static adaptation method.  There are several advantages to this.  For one, it’s simple to understand.

public static class Converter
{
  public static Table ConvertToTable(Mammal m)
  {
      Table t = new Table();
      t.Color = m.Color;
      t.NumberOfLegs = m.NumberOfLegs;
      return t;
  }
}

You also isolate the coupling between these two types outside of the classes themselves.

The other thing that’s great about this is that it’s compatible with quite a few other scenarios, like converting a list of one entity to another.

Mammal[] mammalList = GetAllMammals();
Table[] tables = Array.ConvertAll(mammalList,
                                 m => Converter.ConvertToTable(m));

AutoMapper

Another, more elegant solution is a library called AutoMapper which comes courtesy of Jimmy Bogard (Twitter). Without writing any explicit conversion code, AutoMapper allows you to do things like this:

Mammal dog = new Mammal() { Color = "Brown", NumberOfLegs = 4 };
Table table = new Table();

//Setup code.  You only have to do this once.
//Maps are cached statically.
AutoMapper.Mapper.CreateMap<Mammal, Table>();

table = AutoMapper.Mapper.Map(dog, table);

Which is brilliant.  Converting an array of objects is just as easy.  I highly recommend this very flexible library.

Hopefully this gives you a few strategies for not confusing me and making your life easier.

Feb 9, 2009

Dirty Laundry in Public

I've been hosting with Ultimahosts.net for quite some time now for my blog. They have never been 100% reliable on the email side (I could expect outages every 4-5 months for hours at a time), but I had very few complaints on the website side of things. If things ever went wrong I could expect a reply from technical/billing/sales guy, Mark Schiavetta. Now, let's get one thing straight. Mark's a bit of a dick. I had come to expect a little dickishness from him over the years and as someone who is a bit of a dick myself, I was pretty ok with it. We did business and went our separate ways. Things went wrong today, though, starting with this email from billing@ultimahosts.net:
We have been trying to resolve this issue internally but have been unable to. On Friday 6th of Februrary [sic] our billing system was hijacked by a previous Ultima Hosts partner. As of now Ultima Hosts has no access to this billing system and therefore cannot cancel credit card authorization or process refunds / payments. Please contact your bank directly to cancel all credit card authorizations with Ultima Hosts USA... ...We are going to be offering free hosting in the month of Februrary [sic] to compensate you for this issue. We take full responsibility for giving access to this senstive [sic] data to someoone [sic] we trusted but who ultimately abused this trust.
Not more than an hour later, I received a billing notice that I was just charged 2x what I am normally charged for my hosting. By whom? Still unclear. I emailed billing@ultimahosts.net a short email saying "should I be worried about this? This is more than I usually pay." This is what I received back, supposedly from Mark:
We have paid this month's hosting fee in good faith after the actions of our ex-partners. Please make sure you cancel all credit card authorities with Ultima Hosts USA LLC.
I'm still a little confused, but ok. I start the process of following Mark's instructions. A little while later I receive an email from a third party I'd never heard of before, KineticHosts.com. The story starts to get epic right about here.
We are aware that Mark Schiavetta has recently sent out emails to you regarding billing with UltimaHosts USA, LLC. We regret that you, our valued customer, are brought into the middle of a business dispute. Let us first make this clear: if you wish to continue your hosting with Mark, we will be happy to refund your recent payments. We are, however, in the process of setting up a new hosting company that will live up to the values that started Ultima which, unfortunately, seemed to have been left in the dust by Mark. If you wish to move your hosting over to us, we will also be happy to accommodate this and will honor your payments in full. It has come to our attention that Mark is also claiming that your account was incorrectly billed and that the payment (PayPal) account was hijacked. This is inaccurate. Mark, on his own, decided that he was going to leave the LLC that was formed between himself, James and Dana. He also removed access to James' and Dana's access to resources held and paid for by the LLC. There had been ongoing negotiations on how to resolve the splitting of the LLC that we feel Mark participated in in bad faith, reneging on an agreement that had been reached to split the company with the shared hosting, which he has claimed that he wants to get out of, going to James and Dana and VPS and dedicated servers going to Mark. Some of you may have experience Mark's harsh attitude in recent months and we do apologize for that. He has claimed that he views shared hosting as a waste of time and did not want to provide the support that you, our customers, have every right to expect. Unfortunately, Mark is not in the US (he now lives in Uruguay) and feels that he can act as he wishes because he is beyond the reach of any and all authorities. (See www.expatworld.org for a description of what he's doing.) Additionally, the PayPal account which was used for UltimaHosts USA, LLC billing was to go to Dana and James. There are many issues with these charges. First, James is the contact for the LLC and the only one with the authority to act on its behalf. Second, the PayPal account that he is referring to is registered solely to James. So, it is not possible for James to have hijacked the billing system. Instead, Mark was "beaten to the punch" since, after revoking server access, Mark was certainly going to hijack the PayPal account himself. Before this, Mark also took money from the PayPal account without authorization. His message today is likely the result of our dispute of this unauthorized withdrawal. We are also actively investigating our legal options, though his location will make any remedies difficult to enforce. Again, we apologize that you have been brought into the middle of this dispute.
I couldn't decide whether to be angry or pleased at my string of luck being witness to this airing of dirty laundry in public. It's not every day you get to see something this pathetic and unbusiness-like. It doesn't stop there, though. I then receive an email shortly after that one from billing@ultimahosts.net (Mark):
Some clients are reporting that they have received unsolicited emails from a third party regarding the unauthorized billing. Rest assured your hosting is secure with us. Our primary concern at the moment is your financial data. Hosting will continue as normal. We are taking every step necessary to ensure that you are not adversely affected by the actions of an unauthorized third party. Please feel free to forward any future unsolicited emails and we will pass them onto the appropriate authorities.
Hosting was indeed continuing as normal, but not billing, apparently. In any case, I shot back this reply to both Mark and KineticHosts.com:
What I would like is to continue ... until such time as I can find an appropriate host outside of this little coup d'état. I don't care about the details of this sorted mess, I just want to keep my service as-is for a month or so. I need specific steps that I need to follow in order to do this, please.
I'd been trying all week to find an excuse to use the phrase "coup d'état", and there it was! So I got back 2 responses, one from KineticHosts.com and one from Mark. Here's Kinetic's take on the deal:
I am sorry but I certainly understand. Your billing will remain the same of you do not register with the billing Mark has setup. This billing is not going to Ultima Hosts USA LLC. We will be regaining access to the servers very shortly and you will be afforded the time to relocate. If there is a chance that we can regain you as a customer I would like to offer that we will keep your billing and plan details the same and we are planning to go back to our roots with this company, again offering add-ons and customizable hosting plans that fit your needs. Our goal is customer satisfaction and we do not wish to charge you for services that you do not need. If I am able to assist you with anything further, just let me know.
That was very nice and customer service-y. I'm still not really sure what I am supposed to do. And here's Mark's response:
It is free for this month so please take the time to find an alternative host.
So it's pretty clear Mark doesn't want my business from this response. This is fine - I've been planning to move away from them for a while, but I didn't expect it to come so soon. My concern turns toward the extra moolah I just paid for my hosting... paying twice and then "getting a month free" adds up to paying the regular rate, for those of you keeping score. At this point I really don't know who has access to my billing information and I'd like to get this resolved without making a claim with Visa. I'm mad and didn't think about backing up my data before I fire off this little number to both Mark and KineticHosts.com:
I'll give my business to the first person who credits my paypal acct the difference in the billing for this month. Go.
To which I received a very prompt response from Mark:
Please take your business elsewhere. I am cancelling your account.
So that is the story of how I ended up with no host and no data from the previous version of my blog. Customer service is something that sets successful companies apart from those that fail or don't deliver on their earning potential. The way I see it, Ultimahosts.net (or whatever form Mark's company turns into) has an uphill battle in winning customers back. As for KineticHosts.com, it would be hard for me to trust a company related to this debacle, but I at least hear some concern for their customers, which is a good start.
Update 2/11/2009
I'd sent an email to Mark asking him for a brief reprive from my account lockout so I could grab my data and restore it here, rather than having to snarf it from archive.org or some other such method.  I hadn't heard back today, so I figured I would give it one last fruitless shot.
I just wanted to follow up and see if it would be possible to get a tiny window of time where I could get access to my data to back it up and take it out.  I'd only need an hour or so, tops.  Thanks again in advance.
I got back a very prompt response this time, which I like.  It's hard to find a hosting company that will respond with a concise understandable answer within seconds of you asking it.
HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAH
From one dick to another NO FUCKING WAY JOSE!!!!
So so so glad to be done with fuckers like yourself.
The difference between us dicks is that I am a rich one and you are just plain stupid.
Looks like he reads my blog.  Who knew?