2008-02-21

Dump Evite

Cross-post from my personal blog.

This article from the January Wired got me started:

An email arrives announcing a fete, but it's short on deets. You're forced to click to an ad-choked Web page, then another to RSVP, and then back to the first to see the info again. That faint sound you hear? It's coins tumbling into the pockets of media conglomerate IAC/InterActiveCorp, which acquired the site in 2003.

It's been 2 days since I read the article and I've received 4 evites. It's time to put a stop to this.

The article recommends Socializer as an alternative, but it's way too heavy for my taste. The sign-up experience should be almost invisible.

What I want:

  • Painless sign-up
  • Time and location details in the email
  • +1 if it includes a link to a map
  • +1 if the map link is to Google Maps
  • +1 if a calendar file is attached for us Gmail/Outlook users.
  • Super-clean user experience.

image

Invitastic nails it. There are no crazy custom themes or anything and I'm fine with that. Kudos to the Jackson Fish Market folks.

image

Goovite also looks promising. It includes the ability to offer a number of possible meeting times and allow a discussion about when.

Progress rocks!

2008-02-05

Xaml Serialization with WCF

So I'm reading RESTful Web Services and I got inspired. Sounds like a great way to expose data on the web.

I've heard great things about WCF support for REST, with their new WebGet attribute and such.

So I fire up Visual C# Express and get hacking.

Amazing what one can do in 54 lines of code.

using System;
using System.ServiceModel;
using System.ServiceModel.Web;
 
namespace J832
{
class Program
{
static void Main(string[] args)
{
Time time = new Time();
 
using (WebServiceHost host = new WebServiceHost(time, new Uri("http://localhost:8080/")))
{
host.AddServiceEndpoint(typeof(ITime), new WebHttpBinding(), "time");
host.Open();
 
Console.WriteLine("enter to close...");
Console.ReadLine();
}
}
}
 
[ServiceContract]
public interface ITime
{
[OperationContract, WebGet]
DateTimeCount GetTime();
}
 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Time : ITime
{
public DateTimeCount GetTime()
{
return new DateTimeCount(DateTime.Now, m_count++);
}
 
private int m_count;
}
 
[Serializable]
public class DateTimeCount
{
public DateTimeCount(DateTime now, int count)
{
Now = now;
Count = count;
}
 
public DateTime Now { get; set; }
public int Count { get; set; }
}
}
 

And we open a browser to http://localhost:8080/time/GetTime:

<DateTimeCount xmlns="http://schemas.datacontract.org/2004/07/J832" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<_x003C_Count_x003E_k__BackingField>0</_x003C_Count_x003E_k__BackingField>
<_x003C_Now_x003E_k__BackingField>2008-02-04T23:28:21.987561-08:00</_x003C_Now_x003E_k__BackingField>
</DateTimeCount>

Isn't that *cough* *choke* pretty *gag*.

I suddenly had a flash of nostalgia...of longing...for Xaml.

Xaml: that wonderful language where document-object mapping is implicit, trivial, and human-understandable.

(I'd love to link to Our 7 Goals of Xaml introduction but the link is dead. Help, Rob?)

Thankfully, XamlWriter is publicly available and WCF is insanely, gratuitously, wonderfully extensible.

  • WCF services have endpoints.
  • Endpoints have contracts.
  • Contracts have operations.
  • Operations have behaviors.
  • Behaviors have formatters.
  • Formatters can have custom messages--for instance, XamlMessage.

Thanks to Maheshwar Jayaraman for the post (and sample) on his old blog that got me started.

The code is a bit longer, but it's mostly boiler plate:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Windows.Markup;
using System.Xml;
 
[assembly: XmlnsDefinition("http://schemas.j832.com/demo/2008", "J832")]
 
namespace J832
{
class Program
{
static void Main(string[] args)
{
Time time = new Time();
 
using (WebServiceHost host = new WebServiceHost(time, new Uri("http://localhost:8080/")))
{
ServiceEndpoint endPoint = host.AddServiceEndpoint(typeof(ITime), new WebHttpBinding(), "time");
foreach (OperationDescription operationDescription in endPoint.Contract.Operations)
{
operationDescription.Behaviors.Add(new MyOperationBehavior());
}
 
host.Open();
 
Console.WriteLine("enter to close...");
Console.ReadLine();
}
}
}
 
[ServiceContract]
public interface ITime
{
[OperationContract, WebGet]
DateTimeCount GetTime();
}
 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Time : ITime
{
public DateTimeCount GetTime()
{
return new DateTimeCount(DateTime.Now, m_count++);
}
 
private int m_count;
}
 
[Serializable]
public class DateTimeCount
{
public DateTimeCount(DateTime now, int count)
{
Now = now;
Count = count;
}
 
public DateTime Now { get; set; }
public int Count { get; set; }
}
 
public class MyOperationBehavior : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }
 
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
 
public void ApplyDispatchBehavior(
OperationDescription operationDescription,
DispatchOperation dispatchOperation)
{
dispatchOperation.Formatter = new MyMessageFormatter();
}
 
public void Validate(OperationDescription operationDescription) { }
}
 
public class MyMessageFormatter : IDispatchMessageFormatter
{
public void DeserializeRequest(Message message, object[] parameters) { }
 
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
return new XamlMessage(result);
}
}
 
public class XamlMessage : Message
{
public XamlMessage(object value){ Value = value; }
 
public override MessageHeaders Headers
{
get { return new MessageHeaders(MessageVersion.None); }
}
 
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
XamlWriter.Save(Value, writer);
}
 
public override MessageProperties Properties{ get{ return new MessageProperties(); } }
 
public override MessageVersion Version{ get{ return MessageVersion.None; }}
 
public object Value { get; private set; }
}
}

And (drumroll) the output from http://localhost:8080/time/GetTime:

<DateTimeCount Now="2008-02-04T23:53:18.884273-08:00" Count="14" xmlns="http://schemas.j832.com/demo/2008"/>

Isn't that pretty? The XmlnsDefinition assembly attribute is the icing that gives you the pretty xmlns.

Do other folks love Xaml? Do you wish it was available outside PresentationFramework.dll?

Let me know. I'm thinking of starting a campaign.

Hear that, Rob? :-)


kick it on DotNetKicks.com