dinsdag 18 november 2008

Using a Factory for resolving a dependency

Today I solved the gap between Dependency Injection with Unity and a Factory. What was the question?

We have a UseCaseFactory for creating instances of descendants of the UseCaseBase class. This factory internally uses the Microsoft Patterns & Practices Unity container for actually instantiating the requested class and its dependencies. When a UseCase is created, it gets it's own container.

To make things even more complex, we have UseCaseFactory.CreateChildUseCase, which results in a UseCase in the same container as the parent UseCase.

Some descendants - but not all - require repositories for data handling and therefore a Hibernate session. Currently there is a HibernateSessionFactory as well. The NewSession() method can provide you with a session.

The old solution was ugly: All UseCase classes that required a repository had to be derived from UseCaseWithRepositoriesBase. The CreateUseCase method would check on this. If true, then it created a Session with the HibernateSessionFactory and registered this instance in the container. After that, all necessary repositories (that depend on a session) could be resolved.

I did not want to completely change the creation of Hibernate session objects just to get rid of the factory. It took me a little while to find out what I really wanted: Register a method on a factory in the container to use when resolving the Hibernate session.

There are not many hits on it in Google, but it is possible. The Unity framework provides the StaticFactoryExtension exactly for this purpose. Here's how it works:

Imports Microsoft.Practices.Unity
Imports Microsoft.Practices.Unity.StaticFactory

Public Class UsecaseFactory

Private Shared mHibernateFactoryExtension As New StaticFactoryExtension()

Shared Sub New()
mRootContainer = New UnityContainer

mRootContainer.AddExtension(mHibernateFactoryExtension)
mHibernateFactoryExtension.RegisterFactory(Of HibernateSession)(AddressOf HibernateSessionFactory.CreateSession)
End Sub
End Class

Effectively you tell the container: If a HibernateSession instance is requested and it does not yet exist, call HibernateSessionFactory.CreateSession to create it for you.

You have to provide the RegisterFactory method with a delegate of type FactoryDelegate:

Public Delegate Function FactoryDelegate(ByVal container As Microsoft.Practices.Unity.IUnityContainer) As Object

Although you get the container as a parameter, you need not register the result yourself. You just have to return the requested object (in this case a HibernateSession object). It will automatically be registered in the container. The container is probably just there for your convenience in case you need to resolve other classes along the way.

maandag 10 november 2008

XML questions, serializing and numbering

Two questions I got today, regarding .Net, XML, XSD and XSLT:
1. I have an existing class that is Xml serializable. Can I make the serialization conform to an also existing XSD schema?
2. I have a sequence of elements in one XML. In transforming it to another XML (using XSLT), can I number the resulting sequence in te result?

One by one, that's the credo.

Question one is less of a problem than it seams: The differences are only in the ordering of elements. All the elements from the XSD are in fact present in the existing class. But can we steer the XML serializing so that it will use the ordering prescribed by the XSD schema?

There's a book I should be learning inside out, but I cannot find the time for it. It's annoying. But I knew it contained information about question 1. It the MCTS Application Development Foundation book. Well, chap 5, lesson 2, "How do I conform to an XML Schema". The solution is simple: use the Xml Schema Definition tool xsd.exe tool from the Visual Studio Command line:
xsd C:\schema\blabla.xsd /classes /language:CS

Of course, /language:VB is also a valid option.

Problem is: you generate a new class, but we already had an existing class.

Secondly, I went through the help for XmlSerializer and XmlWriterSettings. I didn't find any help there. And the attributes for steering the XmlSerializer don't seem very helpful either.

Conclusion: Do use the xsd tool, and manually adapt your existing class to match the generated class.

On to question 2. Simple. The answer is in the XSLT Cookbook, chapter 5.5, "Numbering textual output". Just use the xsl:number element, and read the help on it for several options.

donderdag 6 november 2008

Unity and MethodAccessException

This was such a day where I got a problem on my desk even before I got coffee. By now, problem is solved and I had some coffee, so time to register the problem and the solution here.

I'm working on a software package for a customer. Up to the previous version we used the ObjectBuilder dependency injection framework. With the latest release we converted it to Unity. Everything still worked in local tests.

So, it was deployed at two client test-sites. Neither of them worked. The log was full of MethodAccessExceptions. This resulted in Unity not being able to resolve many dependencies. We tried:
- moving all the dll's to the same directory as the exe;
- updating to Unity 1.2 (we started with 1.0);
- signing the Unity dll's (see here for an explanation);
- updating the test server (Windows 2003 Server) with Microsoft Update.

It turned out that there were 44 updates available for the server, including Windows Server 2003 SP1. Finally, after installing these updates, it worked. We think SP1 was the necessary one. However, since all this updating is done through a remote desktop we didn't bother trying to find out which of the updates actually did the trick.

Along the way, with signing the Unity dll's, I found out that I cannot open the Unity solution file. Neither the 1.0 nor the 1.2 version. It states that "The projectfile [...]\Tests.ObjectBuilder.csproj cannot be opened. The project type is not supported by this installation.So far, I have not found out what is required to open this project file. If anyone knows, please post a reply.

Second thing along the way: Dependency injection is nice, but you can hardly find out which type is loaded when. If you want some insight in this, you can use the Fusion Log viewer, Fuslogvw.exe in the Windows SDK (on my machine: C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin). Susanne Cook has blogged about it here.

Back to normal work....