Archive for the ‘MonoRail’ Category

MonoRail with RoutingEx on IIS7

May 9th, 2008

It takes some time to figure out how IIS7 performs its handler/module matching, and to realize that the ordered list not always reflect the real order – once you set up an order click on View Unordered List and back to View Ordered List to see if it really changed to reflect what you want.

And one complain: it would be a lot easier if IIS7 and their handlers/modules could work together to identify if the handler/module was able to deal with the request or not, this is especially true for the DefaultDocumentModule. More on that later

This is how the handlers should look (in the ordered view)

iispanel.png

Steps

First of all, I’m using Vista Ultimate, so from what I’ve read, the integrated mode doesn’t work yet, so fall back to Classic mode.

After creating the web site or virtual folder, go to Handler Mapping and

  • Delete the handler for static files Empirical reason, I can be wrong: I wasn’t able to re-order this one as it seems to inherit from a parent configuration, deleting it saves a lot of hair
  • Add a new Module Mapping, request path: *.*, Module StaticFileModule, Restrictions: File and GET verb. I call this one StaticF
  • Add a new Script Map, request path *, Executable aspnet_isapi.dll (the whole path), name: MR. On the restrictions, uncheck the Invoke handler only if request is mapped to (maybe you could mark Folder, not sure if IIS is going to check if the folder actually exists, that would be a problem)

Now order the handlers. In my case I have a default.aspx, so I make the .aspx handler the first one.

Then you, as you dont want MonoRail handling static content, you make StaticF the next one

Finally MR handler should handle the rest of the requests.

I struggled for some time to get the DefaultDocumentModule working. The problem is that it conflicts with MR handler in its restrictions. You basically want that it handle a folder request, and redirect to one of the default document (if found). What actually happens is that it will greedily take all requests. Leaving no room for MR handler. The fix for that is changing MonoRail routing to be able to handle empty folders requests and matching a PatternRoute, something that today is not possible.

Let me know if that works for you.

Incremental development with Monorail

April 23rd, 2008

Just bumped into this. Great work, Ben.

Just personal preference-wise:

- I’d prefer not to use the BaseControllerTest class
- Instead of writing the form tags, I’d use the form helper: $Form.FormTag(“%{action=’save’}”) and $Form.EndFormTag(). Then you take advantage of automatic form field validation if you want.
- For actions that change things, I’d use [AccessibleThrough(Verb.Post)]
- I’d configure Windsor through code
- The mapper/wrapper sounds like iBatis. Why not using Repositories with Castle ActiveRecord?
- Instead of DTO you could use the domain class as a prototype. I think that simplifies the code.

The cool thing is that Ben knows TDD. He creates a dummy implementation, get the test passing, corner it, triangulate it, and then is forced to get rid of the dummy implementation. That’s the essence of “test-driven”.

The series is also a good way to compare MonoRail with MS MVC. The goals are the same, they just provide different ways to get the same result, up to you to use the one you like the most.

Bashing Castle and its committers

April 10th, 2008

Today I had lunch with two friends/former co-worker, on a project I’ve blogged about earlier. Nice to hear some things I’ve implemented – and which I completely forgot about – are still being used.

Anyways, this project obviously used Castle, from a local build on my machine back in 2005. A huge effort was taken to port it to RC2 – yes, Release Candidate 2 -then it was decided to skip RC3 altogether and go with whatever comes after, which I hope would be 1.0.

I was told that porting was a nightmare. Dealing with compiler errors because some interface changed or some method was renamed is one thing, I dare to say somewhat easy to deal with to some extend. The biggest problem lied elsewhere. Helpers were changed, specifically methods being added, removed and renamed, and those completely broke views.

I argued that these changes are considered important changes, and are registered on the changes.txt that every project under the Castle umbrella has. This document is used to later compile a list of new features, breaking changes and bug fixes.

My friend replied that they looked into that very document, and no mention to these specific changes were there. These at very minimum can be used to drive an smart Find/Replace on the views and get them ported.

To err is human, certainly, build those slips have high costs. This project started being used in Brazil, then South America and now it’s going world wide. It’s ridiculously big. My complain to him is that this went so long unstated. People should complain about these and similar problems.

Do it nicely, though, or I will ask you to contact our customer service to get your money refunded.

And yes, I’m to blame as well as all commiters. We are directly tight to the reputation Castle has, be it bad or good.

MonoRail on SharpDevelop

April 5th, 2008

Cool stuff! A bit out-of-date, but still neat.

Painful Windows Mobile experience

March 18th, 2008

One piece of the app we’re working on needs to be accessed from hand helds. No problem, right? It’s just a different view rendered to the mobile devices. JS, ajax should work as it is. Right? RIGHT?

Wrong. While I’ve read that IE has some Ajax support, I couldn’t make it work. This discussion set my expectation low. So, I downloaded Opera Mobile and wow, what a difference. Even the form validation using the Validation plug in worked. Still no Ajax. Just a few tweaks, right?

Wrong again. The jquery code that creates the XMLHttpRequest fails miserably on Opera. What is worst is that you have no clue of what is failing. No tooling, nothing even remotely similar to Firebug. So add try catches everywhere and prepare your patience.

To cut a long story short, I changed the code on jQuery source code – argh! – but got the XMLHttpRequest working. Just the first request went through, though. That one was easy: caching.

If you’re using MonoRail, all you have to do is:

[Cache(HttpCacheability.NoCache)]
public void YourAction()
{
}

and you’re done.

Requests are going through. No parameters, though. The request.send(“value=something”) doesn’t seem to work. Ok, to fix it make the parameters go through the URL. Ugly!!! But works.

Next problem, and the most involved one. My action returns JSON data:

firebug.png

And that’s what I got on the device:

badmobile.png

Beautiful, isn’t it? My first guess: encoding problem.

I reviewed MonoRail and Newtonsoft.Json’s code almost a hundred times. No encoding relevant code. The response was set to utf-8. Decided to inspect the response’s content type. By default MonoRail’s JSONReturnBinder returns application/json, text/javascript which is right. Commented that line. Result:

expected.png

Opera mobile seems to not associate that content type with anything, so it falls back to binary (!!!). Had to add the following hack to MonoRail’s JSONReturnBinder:

if (userAgent != null && userAgent.IndexOf("Windows CE") == -1)
{
    response.ContentType = "application/json, text/javascript";
}

Sometimes I love being a web developer… :-(

Testing MonoRail Controllers

March 11th, 2008

I’ve seen more misinformation going on a mailing list I lurk. So to clarify I’m going to briefly describe three ways to test MonoRail controllers. Is there only three ways? Probably not, you can create other ways, depends upon your requirements and your preferences.

Using the TestSupport project

The Castle.MonoRail.TestSupport is only there to offer some convenient base classes to test controllers, wizard steps, view components and whatnot. You can read more about it on

http://using.castleproject.org/display/MR/TDDingControllers
http://using.castleproject.org/display/MR/TDDing+WizardSteps
http://using.castleproject.org/display/MR/Testing+file+upload+actions
http://using.castleproject.org/display/MR/Unit+Testing+Filters

I don’t really like the approach, but it is a good way to get started.

Using MockEngineContext and invoking the action directly

This one is just about setting some state on your controller and then invoke your action directly. If the action uses the property bag, session, flash, querystring, form, redirects – everything – it should just work. You can then assert things were added to the property bag, session, the request was redirect, the correct view was selected. It’s the most common way to test your controller. An example:

[Test]
public void Index_DoesXYZ()
{
    MyController controller = new MyController(...my mocks...);

    // set expectations if you're using a mock framework

    controller.Contextualize(new MockEngineContext(), new ControllerContext());

    // playback

    controller.MyAction();

    // asserts here
}

The MockEngineContext has a handful of constructor overloads, so you can customize the request, response, url and services. The ControllerContext holds the state for a controller (the view selected, property bag and so on).

Using MockEngineContext and invoking Process

Now, some people prefer to test the whole thing: filters execution, binders, parameter conversions, return binders. This is also possible, but a bit more involved:

[Test]
public void Index_DoesXYZ()
{
    MyController controller = new MyController(...my mocks...);

    // set expectations if you're using a mock framework

    MockEngineContext ctx = new MockEngineContext();
    // Time to fill things on the session, query string, forms, etc:
    ctx.MockRequest.Params["name"] = "john doe";

    IControllerContext controllerCtx = 
        ctx.Services.ControllerContextFactory.Create("", "mycontroller", "index", 
            ctx.Services.ControllerDescriptorProvider.BuildDescriptor(controller));

    // playback

    controller.Process(ctx, controllerCtx);

    // asserts here
}

Now, what heck just happened? Nothing much, we created a MockEngineContext that holds all needed to process a request. Then we created a controller context – the state – but this time we asked its factory to construct one. We also built a descriptor for the controller. That is necessary because on MonoRail we don’t read custom attributes during the request process, we do all reflection related stuff only once, and cache it. This meta information is called controller descriptor.

Then we invoke Process, which from that point on is exactly what is going to happen on a normal process.

What about the view engine? The MockEngineContext loads a fake one that only saves the fact that something tried to be rendered. You can plug yours, or a real one without hassle.

Hope that shed some light on this topic.

Reversibility

March 11th, 2008

I wonder if it would be possible to agree on a minimal set of contracts that would allow people to shift from MonoRail to ASP.Net MVC and vice-versa. That would be doable if we have:

- A separated and independent entity that would manage the minimal contracts
- A team on MS side (or even the MVC Contrib) creating adaptors for get the contracts working with ASP.net MVC
- Same thing from Castle side of the fence.

But why? If you read “Implementing Lean” you have noticed the “defer big architectural decisions to the last minute”. In this case, MVC would be the decision, and using MonoRail or MS MVC is more up to political/management decision than technical ones. But I’m not here to judge those decisions, just to make life of the developers easier. If they have code their controllers, filters, routing rules to not be bind to neither MS nor MonoRail implementation, the switching would be ridiculously easy.

Another thing to consider is the “J2EE standard syndrome” where, in theory, everyone is standard compliant, in practice they aren’t. The sweet feature are vendor dependent, and you get locked anyway, so I’m not sure the effort is worthwhile.

Thoughts?

Json.Net 2.0 looks awesome!

March 4th, 2008

Check this post. It definitely voids the parallel work that I kicked off, and Ayende implemented, which is a good thing by the way. The less the code we have to maintain, document, release, the better – read Implementing Lean Software Development for more on that.

Now, if only I could get lambda expressions, or some other source of type safe expression on attributes….

MonoRail – Return Binders

February 20th, 2008

I got tired of seeing actions like:

public void GetStates(string countryCode)
{
     ... get the states ...

    string js = Context.Services.JSONSerializer.Serialize(states);

    Response.ContentType = "application/json";
    RenderText(js);
}

They just don’t make sense. So I spent 20 minutes adding support for return binders. Now my code looks like:

[return: JSONReturnBinder]
public State[] GetStates(string countryCode)
{
     return stateRepository.FetchAllByCountry(new Country(countryCode));
}

I know, I know, the attributes associated with return looks weird, but take your complain to MS/C# team. You have to play with the cards you’re dealt.

A return binder, much like a parameter binder, is a class/attribute that implements the IReturnBinder interface, which has a single method: Bind. There you can go wild and do whatever you want with the return value. You could add to the property bag, example, or use it to figure out to where the user should be redirected (struts like), or like me, you just want to serialize some data in JSON format.

I’ve also added the ability to serialize only the properties I want:

[return: JSONReturnBinder(Properties="Id,Name")]
public State[] GetStates(string countryCode)
{
     return stateRepository.FetchAllByCountry(new Country(countryCode));
}

That saves bandwidth, not to mention that I dont expose the whole objects through the wire.

The code, if you’re wondering, is on my branch playground. I’m experimenting with more things, which I will blog soon.

A realistic impression about MonoRail

February 15th, 2008

I keep following what people say about Castle through technorati. Most hail, some bashings – for the wrong reasons – and from time to time I read something that is really cool. Last one was 0 to 60 in … 3 months.

MonoRail is hard, don’t let anyone tell you any different. You have to download a bunch of stuff, set it up on your machine, learn some weird new syntax for writing your web pages, you don’t get intellisense in your webpages, there’s no nice server controls, no drag and dropping to build the UI, the documentation doesn’t always show you how to get things done and much much more.

Very very true.

Update: I’m not being ironic. I agree with the paragraph I quoted, and I suggest go reading the whole post.