CONTRIB: Rest support for MonoRail

2 views
Skip to first unread message

Chris Ortman

unread,
Sep 18, 2007, 4:30:13 PM9/18/07
to castle-pro...@googlegroups.com
I have the need to build a RESTful interface to one of our applications. I set about using the new REST support in WCF (.Net?) 3.5 but quickly ran into some limitations (doesn't support form encoded data, multiple response types that include html will get ugly etc) so I've decided to build this around monorail instead. So far I've only needed very few changes to the existing MonoRail codebase (virutalized 2 properties and extended 2 interfaces) to make this happen. I'm releasing what I have so far in the hopes this will spark some interest and generate some feedback.

Right now basic action routing and content negotiation are working. I've tried to follow rails conventions in the hopes of keeping things simple. Right now it requires .NET 3.5 but it could be made to work on 2.0 if needed (the syntax will be uglier though)

A sample controller looks like this:

 [ControllerDetails(Area="V1")]
    public class CustomersController : RestfulController
    {
        public void Index()
        {
            var customers = Customer.FindAll();
            PropertyBag["customers"] = customers;

            RespondTo(format =>
            {
                format.Xml(xml => xml.Serialize(customers));
                format.Html(html => html.DefaultResponse());
            });

           
        }

        public void Show(int ID)
        {
            Customer c = Customer.FindById(ID);

            RespondTo(format =>
            {
                format.Xml(response => response.Serialize(c));
                format.Html(response => response.DefaultResponse ());
            });
                      
        }

        public void Create([XmlBind] Customer createMe)
        {
            Customer.AddNew(createMe);

            RespondTo(format =>
                    format.Xml(response => response.Empty(201, headers => headers["Location"] = UrlFor(createMe.ID.ToString()))));

        }

        public void New()
        {
            RespondTo(format => format.Xml(response => response.Serialize(new Customer())));
        }

        public void Update(int id, [XmlBind] Customer customer)
        {
            customer.ID = id;
            Customer.UpdateCustomer (customer);
            RespondTo(format =>
                format.Xml(response => response.Empty(200)));
        }

        public void Destroy(int ID)
        {
            Customer.Delete(ID);

            RespondTo(format =>
                format.Xml(response => response.Empty(200)));
        }
    }

Action routing is as follows:
GET /controller => index
POST /controller => create
GET /controller/new => new
GET /controller/id => show
PUT /controller/id => update
DELETE /controller/id => destroy

Format can be specified on the querystring
/controller/1.rails?format=xml
or as an accept header
curl -i -H Accept:application/xml /controller/1.rails

If you want to do some url rewriting with an ISAPI filter it gives you an easy way to support urls like
/controller/1.xml
/controller/1.html

In order for views to work, they need to follow a convention of
Action_format.brail
Index_html.brail
Index_xml.brail

Included in my zip file is:
Castle.MonoRail.Rest -- extensions to monorail
Custom Castle Build -- changes needed to MonoRail to make this work
Sample website
Sample Ruby Client
Tests

Eventually I'd like to get this into the Contrib repository, but not quite ready for that yet.
I'd appreciate any feedback / improvements you may have.
Thanks

mrrestsupport.zip

Hamilton Verissimo

unread,
Sep 18, 2007, 4:47:11 PM9/18/07
to castle-pro...@googlegroups.com
Awesome!!!!
Pretty cool syntax too!

On 9/18/07, Chris Ortman <chris...@gmail.com> wrote:
> I'd appreciate any feedback / improvements you may have.


--
Cheers,
hamilton verissimo
ham...@castlestronghold.com
http://www.castlestronghold.com/

Colin Ramsay

unread,
Sep 18, 2007, 4:48:54 PM9/18/07
to castle-pro...@googlegroups.com

RespondTo looks interesting - isn't this taken from RoR? Something like that could be helpful when creating an ajax application - so some things serve up JSON and HTML...

Very cool
Love


On 9/18/07, Chris Ortman <chris...@gmail.com> wrote:

Colin Ramsay

unread,
Sep 18, 2007, 4:50:23 PM9/18/07
to castle-pro...@googlegroups.com

WTF. I have no idea why gmail just randomly decided to append "love" at the end of my last email but I'd just like to say that... well, I don't think of you in that way Chris. Sorry.

:>

Fábio Batista

unread,
Sep 18, 2007, 4:51:40 PM9/18/07
to castle-pro...@googlegroups.com
Ohhh, how sexy are those expressions :D

=> ..., I love you
delegate(MyType x) { ... }, I hate you

On 9/18/07, Chris Ortman <chris...@gmail.com> wrote:


--
Fábio David Batista
fabio.dav...@gmail.com
http://nerd-o-matic.blogspot.com

Hamilton Verissimo

unread,
Sep 18, 2007, 4:53:49 PM9/18/07
to castle-pro...@googlegroups.com
LOL !!
I thought you intended to write "loved it" but you were in a hurry.

Colin Ramsay

unread,
Sep 18, 2007, 5:12:15 PM9/18/07
to castle-pro...@googlegroups.com

My browser knows that at heart, I'm a lover not a coder. ;)

Anyway, Chris: Love the syntax and the idea!

> > >                 format.Html (html => html.DefaultResponse());

chriso

unread,
Sep 18, 2007, 5:33:37 PM9/18/07
to Castle Project Development List
Yes, this is heavily influenced by ROR. I tried to follow their
conventions as close as possible as my eventual hope is a .NET service
with the client written using Ruby+ActiveResource

On Sep 18, 3:48 pm, "Colin Ramsay" <colinram...@gmail.com> wrote:
> RespondTo looks interesting - isn't this taken from RoR? Something like that
> could be helpful when creating an ajax application - so some things serve up
> JSON and HTML...
>
> Very cool
> Love
>

Benjamin Lovell

unread,
Sep 18, 2007, 5:36:16 PM9/18/07
to castle-pro...@googlegroups.com
Wow love the expressiveness. This feature is a god-send in RoR. I for one
would *love* to see this in MR asap!

Kevin Williams

unread,
Sep 18, 2007, 6:40:19 PM9/18/07
to castle-pro...@googlegroups.com
Wow, that looks a lot like my idea from last year: http://www.almostserio.us/articles/2006/06/28/accept-header-responder-in-monorail-spike
- I can't wait to get home and try this.

Great timing on your part - I actually need this next week. :) I'll
try to help if I can.

Are we too close to RC3 to put this in trunk?

--
Cheers,

Kevin Williams

http://kevwil.com
http://www.almostserio.us
http://kevwil.haiku.com

On Sep 18, 2007, at 2:30 PM, "Chris Ortman" <chris...@gmail.com>
wrote:

> <mrrestsupport.zip>

Hamilton Verissimo

unread,
Sep 18, 2007, 8:58:32 PM9/18/07
to castle-pro...@googlegroups.com
On 9/18/07, Kevin Williams <ke...@bantamtech.com> wrote:
> Are we too close to RC3 to put this in trunk?

Yep

sradack

unread,
Sep 18, 2007, 9:41:39 PM9/18/07
to Castle Project Development List
I have no immediate need for this but it makes me feel warm and fuzzy
that it's available. I'd really like to see this make it into Castle.

> mrrestsupport.zip
> 5480KDownload

goodwill

unread,
Sep 18, 2007, 10:09:45 PM9/18/07
to Castle Project Development List
How is that => syntax achieved? Its C# 3.5 feature or can be used on
C# 2.0 too?

> mrrestsupport.zip
> 5480KDownload

Hamilton Verissimo

unread,
Sep 18, 2007, 10:16:35 PM9/18/07
to castle-pro...@googlegroups.com

chriso

unread,
Sep 18, 2007, 11:48:44 PM9/18/07
to Castle Project Development List
The .NET 3.5 requirement also makes RC3 not very realistic. We can
probably get the changes needed to MR for this into the trunk though,
they are very small.

On Sep 18, 7:58 pm, "Hamilton Verissimo"


<hamm...@castlestronghold.com> wrote:
> On 9/18/07, Kevin Williams <ke...@bantamtech.com> wrote:
>
> > Are we too close to RC3 to put this in trunk?
>
> Yep
>
> --
> Cheers,
> hamilton verissimo

> hamm...@castlestronghold.comhttp://www.castlestronghold.com/

Message has been deleted

goodwill

unread,
Sep 19, 2007, 10:02:59 AM9/19/07
to Castle Project Development List
Hammett you wanna come HK for a short training trip? :P You are so
nice.

On Sep 19, 10:16 am, "Hamilton Verissimo"
<hamm...@castlestronghold.com> wrote:
> Check thishttp://www.developer.com/net/csharp/article.php/3598381

> hamm...@castlestronghold.comhttp://www.castlestronghold.com/

chriso

unread,
Sep 19, 2007, 10:33:41 AM9/19/07
to Castle Project Development List
Yes very similar.
I had originally started with this

RespondTo(
xml=> xml.Empty(201,responseHeaders)
);

But changed it because the ORCAS intellisense made it a real pain to
get xml typed.

On Sep 18, 5:40 pm, Kevin Williams <ke...@bantamtech.com> wrote:
> Wow, that looks a lot like my idea from last year:http://www.almostserio.us/articles/2006/06/28/accept-header-responder...


> - I can't wait to get home and try this.
>
> Great timing on your part - I actually need this next week. :) I'll
> try to help if I can.
>
> Are we too close to RC3 to put this in trunk?
>
> --
> Cheers,
>
> Kevin Williams
>

> http://kevwil.comhttp://www.almostserio.ushttp://kevwil.haiku.com
>
> On Sep 18, 2007, at 2:30 PM, "Chris Ortman" <chrisort...@gmail.com>

Kevin Williams

unread,
Sep 19, 2007, 10:54:05 AM9/19/07
to castle-pro...@googlegroups.com
How do you feel about backporting to 2.0? If I am going to be able to
use this next week, I can't use 3.5 yet. I can help if you like.

Colin Ramsay

unread,
Sep 19, 2007, 11:04:47 AM9/19/07
to castle-pro...@googlegroups.com
What would it look like in 2.0? A fair bit less elegant I should think.

>>>                 format.Xml (response => response.Empty(200)));

chriso

unread,
Sep 19, 2007, 11:14:22 AM9/19/07
to Castle Project Development List
It wouldn't be terrible hard to make it work on 2.0, the respond to
syntax would look like
RespondTo(delegate(ResponseFormat format) {
format.Xml(delegate(ResponseHandler response)
{
response.Serialize(customer);
});
format.Html(delegate(ResponseHandler response)
{
response.DefaultResponse();
});

});

Although I'm not sure how long I'd want to maintain 2.0
compatibility....having to have #ifdef DotNet35 all over the place
doesn't excite me a lot.

If you want 2.0 support for this though, I will get the code into the
contrib repository.

> > >>> format.Xml(response => response.Empty(200)));

chriso

unread,
Sep 19, 2007, 12:07:11 PM9/19/07
to Castle Project Development List
The code is now in SVN
https://svn.castleproject.org/svn/castlecontrib/Castle.MonoRail.Rest

For now I've created a separate branch for .NET 2.0 support, feel free
to start on any conversion work you need to do, I don't have time to
get to it today, but as I make changes to the code I'll try to make
them 2.0 friendly.

Kevin Williams

unread,
Sep 19, 2007, 5:38:38 PM9/19/07
to castle-pro...@googlegroups.com
I started the conversion work. I didn't go with #ifdef defines but
rather just changing the code to make it work in vs2005. I hope that was
an acceptable assumption.

chriso

unread,
Sep 19, 2007, 6:01:39 PM9/19/07
to Castle Project Development List
Yes that sounds good.

Hamilton Verissimo

unread,
Sep 19, 2007, 11:03:41 PM9/19/07
to castle-pro...@googlegroups.com
Did you attach the patch to MR on your zip? I'd like to review it and
couldnt find it.

Roelof Blom

unread,
Sep 20, 2007, 4:58:59 AM9/20/07
to castle-pro...@googlegroups.com

k-dub

unread,
Sep 20, 2007, 12:22:14 PM9/20/07
to Castle Project Development List
OK, I'm choking on the XDocument object. I'm not sure what that does,
so I don't know how to port it back to 2.0. Any ideas?

James Curran

unread,
Sep 20, 2007, 12:40:21 PM9/20/07
to castle-pro...@googlegroups.com
XDocument is an XLINQ class (v3.5 only).  It's roughly equivalent to an XmlDocument.
Reply all
Reply to author
Forward
0 new messages