I've done it before, but my mind went totally blank yesterday ... due to some typically quick responses from the Castle Users Google Group ... here is the code to do it for future generations to avoid my same silly mistakes ... WindsorContainer container = new WindsorContainer();
Type eventBrokerServiceType = typeof(IEventBroker<>);
Type brokerType = typeof(EventBroker<>);
container.AddComponent("key", eventBrokerServiceType, brokerType);
IEventBroker<EventArgs> eventBroker = container.Resolve<IEventBroker<EventArgs>>();
Assert.IsNotNull(eventBroker);
A short while ago I wanted to get VSTS code coverage reports from NUnit tests ... and after some asking around found that using the Profiler I could get what I needed. I just released a CodePlex project to wrap this functionality. Hope it helps somebody else. Project Description This project is an attempt to provide a wrapper around the VSTS instrumentation and code coverage tools. VSTS provides very powerful code coverage tools with Visual Studio, but as packaged, you need to be running MSTest unit tests to obtain this coverage data. There is a way of getting this data without using MSTest though, bu using another test framework such as NUnit or MbUnit for example. This wrapper encapsulates the generation of the .coverage file from a run of NUnit or MbUnit (or similar), but in addition it provides an automated generation of the .xml version of the .coverage file (both can be read by Visual Studio directly), and then uses an XSLT template to transform the XML output into a final human readabale page (by default a .html file) Further extension will pull the actual parameters from the hardcoded values in the console application into a wrapper class, and will wrap both with a command line tool and with an MSBuild task - however the code is functional enough, and is transparent enough, that both of these tasks should be easy to implement for anyone wishing to do so for themselves if they require this immediately.
Previously I got my basic interception going, to allow me to strongly type resource requests.
The next step was to allow me to inject that capability via Windsor. The test for this was a bit tricky, due to me not understanding the Windsor container syntax in C#, but after a bit of playing around, we end up with the following code to create my IResource via the container. [TestFixture]
public class SpikeProxyResources
{
[Test]
public void TestWithFactoryCreation()
{
IWindsorContainer container = new WindsorContainer();
FactorySupportFacility facility = new FactorySupportFacility();
container.AddFacility("factory.support", facility);
facility.AddFactory<IResource, ResourceFactory>("ResourceFactory", "CreateResource");
IResource resource = container.Resolve<IResource>();
Assert.AreEqual("GetVal", resource.GetVal);
Assert.AreEqual("NewValue", resource.NewValue);
}
}
public class ResourceFactory : IInterceptor
{
public IResource CreateResource()
{
ProxyGenerator generator = new ProxyGenerator();
IResource proxy = generator.CreateInterfaceProxyWithoutTarget<IResource>(this);
return proxy;
}
public void Intercept(IInvocation invocation)
{
if (invocation.Method.Name.StartsWith("get_"))
{
//TODO: Lookup resource here....
invocation.ReturnValue = invocation.Method.Name.Substring(4);
}
else
invocation.ReturnValue = null;
}
}
The next step will be to pull this configuration out into Xml ... or if I can convince the people that matter, into Binsor and Boo!
Whilst discussing Globalization and Localization on the current SharePoint stuff I am working on, the issue of resource files, their location, their abstraction, and their general use came up.
One option was to use resgen.exe to create strongly typed classes for the resources, but I felt that this lost us the flexibility that dropping the .resx files into app_globalresources would provide us with. Although accessing the compiled resources from the AppDomain is easy enough (look for an assembly called "app_GlobalResources"), we would then lose the strong typing, and have to resort to: ResourceManager rm = new ResourceManager(... ,...);
rm.GetString("MyNonTypedName");
So to work around this I spent a bit of time looking into DynamicProxy2 from the Castle stack. After a few interesting diversions into the world of DictionaryAdapter (thanks to Ken Egozii and Josh Robb. Sadly poorly documented, but I'm sure it will prove invaluable soon), I finally came up with the simple bit of code I was trying to achieve: public class SpikeProxyResources
{
[Test]
public void Test()
{
ProxyGenerator pg = new ProxyGenerator();
IResource proxy = pg.CreateInterfaceProxyWithoutTarget<IResource>(new MyInterceptor());
string s = proxy.GetVal;
Assert.AreEqual("GetVal", s);
Assert.AreEqual("NewValue", proxy.NewValue);
}
}
public interface IResource
{
string GetVal { get;}
string NewValue { get; }
}
public class MyInterceptor :IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.Method.Name.StartsWith("get_"))
{
//TODO: Lookup resource here....
invocation.ReturnValue = invocation.Method.Name.Substring(4);
}
else
invocation.ReturnValue = null;
}
}
Fundamentally, this allows us to intercept the calls to the getter on IResource, and look up the resource we are after within the compiled resources. For the moment it may only return the called Method Name, but only because I saved you the boring bit that goes off and gets back the real value.
IResource can now be instantiated by Windsor and adding more strongly typed resources is just a matter of adding a get property onto the interface.
Surely some mistake? I write an Event Handler for SharePoint 2007, deriving from SPItemEventReceiver, and all is well. Until I try to put in some basic IoC using the Windsor container. My thinking is that Windsor will allow me to separate the mechanism and plumbing of the Event Handler from the implementation of my nitty gritty stuff - and indeed it does - all is well and good. Until, that is, I decide to put the Windsor container where it really belongs, in the HttpApplication global scope. My first try for testing this was : if (HttpContext.Current.Application["WindsorContainer"] == null)
HttpContext.Current.Application["WindsorContainer"] = new WindsorContainer(new XmlInterpreter());
IWindsorContainer container = (IWindsorContainer)HttpContext.Current.Application["WindsorContainer"];
Which was all well and good until my Event Handler just fell over ... so I stepped into debug mode ... and was beffudled ... there is no HttPContext.Current ... Nor is there any SPContext.Current either ...
This is confusing, and annoying ... my event is clearly working from an event on a list, which is clearly running within a web application, and within a SharePoint application. Apparently I'm not the first to discover this, but I haven't found a solution yet ... AAARRRRGGGHHHHHH!!!!!!!
Update: Oren and Ken both came up with similar suggestions on how to improve this situation specifically for Windsor, by putting a static class within the assembly that has the container within it. Certainly makes this a little more palatable from the Windsor point of view, but this isn't just a Windsor issue ... SharePoint really does enjoy making my life hell! :)
I am pleased to say, not only do I have a full working Model-View-Presenter implementation running within a SharePoint WebPart now, but I am very very close to having the rendering abstracted away from the WebPart and into a UserControl too. I'll blog more about this when I'm happy with the whole solution end to end. In the meantime however, one annoying problem got me very very confused for a while ... if only SharePoint didn't give such stupid error messages and let you debug it properly, my life would have been much easier ... It was silly mistake really ... would have found it in 30 seconds in an ASP.NET application ... anyway I digress. Remember, if you are using Castle Windsor from the GAC (as you need to for SharePoint work), then the web.config entry must specify the stong name of the assembly in the ConfigSections entry: <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor, Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc" />
I had copied and pasted the entry from another project, not in the GAC, it only had the entry as Castle.Windsor and voila I got a lot of cryptic errors from SharePoint.
As a secondary note, remember all of your entries in the <castle> section must also specify the strong name, or they too will give you cryptic messages and a lot of wasted effort.
Another one to watch out for!
Simple ... and SO MUCH FASTER than iisreset ... cscript "c:\windows\system32\iisapp.vbs" /a "AppPoolName" /r ... where "AppPoolName" is replaced by the pool you want to recycle. Damn useful for MOSS development, where the environment dictates a lot of resetting of IIS to see changes made. Technorati Tags: IIS, SharePoint
Whilst looking for something entirely different, I came across a post by Eric Kraus on putting options on the explorer context menu for .DLL files to allow them to be installed in the GAC and to open them in Reflector. As posted his code didn't quite work, so I modified it a little and it is below. Create a dll.reg file in notepad, copy and paste the following in, then double click it to install the shortcuts. Make sure you change the paths if needed, but be careful to keep the escape sequences intact: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\dllfile\Shell] @="\"c:\\Program Files\\Reflector\\reflector.exe\" \"%1\"" [HKEY_CLASSES_ROOT\dllfile\Shell\Reflector] [HKEY_CLASSES_ROOT\dllfile\Shell\Reflector\command] @="\"c:\\Program Files\\Reflector\\reflector.exe\" \"%1\"" [HKEY_CLASSES_ROOT\dllfile\Shell\InstallGAC] [HKEY_CLASSES_ROOT\dllfile\Shell\InstallGAC\command] @="\"c:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\Bin\\gacutil.exe\" /i \"%1\"" Thanks Eric Technorati Tags: Reflector, GacUtil
Jean-Paul has updated his test naming macro to deal with class names as well as method names, and while I like naming my tests in the form of Test_That_Data_Has_Been_Loaded, I find that JP's macro doesn't work well for me. The reason is that as I type in the form JP does ("Test That Data Has Been Loaded") I find ReSharper kicks in and start inserting class names for me. I have also got in the habit of typing "TestThatDataHasBeenLoaded" which is a lot less readable than JP's convention. So I took JP's macro and modified it for my own use ... it will now turn my style of typing into JP's style of naming... voila ... readable test names! TestThatDataHasBeenLoaded ==>> Test_That_Data_Has_Been_Loaded Code below - all credit to JP for the bulk of this (and I am no VB programmer so my changes are pretty poorly coded, no critique needed pls): Imports System
Imports System.Windows.Forms
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Text.RegularExpressions
Public Module CodeEditor
Sub ReplaceSpacesInTestNameWithUnderscores()
If DTE.ActiveDocument Is Nothing Then Return
Dim wrCS As Boolean = DTE.Properties("TextEditor", "CSharp").Item("WordWrap").Value
Try
DTE.Properties("TextEditor", "CSharp").Item("WordWrap").Value = False
Dim selection As TextSelection = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection)
Dim index As Integer
selection.SelectLine()
If selection.Text = "" Then Return
Dim methodIndex As Integer = selection.Text.IndexOf("public void ")
Dim classIndex As Integer = selection.Text.IndexOf("public class ")
index = CType(IIf(methodIndex >= 0, methodIndex, classIndex), Integer)
Dim prefix As String = CType(IIf(methodIndex >= 0, "public void ", "public class "), String)
prefix = selection.Text.Substring(0, index) + prefix
Dim description As String = selection.Text.Replace(prefix, String.Empty).Trim
Dim r = New Regex("[A-Z][^A-Z]*")
Dim myMatches As MatchCollection
Dim reformedDescription As String
myMatches = r.Matches(description)
Dim successfulMatch As Match
For Each successfulMatch In myMatches
reformedDescription = reformedDescription + successfulMatch.Value + "_"
Next
reformedDescription = reformedDescription.Trim("_")
selection.Text = prefix + reformedDescription + vbCrLf
selection.LineDown()
selection.EndOfLine()
Catch ex As Exception
MsgBox(ex.Message)
Finally
DTE.Properties("TextEditor", "CSharp").Item("WordWrap").Value = wrCS
End Try
End Sub
End Module
The interfaces we have created in Abstracting SharePoint allow us to unit test our code, but only if we mock the objects. We can do this in 2 ways, we either write an implementation of our own that mimics the SharePoint model (by storing data in in-memory objects for example), or we can use a mocking framework like Rhino Mocks or TypeMock.NET
My first approach was to write my own mock of SharePoint. This, I reasoned to myself, would allow me to actually setup test data, and to use the mocked layer to operate as a way of demonstrating the system in addition to testing.
This approach soon became a nightmare, the SharePoint object model is convoluted and confused. The interactions between objects are unclear, and often unexpected. I gave up on this one after a few hours of work that convinced me I needed to go down the other route.
For mocking I had a range of mocking frameworks to choose from, but Rhino Mocks (which I have used before with great success) was the obvious choice. Rhino has one limitation though which made me consider an alternative, it cannot mock Sealed classes. The bright sparks that wrote Microsoft.SharePoint decided the classes would be sealed, so although I can use Rhino to mock my newly formed interfaces, I would not be able to use it to mock Microsoft.SharePoint classes should the need arise (for example if it becomes too complex to complete the interface abstractions).
TypeMock.NET can, I am told, mock sealed classes. This would make it an ideal candidate for dealing with SharePoint. It is however a commercial product, and a pricey one at that. Cost isn't really a major issue here, but still it is a factor. It is also somewhat trickier than Rhino to get to grips with, at least for someone that has only just got to grips with the simpler aspects of Rhino.
For the present I am going to use Rhino, and I am going to hope I do not have to mock any sealed classes. If I do then TypeMock.NET may save me, but I suspect at that point I am in deeper trouble anyway. The two syntaxes are different enough that the learning curve is probably not worth it until I hit those 'sealed class' cases.
The Rhino Mocks version: [TestMethod]
public void TestLookupUniqueItemReturnsSingle()
{
MockRepository mocks = new MockRepository();
ICustomSPQuery query = mocks.CreateMock<ICustomSPQuery>();
ICustomSPList list = mocks.CreateMock<ICustomSPList>();
ICustomSPListItemCollection expectedResults = mocks.CreateMock<ICustomSPListItemCollection>();
ICustomSPListItem listItem = mocks.CreateMock<ICustomSPListItem>();
int numberOfResultsToReport = 1;
With.Mocks(mocks).Expecting(
delegate
{
using (mocks.Unordered())
{
Expect.Call(query.Query).PropertyBehavior().IgnoreArguments();
Expect.Call(list.GetItems(query)).IgnoreArguments().Return(
expectedResults);
Expect.Call(expectedResults.Count).Return(numberOfResultsToReport).
Repeat.Any();
Expect.Call(expectedResults[0]).Return(listItem);
}
})
.Verify(
delegate
{
ListLookup lookup = new ListLookup(list, query);
ICustomSPListItem lookupResult = lookup.LookupUniqueItem("test", "test");
Assert.AreEqual(listItem, lookupResult);
}
);
}
And the TypeMock.NET version: [TestMethod]
public void TestSingleItemFindsMatch()
{
MockManager.Init();
ICustomSPList list = (ICustomSPList)RecorderManager.CreateMockedObject(typeof(ICustomSPList));
ICustomSPQuery query =
(ICustomSPQuery)RecorderManager.CreateMockedObject(typeof(ICustomSPQuery));
ICustomSPListItemCollection expectedResults = (ICustomSPListItemCollection)RecorderManager
.CreateMockedObject(typeof(ICustomSPListItemCollection));
ICustomSPListItem item =
(ICustomSPListItem)RecorderManager.CreateMockedObject(typeof(ICustomSPListItem));
using (RecordExpectations recorder = new RecordExpectations())
{
query.Query = "";
recorder.ExpectAndReturn(list.GetItems(null), expectedResults);
recorder.ExpectAndReturn(expectedResults.Count, 1).RepeatAlways();
recorder.ExpectAndReturn(expectedResults[0], item);
}
ListLookup listToLookup = new ListLookup(list, query);
ICustomSPListItem result = listToLookup.LookupUniqueItem("FieldName", "MyValue");
Assert.AreEqual(item, result); MockManager.Verify();
}
There is one more point in favour of Rhino Mocks ... its author Oren Eini (known as Ayende) is possibly one of the most talented developers I know, has a real passion for good quality code, and a deep commitment to open source and providing great tools to other developers. That alone makes Rhino an excellent choice.
Fingers crossed!
This is a repost from my old blog, as it is code I'm bound to need again sometime...
More than once I have needed to sort items according to some arbitrary sort criteria, for example to sort a list of status codes. They can't be logically sorted alphabetically, so I wrote these routines.
In the example, it is a string list, but it could be any object with a bit of modification. Essentially this uses a Comparer, which uses the position within the SortString to decide on the order of the items. Nice and simple.
List<string> MyList = new List<string>();
MyList.Add("OK");
MyList.Add("Failed");
MyList.Add("Stopped");
MyList.Add("Beginning");
SortStringList(MyList, "Beginning;OK;Failed;Stopped;");
private void SortStringList(List<string> list, string sortString)
{
if (string.IsNullOrEmpty(SortDirection))
list.Sort(new StringListComparer(sortString));
else
{
StringListComparer.SortDirection direction;
try
{
direction =
(StringListComparer.SortDirection)
Enum.Parse((typeof(StringListComparer.SortDirection)), SortDirection);
list.Sort(new StringListComparer(sortString, direction));
}
catch(ArgumentException ex)
{
throw new ArgumentException(
string.Format("An attempt was made to parse the
SortDirection key ('{0}') which did not evaluate
to a known value", SortDirection),
ex);
}
}
}
public class StringListComparer : IComparer<string>
{
public enum SortDirection
{
Ascending,
Descending
}
private SortDirection _sortDirection;
private string _sortString;
public StringListComparer(string sortString)
: this(sortString, SortDirection.Ascending)
{
}
public StringListComparer(string sortString, SortDirection direction)
{
if (sortString == null)
_sortString = string.Empty;
else
_sortString = sortString;
_sortDirection = direction;
}
public int Compare(string x, string y)
{
if (x == null || y == null)
return EvaluateForNullStrings(x, y);
else
return EvaluateForNonNullStrings(x, y);
}
private int EvaluateForNonNullStrings(string x, string y)
{
int indexOfX = _sortString.IndexOf(x) + 1;
int indexOfY = _sortString.IndexOf(y) + 1;
if (indexOfX == 0 && indexOfY != 0)
return (_sortDirection == SortDirection.Ascending) ? -1 : 1;
else if (indexOfX != 0 && indexOfY == 0)
return (_sortDirection == SortDirection.Ascending) ? 1 : -1;
else
return (_sortDirection == SortDirection.Ascending)
?
indexOfX.CompareTo(indexOfY)
:
indexOfY.CompareTo(indexOfX);
}
private int EvaluateForNullStrings(string x, string y)
{
if (x == null && y != null)
{
return (_sortDirection == SortDirection.Ascending) ? -1 : 1;
}
else if (x != null && y == null)
{
return (_sortDirection == SortDirection.Ascending) ? 1 : -1;
}
return 0;
}
}
|