Rhino Commons
On PSake
James Kovacks introduced psake ( a power shell based build system )over a year ago, and at the time, I gave it a glance and decided that it was interesting, but not worth further investigation. This weekend, as I was restructuring my Rhino Tools project, I realized that I need to touch the build system as well. The Rhino Tools build system has been through several projects, and was originally ported from Hibernate. It is NAnt based, complex, and can do just about everything that you want expect be easily understandable. It became clear to me very quickly...
The complexity of unity
This post is about the Rhino Tools project. It has been running for a long time now, over 5 years, and amassed quite a few projects in it. I really like the codebase in the projects in Rhino Tools, but secondary aspects has been creeping in that made managing the project harder. In particular, putting all the projects in a single repository made it easy, far too easy. Projects had an easy time taking dependencies that they shouldn’t, and the entire build process was… complex, to say the least. I have been somewhat unhappily tolerant of this so...
Common infrastructure? Don't make me laugh
I am currently in the process of retiring the IRepository<T> from Rhino.Commons. I am moving it to its own set of projects, and I am not going to give it much attention in the future. Note: Backward comparability is maintained, as long as you reference the new DLLs. But why am I doing that? If there is anything that I have been thought in the last couple of years is that there is a sharp and clear distinction between technological infrastructure (web frameworks, IoC containers, OR/M) and application infrastructure (layer super type, base services, conventions). The first can...
Rhino Queues
One of the things that often come up in the NServiceBus mailing list is the request for an xcopy, zero administration, queuing service. This is especially the case when you have smart clients or want to have queues over the Internet. I decided to try to build such a thing, because it didn't seem such a hard problem. I turned out to be wrong, but it was an interesting experiment. Actually, the problem isn't that it is hard to do this, the problem was that I wanted durable queuing, and that led me to a lot of technologies that...
The purpose of Rhino Commons
Nathan has posted about utility libraries and he includes Rhino Commons there as well. I don't see Rhino Commons as a utility library. At least not anymore. It certainly started its life as such, but it has grown since then. Rhino Commons represent my default architecture. This is my base when I am building applications. It has some utility classes, sure, but it contains a lot more foundation and infrastructure components than anything else.
Answer: How many tests?
Two days ago I asked how many tests this method need: ///<summary>
///Get the latest published webcast
///</summary>
public Webcast GetLatest();
Here is what I came up with:
[TestFixture]
public class WebcastRepositoryTest : DatabaseTestFixtureBase
{
private IWebcastRepository webcastRepository;
[TestFixtureSetUp]
public void TestFixtureSetup()
{
IntializeNHibernateAndIoC(PersistenceFramework.ActiveRecord,
"windsor.boo", MappingInfo.FromAssemblyContaining<Webcast>());
}
[SetUp]
public void Setup()
{
CurrentContext.CreateUnitOfWork();
webcastRepository = IoC.Resolve<IWebcastRepository>();
}
[TearDown]
public void Teardown()
{
CurrentContext.DisposeUnitOfWork();
}
[Test]
public void Can_save_webcast()
{
var webcast = new Webcast { Name = "test", PublishDate = null };
With.Transaction(() => webcastRepository.Save(webcast));
Assert.AreNotEqual(0, webcast.Id);
}
[Test]
public void Can_load_webcast()
{
var webcast = new Webcast { Name = "test", PublishDate = null };
With.Transaction(() => webcastRepository.Save(webcast));
UnitOfWork.CurrentSession.Evict(webcast);
var webcast2 = webcastRepository.Get(webcast.Id);
Assert.AreEqual(webcast.Id, webcast2.Id);
Assert.AreEqual("test", webcast2.Name);
Assert.IsNull(webcast2.PublishDate);
}
[Test]
public void When_asking_for_latest_webcast_will_not_consider_any_that_is_not_published()
{
var webcast = new Webcast { Name = "test", PublishDate = null };
With.Transaction(()...
Adaptive Domain Models with Rhino Commons
Udi Dahan has been talking about this for a while now. As usual, he makes sense, but I am working in different enough context that it takes time to assimilate it. At any rate, we have been talking about this for a few days, and I finally sat down and decided that I really need to look at it with code. The result of that experiment is that I like this approach, but am still not 100% sold. The first idea is that we need to decouple the service layer from our domain implementation. But why? The...
Dealing with hierarchical structures in databases
I have a very simple requirement, I need to create a hierarchy of users' groups. So you can do something like: Administrators DBA SQLite DBA If you are a member of SQLite DBA group, you are implicitly a member of the Administrators group. In the database, it is trivial to model this: Except that then we run into the problem of dealing with the hierarchy. We can't really ask questions that involve more than one level of the hierarchy easily. Some databases has support for hierarchical operators, but that is different from one database to...
Rhino Igloo – MVC Framework for Web Forms
How many times have the documentation of a product told you that you really should use another product? Well, this is one such case. Rhino Igloo is an attempt to make an application that was mandated to Web Forms more palatable to work with. As such, it is heavily influenced by MonoRail and its ideas. I speak as the creator of this framework, if at all possible, prefer (mandate!) the use of MonoRail, it will be far easier, all around. Model View Controller is a problematic subject in Web Forms, because of the importance placed on the view (ASPX...
Running on the trunk: Building Rhino Commons
Well, it looks like I have to share the big secret of how to keep Rhino Commons in sync with both NHibernate & Castle. The secret is never opening Visual Studio and doing it all from the command line. Here is the magic formula:D:\OSS>cd nhibernate
D:\OSS\nhibernate>svn up
D:\OSS\nhibernate>nant
D:\OSS\nhibernate>cd..
D:\OSS>cd Castle
D:\OSS\Castle>svn up
D:\OSS\Castle>nant
D:\OSS\Castle>copy ..\nhibernate\build\NHibernate-2.0.0.Alpha1-debug\bin\net-2.0\*.* build\net-2.0\debug /y
D:\OSS\Castle>nant
D:\OSS\Castle>copy ..\nhibernate\build\NHibernate-2.0.0.Alpha1-debug\bin\net-2.0\*.* ..\rhino-tools\SharedLibs\NHibernate /y
D:\OSS\Castle>copy build\net-2.0\debug\*.* ..\rhino-tools\SharedLibs\Castle\*.* /y
D:\OSS\Castle>cd..
D:\OSS>cd rhino-tools
D:\OSS\rhino-tools>msbuild BuildAll.build
Rhino ETL: Thinking about Joins & Merges
Well, I think that I have a solid foundation with the engine and syntax right now, I still have error conditions to verify, but that is something that I can handle as I go along. Now it is time to consider handling joins and merges. My initial thinking was something like: joinTransform UsersAndOrganizations:
on:
Left.Id.ToString().Equals(Right.UserId)
transform:
Row.Copy(Left)
Row.OrgId = Right["Organization Id"]
The problem is that while this gives me equality operation, I can't handle sets very well, I have to compare each row vs. each row, and I would like to do it better. It would also mean having to do everything in memory,...
Rhino ETL: First Code Drop
First, let me make it clear, it is not ready yet. What we have: 99% complete on the syntax Overall architecture should be stable The engine works - but I think of it as a spike, it is likely to change significantly. What remains to be done: Parallelising the work inside a pipeline Better error messages More logging More tests Transforms over sets of rows Here are a few works about how it works. The DSL is compromised of connection, source, destination and transform, which has one to one mapping with the...
Rhino.ETL: Full Package Syntax
Okay, here is the full package syntax that I have now, which is enough to express quite a bit, I am now getting started on working on the engine itself, I am going to try the message passing architecture for now, since it is much more flexible. connection(
"NorthwindConnection",
ConnectionType: SqlConnection,
ConnectionString: "Data Source=localhost;Initial Catalog=Northwind; Integrated Security=SSPI;"
)
source Northwind, Connection="NorthwindConnection":
Command: "SELECT * FROM Orders WHERE RequiredDate BETWEEN @LastUpdate AND @CurrentDate"
Parameters:
@LastUpdate = date.Today.AddDays(-1)
@CurrentTime = ExecuteScalar("NorthwindConnection", "SELECT MAX(RequiredDate) FROM Orders")
transform ToLowerCase:
for column in Parameters.Columns:
Row[column] = Row[column].ToLower() if Row[column] isa string
destination Northwind, Connection = "NorthwindConnection":
Command: """
INSERT INTO [Orders_Copy]
(
[CustomerID], [EmployeeID], [OrderDate], [RequiredDate], [ShippedDate],[ShipVia],
[Freight],[ShipName],[ShipAddress],[ShipCity],[ShipRegion],[ShipPostalCode],
[ShipCountry]
)
VALUES
(
@CustomerID,@EmployeeID,@OrderDate,@RequiredDate,@ShippedDate,@ShipVia,@Freight,
@ShipName,@ShipAddress,@ShipCity,@ShipRegion,@ShipPostalCode,@ShipCountry
)
"""
pipeline CopyOrders:
Sources.Northwind >> ToLowerCase(Columns: ['ShipCity','ShipRegion'])
ToLowerCase >>...
Rhino.ETL: Turning Transformations to FizzBuzz tests
Tobin Harris has asked some questions about how Rhino.ETL will handle transformations. As you can see, I consider this something as trivial as a FizzBuzz test, which is a Good Thing, since it really should be so simple. Tobin's questions really show the current pain points in ETL processes. Remove commas from numberstransform RemoveCommas:
for column in row.Columns:
if row[column] isa string:
row[column] = row[column].Replace(",","")
Trim and convert empty string to nulltransform TrimEmptyStringToNull:
for column in row.Columns:
val = row[column]
if val isa string:
row[column] = null if val.Trim().Length == 0
Reformat UK postcodes - No idea from what format, and to what format, but let...
Rhino.ETL: Providing Answers
It would be easier to me to answer a few of the questions that has cropped up regarding Rhino.ETL. Boo vs. Ruby: Why I choose to go with Boo rather than Ruby. Very simple reasoning, my familiarity with Boo. I can make Boo do a lot of stuff already, I would have to start from scratch on Ruby. I don't see any value in one over the other, frankly, is there a reason behind the preference? NAnt ETL Tasks: The main problem I have with such an endeavor is that it is back to XML again, if I want to...
Framework building: Rhino.ETL Status Report
I am currently working on making this syntax possible, and letting ideas buzz at the back of my head regarding the implementation of the ETL engine itself. This probably requires some explanation. My idea about this is to separate the framework into two distinct layers. The core engine, which I'll talk about in a second, and the DSL syntax. One of the basic design decisions was that the DSL would be declarative, and not imperative. How does this follow, when I have something like this working: source ComplexGenerator:
CommandGenerator:
if Environment.GetEnvironmentVariable("production"):
return "SELECT * FROM Production.Customers"
else:
return "SELECT * FROM Test.Customers"
This certainly looks like...
Test driving Rhino.ETL
Here is the first test: [Test]
public void EvaluatingScript_WithConnection_WillAddDataSourceToContext()
{
EtlConfigurationContext configurationContext = EtlContextBuilder.FromFile(@"Connections\connection_only.retl");
Assert.AreEqual(3, configurationContext.Connections.Count, "should have three connections");
}
There is quite a bit of information just in this test, we introduced the EtlConfigurationContext class, decided that we will create it from a factory, and that we have something that is called a connection. Another decision made was the “retl” extension (Rhino ETL), but that is a side benefit.
The source for this is:
Connection(
"Northwind",
ConnectionType: SqlConnection,
ConnectionString: "Data Source=localhost;Initial Catalog=Northwind; Integrated Security=SSPI;",
ConcurrentConnections: 5
)
Connection(
"SouthSand",
ConnectionType: OracleConnection,
ConnectionStringName: "SouthSand"
)
Connection(
"StrangeOne",
ConnectionType: OracleConnection,
ConnectionStringGenerator: { System.Environment.GetEnvironmentVariable("MyEnvVar") }
)
You may have wondered about the last one, what does this do? Well,...
Dependency Injection in Web Forms MVC
David Hayden has a post about the issue that you face when you are trying to use dependency injection in Web Forms MVC. I talked about similar issues here. He points out that this type of code is bad: protected Page_PreInit(object sender, EventArgs e)
{
// Constructor Injection of Data Access Service and View
ICustomerDAO dao = Container.Resolve<ICustomerDAO>():
_presenter = new AddCustomerPresenter(dao,...
Rhino Commons, Repository<T> and Unit Of Work
Rhino Commons is a great collection of stuff that I gathered along the way, but never documented. There is a sample application (https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/SampleApplications/Exesto), but not much more. I want to spend a few minutes talking about the way the data access part of it works. This is post about how it works, not how to make it work (in other words, very little code here). Before I start, I want to mentions that Rhino Commons is (highly) opinionated software, unlike Castle or NHibernate. It is a separate place where I take what Castle & NHibernate gives me, add a mix...
Rhino Mocks 2.9.6 Released
Hi, over a month without a release for Rhino Mocks is a Big Thing, I think :-)
Anyway, this is a fix to a problem with the documentation message, which only work on the default expectation (because I was lazy when I wrote this?). The basic issue was that this didn't give the correct message:
IAppLock mockAppLock = this.MockFactory.CreateMock<IAppLock>();
//rig up Dispose() method
mockAppLock.Dispose();
LastCall
.On(mockAppLock)
.IgnoreArguments()
.Message("IAppLock should be disposed.");
this.MockFactory.VerifyAll()
Now it will report to you both the fact that you didn't call Dispose, as well as why you should have called dispose, which is a lot more interesting, IMO.
As...
Rhino Mocks 2.9.5: Extending Rhino Mocks...
After getting a request for implementing a feature that I don't want to have in Rhino Mocks (very narrow scenario, very confusing semantics), I decided to follow my own advice and open up the API.
In this case, it involved making MockRepository.CreateMockObject() and the MockRepository.CreateMockState delegate protected. Now, users of the library can extend it with their own recorders and replayers.
Of course, using this require a bit of understanding of how Rhino Mocks Internals work. Basically, when Rhino Mocks is returning a type, its state is set to RecordMockState....
Rhino Tools Worth $1,000,000 ?!
I registered Rhino Tools with Ohloh (which, in Hebrew, means "On no!"), you can find the project site here. Ohloh is a project assesment site, you point it at a repository, and it does its thinks and push a nice graph in the end. Appernatly, it would take 18 years and nearly million dollars to create Rhino Tools. I'm also very surprised by the amount of code that it found, 75 thousands lines of code? I told it to estimate Castle, I wonder what it would...
The New Repository: Rhino Tools
Following the advice from the comments, I have managed to consolidate my various OSS SVN repositories into a single one, hosted at source forge. I was quite suprised that it was so much, to tell you the truth. The repository URL is: https://svn.sourceforge.net/svnroot/rhino-tools/trunk/ To checkout, execute:svn co https://svn.sourceforge.net/svnroot/rhino-tools/trunk/ rhino-tools There is no password necceary for reads. I'll be update the various links on the site to point to the correct location soon.
PluralizingNamingStrategy for NHibenrate
One of the nicest parts of developing with NHibernate is that you can get NHibernate to generate the table from the mapping. This is extremely useful during development, when changes to the domain model and the data model are fairly common. This is even more important when you want to try something on a different database. (For instnace, you may want to use a SQLite database during testing / development, and SQL Server for production, etc). I intend to post soon about unit testing applications that uses NHibernate, and this functionality is a extremely important in...
Binsor on track (and trunk)
IoC 29 - Required to make Binsor work, has moved (with changes from Hammett), to the trunk. I've update Rhino Commons with the new changes, and now you can use it with the Windsor from Castle's trunk. Have fun...
Thinking about APIs: Advance Usages
You may have noticed that I have create some wrappers around NHibernate, to make it easier to work with. NHibernate's API is very rich, and it can get pretty long if you are not careful. Consider the following: Session.CreateCriteria(typeof(Post)) .Add(Expression.Gt("PostedAt", DateTime.Now.AddDays(-3))) ...
Rhino Commons Wiki
I opened up a section in the Wiki for Rhino Commons, mostly just descirbing what it is at the moment
From NHibernate Sessions to Repository
Before: using (ISession session = _sessionManager.OpenSession()) { IList list = session.CreateCriteria(typeof (State)) ...
How to use Rhino Commons in ASP.Net
In the web space, the Unit of Work pattern is usually mapped to a unit of work per web request. This translate very easily to an http module, which you can find here. It configures the container automatically from a file named (by defauly) "windsor.config", and starts / dispose unit of works as part of the http pipeline. Basically, this means that you never need to worry about this. The configuration is simply: < ...
Rhino Commons In The Open
I just realized that I was posting about it all day, but I forgot to mention where you can get it. You can browse the source repository online here, or get the source using: svn checkout svn://svn.berlios.de/rhino-mocks/trunk/rhino-commons
IoC and fluent interfaces
You may have noticed that I like to play word games with code, so here is the Inversion of Control interface in Rhino Commons: The main goal is to be able to say:ISender sender = (ISender)IoC.Container.Resolve("email"); The Initialize() method is called at application start, and will set everything up for the rest of the application. This class is to fetch the repositories, so I can generate a complex object graph and handle some interesting scenarios from the start, using generic decorators. In the end, I didn't...
More on repositories
I forgot to add that I am using a static forwarder class to get a better syntax, so I have this (after the change from RegisterSave()/RegisterDelete() to Save()/Delete() ). Another thing that I wanted to talk about was the FindAll()/FindOne() methods. While they have their overloads for working with ICriterion (and wait for a surprise there too), they also have overloads for queries. Now, I believe that one of the responsabilities of good API is to encourage good code, so I don't have any overload which...
Thinking About The Repository API
I'm currently building the API for the my Repository interface (I talked about it here). Here is what I have so far: Couple of things to note, I don't have Delete or Save methods, instead, I use RegisterSave() and RegisterDelete(), both of those make it clearer that a Unit Of Work is in action here. To make it more explicit (and to allow several repositories to use in a single Unit Of Work, I made the Unit Of Work an explicit concept: ...