Ayende @ Rahien

Hi!
My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by email or phone:

ayende@ayende.com

+972 52-548-6969

, @ Q j

Posts: 6,710 | Comments: 48,642

filter by tags archive

Misconceptions

time to read 1 min | 58 words

I was explaining to a couple of team members about our stack (NHibernate, Castle, Boo, Rhino) and how the different pieces are hooked together.

When I got to talk to Boo, I explained that it is just like Brail, which we are using for the views. One of the guys then asked if Boo stands for Brail, Object Oriented

Commercial support for Castle Windsor, Castle MonoRail, NHibernate, etc

time to read 1 min | 184 words

This post by Ben Scheirman is interesting. He points out that the MS.MVC stuff is targeted toward a different crowd than the one who is using MonoRail, it is targeted toward the corporate developers and the All-Microsoft Shops.

The question of support has been raised again, and it prompted this post. It seems that there isn't a lot of awareness that there are commercial support options for those tools.

  • Castle Stronghold is the obvious place for commercial support for Castle.
  • JBoss / RedHat are offering commercial support for NHibernate. JBoss no longer support NHibernate.
  • We!* (Hebrew site) is offering commercial support for NHibernate and Castle.
  • Mindscape is offering commercial support for Castle.

I am actually not very interested in getting support for those, so it is entirely possible (and likely) that I missed some. Most of the active members of the community are members of consultancies that are capable offering support, but those are the one that I am aware of.

* Full disclosure: I work there.

Multiple parents in Cascading Drop Downs in MonoRail

time to read 2 min | 222 words

Apparently I am suffering from the Bug Duplication Syndrom. Shortly after posting about cascading drop downs in MonoRail, I realized that I have actually duplicated a bug that I have run into while using the cascading drop down extender in the ASP.Net Ajax toolkit. That is not a fixable bug, btw, and has to do with what happens when you have more than a single parent. You can see my post about this scenario here, but be aware that the solution in that post is vulnerable to race conditions, and I have finally declared that unpracticle to use.

At any rate, I have duplicate the inability to have multiply parents in my previous solution using MonoRail. And I decided that instead of fixing it in place, I'll show the steps neccesary to fix the problem. Basically, we want to update both the secondaries select and the tertiaries select, which means that our GetSecondaryProfressionsByPrimary.brailjs will now contains:

page.Replace( 'secondaries',
    Form.Select('secondaries',SecondaryProfessions,
        {@value: @Id, @text: @Name, @firstoption: res.Select})           
)
page.Replace( 'tertiaries',
    Form.Select('tertiaries',TertiaryProfessions,
        {@value: @Id, @text: @Name, @firstoption: res.Select})           
)
page.Call( @hookSecondariesChangeEvent );

And that the GetSecondaryProfressionsByPrimary action is now:

public void GetSecondaryProfressionsByPrimary(Guid id)
{
	PropertyBag["SecondaryProfessions"] =
		professionRepository.FindSecondariesByPrimaryIdOrAll(id);
	PropertyBag["TertiaryProfessions"] =
		professionRepository.FindTertiariesByPrimaryIdOrAll(id);
}

Oh, and that was it.

Cascading Drop Downs in MonoRail

time to read 3 min | 594 words

I just had this need, and I decided to explore what I could do without referring to what other people has already done. There are probably better ways, but this one has tickled my fancy.

Anyway, the idea here is to display three levels of hierarchy in a profression. Here is the HTML:

<table>
	<tr>
		<td>
			${res.PrimaryProfession}
		</td>
		<td>
			${Form.Select("primaries",PrimaryProfessions, 
{@value: @Id, @text: @Name, @firstoption: res.Select}) } </td> <td> ${res.SecondaryProfession} </td> <td> ${Form.Select("secondaries",SecondaryProfessions,
{@value: @Id, @text: @Name, @firstoption: res.Select}) } </td> <td> ${res.TertiaryProfession} </td> <td> ${Form.Select("tertiaries",TertiaryProfessions,
{@value: @Id, @text: @Name, @firstoption: res.Select}) } </td> </tr> </table>

This is not very fancy, and the CSS guys would be all over me for using a table, but let us leave that aside. Basically, we render three select elements. Now, let us see the server side, shall we?

public void Index()
{
	PropertyBag["PrimaryProfessions"] =
		professionRepository.FindAllPrimaries();

	PropertyBag["SecondaryProfessions"] =
		professionRepository.FindAllSecondaries();

	PropertyBag["TertiaryProfessions"] =
		professionRepository.FindAllTertiaries();
}

The ProfressionRepository uses Repository<T> internally, I want to avoid using Repository<T> directly in my controllers. Now, we need to actually respond to change events on the client side:

$j(document).ready(function()
{
	$j('#primaries').change(function()
	{
		$j.ajax({ 
			url:'GetSecondaryProfressionsByPrimary.ashx',
			data: { id: $j('#primaries').val() },
			dataType: 'script'
		});
	});
	hookSecondariesChangeEvent();
});

function hookSecondariesChangeEvent()
{
	$j('#secondaries').change(function()
	{
		$j.ajax({ 
			url:'GetTertiaryProfressionsBySecondary.ashx',
			data: { id: $j('#secondaries').val() },
			dataType: 'script'
		});
	});
}

This is done using jQuery, to hook the events and issue Ajax requests to the server when they are done. Note that I am registering the seconderies change event in a separate function, it will be soon clear why.

Now, how does the server handles this?

public void GetSecondaryProfressionsByPrimary(Guid id)
{
	PropertyBag["SecondaryProfessions"] =
		professionRepository.FindSecondariesByPrimaryIdOrAll(id);
}

public void GetTertiaryProfressionsBySecondary(Guid id)
{
	PropertyBag["TertiaryProfessions"] =
		professionRepository.FindTertiariesBySecondaryIdOrAll(id);
}

So we just pass the parameters to the repository, which does all the work for us, in this case, getting the children if the id is valid, or all if it isn't. Now let us move to the relevant views, shall we? We are using BrailJS here, so here is GetSecondaryProfressionsByPrimary.brailjs:

page.Replace( 'secondaries', 
	Form.Select('secondaries',SecondaryProfessions, 
		{@value: @Id, @text: @Name, @firstoption: res.Select})			
)
page.Call( @hookSecondariesChangeEvent );

As you can see, I ask the page to replace the element secondaries with the newly rendered select element. I then acll the hookSecondariesChangeEvent function, since I actually replace the entire element, and not just its content. I am doing this because I don't feel like extracting the part that renders just the options from the Form.Select() method, but I will probably will the next time I need it.

The GetTertiaryProfressionsBySecondary.brailjs is actually simpler:

page.Replace( 'tertiaries', 
	Form.Select('tertiaries',TertiaryProfessions, 
		{@value: @Id, @text: @Name, @firstoption: res.Select})			
)

Again, there are probably betters way, but this is the one I just came up with.

Handling javascript localization in Mono Rail

time to read 2 min | 282 words

I run into the issue of having to alert the user of some error, and it brought home the fact that English & Hebrew are not easy to mix. In fact, code such as this is consider a very bad sign, usually code that you don't really want to touch, see or believe in:

image

So, we need some sort of a way to externalize those strings, even if the only language that this application is going to use is Hebrew, simply because of the pain of mixing the two together.

After thinking about it for a while, I decided to create this view (JavascriptResources/index.brail):

<%
for de in controller.Resources:
	resourceName = de.Key
%>
	var ${resourceName} = {
	<% for item in GetParameter(resourceName): %>
		${item.Key}: '${item.Value.Replace("'","\\'") }',
	<% end %>
		Empty: ''
	};
<%
end
%>

And here is the definition of the controller:

[Resource("Processes", "MyApp.Resources.Javascript.Processes")]
[Resource("Errors", "MyApp.Resources.Javascript.Errors")]
[Resource("Messages", "MyApp.Resources.Javascript.Messages")]
public class JavascriptResourcesController : Controller
{
	public void Index()
	{
		
	}
}

But what the hell does this do, anyway? Not much, actually, but it will iterate over all the registered resources for the controller, and output something that looks like this for each of those resources:

var Processes = {
 	EmploymentType: 'Employment Type',
	Details: 'Details',
	Dates: 'The dates',
	Empty: ''
};

The nice thing is that I can now write: alert(Errors.RecursiveError);*. As a side affect (as I said, the application is just in Hebrew so I don't care about that much), I also get the usual benefits of localization.

* You have to read Hebrew to get the joke, I am afraid.

Redefining If

time to read 1 min | 80 words

I had time today to sit on several Brail bugs. I keep getting more and more and more amazed by the power that Boo is giving me.

In order to fix some of those bugs, I had to literally change the meaning of the if statement. (I defined my own nullable propagator, which I had to implement deeply into the language).

Damn, I love this language.

Oh, and FYI, if 2+2 == 4 will not do the expected thing anymore :-) 

Refactoring MonoRail Views

time to read 4 min | 763 words

imageAs I mentioned, I build a very quick & dirty solution to display a collection of scheduled task descriptions. The end result looked like this:

image

This works, and it should start producing value as of next week, but I didn't really like the way I built it.

Here is the original view code:

<table cellspacing="0" cellpadding="0">
	<thead>
		<tr>
			<th>
				Name:</th>
			<th>
				Occurances</th>
			<th>
				&nbsp;</th>
		</tr>
	</thead>
	<tbody>
		<% for task in tasks: %>
		<tr>
			<td>
			${Text.PascalCaseToWord(task.Name)}
			</td>
			<td>
			Every ${task.OccuranceEvery}
			</td>
			<td>
			${Html.LinkTo("Execute", "ScheduledTasks", "Execute", task.FullName)}
			</td>
		</tr>
		<% end %>
	</tbody>
</table>

This work, it is simple and easy to understand, but it still bothered me. So I replaced it with this:

<% component SmartGrid, {@source: tasks}  %>

Well, that was much shorter, but the result was this...

image

I am cropping things, because it is a fairly long picture, but it should be clear that this is not a really nice UI to use.

This was my second attempt;

<% component SmartGrid, {@source: tasks, @columns: [@Name, @OccuranceEvery] }  %>

And it produced this:

image

Better, but not really that much, let us try to have nicer names there, shall we?

<% 
component SmartGrid, {@source: tasks, @columns: [@Name, @OccuranceEvery] }:  
	section Name:
	%>
	<td>${Text.PascalCaseToWord(value)}</td>
	<%
	end
end
%>

And this produced:

image

That is much better on the name side, but we still have the "Occurance Every" column to fix...

<% 
component SmartGrid, {@source: tasks, @columns: [@Name, @OccuranceEvery] }:  
	section OccuranceEveryHeader:
	%>
	<th>Occurances</th>
	<%
	end
	section Name:
	%>
	<td>${Text.PascalCaseToWord(value)}</td>
	<%
	end
	section OccuranceEvery:
	%>
	<td>Every ${value}</td>
	<%
	end
end
%>

With the result being:

image

One last thing that we have left is the additional column at the end, we can manage it like this:

<% 
component SmartGrid, {@source: tasks, @columns: [@Name, @OccuranceEvery] }:  
	section OccuranceEveryHeader:
	%>
	<th>Occurances</th>
	<%
	end
	section MoreHeader:
	%>
	<th></th>
	<%
	end
	section Name:
	%>
	<td>${Text.PascalCaseToWord(value)}</td>
	<%
	end
	section OccuranceEvery:
	%>
	<td>Every ${value}</td>
	<%
	end
	section More:
	%>
	<td>${Html.LinkTo("Execute", "ScheduledTasks", "Execute", item.FullName)}</td>
	<%
	end
end
%>

So here is the final result:

image

Now that I did that, I am looking at both pieces of code and wondering:

  • What is the fuss about, anyway?
  • Which of those versions is more readable?

Granted, this is a fairly specialized case, but in terms of LoC, the second approach is actually longer, and the "major" benefit here is that I get less HTML in the view, but that is not a really major consideration.

The SmartGrid would produce a pager if needed, but that about it with regards to the differences in their abilities.

BrailNull propagation

time to read 1 min | 200 words

Here is a small, but interesting tidbit. Yesterday I have finally sat down and documented a lot of the changes that I made in Brail recently, I was surprised to see how much I had to document:

  • Auto Imports
  • Strongly typed variables
  • Sections
  • The "?variableName" syntax
  • Symbols
  • Null Propagation

The last part is what I want talk about now. Brail is a .Net language, which means that something like this:

output user.Parent.Name

will raise NullReferenceException if the user's parent is null. That can be somewhat of a pain in many scenarios. Brail now has a better syntax for this:

output ?user.Parent.Name

 will ignore any null values that it encounter in the way. It is will either output the parent's name or nothing at all.

The small print:

This will work only for variables that you get from the controller via the PropertyBag or Flash. You can't use it on variables that you define in the view. However, that is rare enough that I don't think that it is going to be a problem.

Note that I didn't document the DSL support in Brail yet, that is going to wait until it is stabilized a bit.

BrailDSL Support Information

time to read 1 min | 114 words

Harris has more details about the internal implementation of Brail's DSL Support

Following the same line of thoughts, Alex has a similar implementation using C# 3.0. Personally, I think that Alex's implementation is cool, but it looks really similar to LISP, and that sort of scares me. I am currently reading about ANTLR, so it actually makes sense, in a weird way, except that I keep looking for the lower level implementation.

And as long as I am busy in link aggregation, Tom Opgenorth has posted a guide to Binsor, including a Getting Started example!

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Graphs in RavenDB (4):
    21 Sep 2018 - Graph modeling vs. document modeling
  2. Reviewing FASTER (9):
    06 Sep 2018 - Summary
  3. RavenDB 4.1 features (12):
    22 Aug 2018 - MongoDB & CosmosDB Migration Wizards
  4. Reading the NSA’s codebase (7):
    13 Aug 2018 - LemonGraph review–Part VII–Summary
  5. Codex KV (2):
    06 Jun 2018 - Properly generating the file
View all series

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats