Something is locking me out of my assemblies ... after a clean Get Latest from TFS, i go to a command prompt and run my MSBuild script ... it fails with errors reporting it cannot delete the directory as it is not empty, and then proceeds to report a host or errors updating assemblies as access is denied. If I then go back to Visual Studio I get the following error for every project .... "Cannot analyze project output:"
I don't know if this is Visual Studio, TFS or ReSharper causing this but it is annoying me to hell ... closing the solution lets me run MSBuild perfectly again ... anyone got any ideas?
UPDATE: Turns out that this is a ReSharper error certainly present in 3.1 ... I found this out as the amazingly responsive ReSharper team took a look at my post, and replied immediately admitting it was a bug of theirs. It also turns out it was already fixed in version 4.x but not in 3.x ... after a very short whine by me to Ilya at JetBrains, he then dropped me back an email very soon after telling me the changes had been back ported into the 3.x build, and would appear there from the next nightly build. Now that is responsive!
Suffice to say, and good to their word, the error is no longer present ... Yippppeeee!!!!!
Thanks for the many suggestions I had to try and pin this down!
OK, so I figure it's 6am - in the interests of personal education, and possible improvement of my framework for my client, I decide I best get down and dirty with Unity and see how simple it is to replace Windsor in our current application. If it is simple, and it makes the application simpler, then I'll go the Unity route (as a MS fanboi I really do prefer the MS option where all other factors are equal). Some debate on altdotnet made me consider my position on it. Unity is roughly comparable to IoC containers like Windsor and StructureMap, the CodePlex site description says: The Unity Application Block (Unity) is a lightweight extensible dependency injection container with support for constructor, property, and method call injection. So ... I download the project from CodePlex ... and double click the solution file ... I only have VS2008 Development Edition on this laptop, no VS2005, so a conversion is required. OK - I have done this before - it should work right, after all CodePlex says: You can modify or extend the Unity Application Block using Visual Studio 2008. When you open a solution, Visual Studio 2008 will upgrade the projects to its format and you can edit and compile the code to create assemblies targeted at version 3.0 of the .NET Framework. However, you will not be able to convert the projects back into Visual Studio 2005 format. Therefore, it is a good idea to work with a copy of the original solutions and projects. Guess what ... the conversion fails. Well mostly it works, but all of the Unit Test projects fail to convert. Come on MS ... these are your things ... your IDE, your conversion wizard, your CodePlex project, and your unit testing framework - this is not rocket science. OK - I'll give you a little leeway as Unity is a CTP ... So I close it down after struggling a little with the sample applications when I don't have unit tests to read (more on the sample apps shortly). Go and read CodePlex for 20 mins to try and see if anyone has these problems, but with no luck. I brace myself to figure this stuff out without unit tests, and double click the solution again. It now tells me it needs to do a conversion. Deja Vu moment ... surely I just converted it already ... maybe I was dreaming. I tell it to do the conversion, and bingo it converts successfully, including all the unit test projects it failed to convert 20 minutes ago. Inconsistent behaviour annoys me ... either fail to convert every damn time, or work every damn time, but don't pick and choose based on some ethereal criteria I am unaware of! Right ... I have a full solution loaded ... lets compile this and see it fly ... Nice idea ... except VS thinks otherwise ... all references to using Microsoft.VisualStudio.TestTools.UnitTesting are showing red in the test projects. All references are broken ... they point to Microsoft.VisualStudio.QualityTools.UnitTestFramework correctly, but they show pointing to version 0.0.0.0 which I guess is the VS2005 reference misbehaving in VS2008 ... so I have to manually update each reference, either by changing the "Specific Version" property to false in which case it auto picks the version 9.0 assembly, or by removing the reference and re-adding it (and we all know how tedious that is to do). Why????? Why make me go through all this to see Unity, when every tool I was using was from MS ??? I understand it isn't entirely the fault of the Unity team here, but surely you guys are in the best possible position to know about the way each others products work. I choose MS products because I expect them to *just work* out of the box ... I choose certain OSS products expecting them to not be packaged as nicely, or as well documented, and expect a few niggles. So I have wasted at least 30 minutes on Unity already, and haven't read any code. Please Microsoft, make your things play nicely with each other ... is that too much to ask? Right ... off to actually see how Unity works, and how it can make my life easier now ...
Today I wanted to setup JetBrains TeamCity as a pilot to run continuous integration for us.
With their new licencing model, TeamCity is free for up to 20 build configurations, 3 build agents and 20 users, which is more than enough for us to get going and see if it improves our process.
Other options were Team Foundation Build or CC.Net
Personally I discounted Team Build early, various comments on mailing lists and forums made it very clear that it was far from being a CI server out of the box, and although after some apparently extensive configuration it could be made to do something similar, it is far from a friction free piece of software.
CC.Net I have used a number of times before, but the XML configuration it requires is less than joyous, and no matter how often I set it up, I never seem to get quicker at it. Good it may be, easy to configure it isn't.
So we decided to start off with a clean Windows 2003 Server installation, as it comes out of the box. That meant that we didn't even install IIS, as TeamCity includes Tomcat to serve up its dashboard.
We had a few teething problems, but the installation was up and running inside a few short minutes ... albeit not building.
The first problem was rather major - under the VCS settings in TeamCity we had opted for Team Foundation Server, and given it all the settings we knew to be correct - but it repeatedly gave us an obscure error - one with no information other than a java exception:
jetbrains.buildServer.vcs.VcsException: TFS execution error Stdout: TFS Native Verifier v1.0 Copyright (C) 2006-2007 JetBrains s.r.o. by Mikhail Pilin and Eugene Petrenko Stderr: Exception: at jetbrains.buildServer.buildTriggers.vcs.tfs.TfsNativeExeRunner.start(TfsNativeExeRunner.java:20)
We spent a fair while on this, eventually giving in and dropping an email to JetBrains - all credit to Serge there for a quick response. After a few confusing emails backwards and forwards, the first solution they could suggest was that I needed a "full TFS" install on the CI server.
This wasn't a great solution - we were deliberately trying to keep the server clean, the last thing I wanted was Visual Studio or Team Explorer installed.
After a bit of searching around, and some helpful hints on the altdotnet mailing list, I found that MS now package the Team Explorer as a download on its own. This looked after unpacking to install some kind of Visual Studio "light" which I still didn't want on the server - but after drilling down I found the Microsoft.TeamFoundation.xxxx assemblies were included in the package. I added these into the GAC, and the problem was instantly resolved without an install of Team Explorer or Visual Studio. A very short while afterwards a clarification came from JetBrains:
To be more specific, the following components must be in PATH:
Microsoft.TeamFoundation.Client.dll Microsoft.TeamFoundation.Common.dll Microsoft.TeamFoundation.Common.Library.dll Microsoft.TeamFoundation.dll Microsoft.TeamFoundation.VersionControl.Client.dll Microsoft.TeamFoundation.VersionControl.Common.dll Microsoft.TeamFoundation.VersionControl.Common.Integration.dll Microsoft.TeamFoundation.WorkItemTracking.Client.Cache.dll Microsoft.TeamFoundation.WorkItemTracking.Client.DataStore.dll Microsoft.TeamFoundation.WorkItemTracking.Client.dll Microsoft.TeamFoundation.WorkItemTracking.Client.Provision.dll Microsoft.TeamFoundation.WorkItemTracking.Client.QueryLanguage.dll Microsoft.TeamFoundation.WorkItemTracking.Client.RuleEngine.dll Microsoft.TeamFoundation.WorkItemTracking.Proxy.dll
The GAC solution was therefore on the mark, but we may have got away with dropping the assemblies in the path too. Either way - this was a much cleaner install.
Our second problem was a silly mistake in configuring the project. We are using MSBuild to do the building, and we kept getting a "MSBuild Schema could not be found" error. After a lot of head bashing it turned out I had managed to click on the Validate option in TeamCity, and it was TeamCity rather than MSBuild that was throwing the error - TC could certainly do with better logging. The missing schema file could probably have been dropped alongside the .build file, but as we didn't need it to be validated, we unticked the option, and voila ... it all worked ... almost ...
One last little niggle caught us, NCover was timing out while running, and giving us an error regarding the profiler. We had included NCover in our TFS tree, along with NUnit, Rhino, and all the other tools we need, this was to avoid having to install anything on a workstation to be able to build the projects.
After a hint from Ayende, it turned out that NCover requires an assembly to be registered with regsvr32, something I haven't done in so long, I had forgotten the command even existed! So to solve this problem, the answer is:
regsvr32 coverlib.dll
It may not be ideal, but it does the job, and I think I can live with one assembly needing to be registered, at least in the short term.
Update: Grant Drake posted about this a while ago, and has 4 possible solutions here ... using //reg on the command line is a much better option in a CI environment, so I'm switching our build to do that this morning.
And with all that done, we now have a *very* clean CI server, running a very basic Windows Server install, with a very neat TeamCity install.
Now to show the business benefit!
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.
Whilst reading a great article on getter and setter methods, I came across a small quotation that perfectly encapsulated the problems I see with a lot of code at my current client: Developers by their nature have a desire to hang on to global data, and to create global methods.
In 1989, Kent Beck and Ward Cunningham taught classes on OO design, and they had problems getting people to abandon the get/set mentality. They characterized the problem as follows:
The most difficult problem in teaching object-oriented programming is getting the learner to give up the global knowledge of control that is possible with procedural programs, and rely on the local knowledge of objects to accomplish their tasks. Novice designs are littered with regressions to global thinking: gratuitous global variables, unnecessary pointers, and inappropriate reliance on the implementation of other objects.
This problem is particularly common where I am at present as a large part of the development work is in MOSS 2007, which encourages global data and methods in a large number of insidious ways.
I'm now off to re-read Beck and Cunningham in more detail ... but in the meantime, pretty please MS, could you stop encouraging bad practices!
Early in the new year my current client has asked me to present to the senior management on two areas they feel they can currently improve in, their RUP project management process, and their development processes overall.
Attached are two presentations in their early form, in PowerPoint 2003 format.
Missing from the presentations are the notes (which I will add once I am happy with the overall structure) but you should be able to figure out what I am intending to say for each slide/bullet point.
Both of these presentations will evolve over the next few weeks. Feel free to comment either by the comment option or directly to me, and if you think they will be helpful to you for a presentation, also feel free to use them and modify them as you see fit.
Agile.ppt (80.5 KB)
This is intended to give a very high level view of Agile, to a group of senior managers who practice almost none of these things at present, and who are not 'tech savy'. This is fundamentally a 'get to know you' kind of presentation, to encourage aspects of Agile to be adopted, rather than any specific methodology or practice.
Development.ppt (80.5 KB)
This is intended to be presented to a similar level group, but the audience members may overlap to some degree with the previous presentation, and some may not. At the moment it is more likely that these people are closer to the ground and more 'tech focused'.
It is intended to give some key practices that can help improve the development processes the client currently has, again without forcing a wholesale shift to a specific Agile methodology on to them.
Oh, and Merry Xmas (or whichever thing you celebrate at this time of year!)
There are many forms of speed bump in development, things that cause you to slow down, stop, change your train of thought. From large things like people coming to your desk and asking questions, to smaller things like your IDE pausing for that half a second to refresh the screen. In fact if you think about your day, it is amazing how you get any work at all done with this many distractions and diversions. But, to me, the most annoying of all these things is a poorly thought out IDE - after all I spend a lot of my time inside it, and that means a lot of my wasted time is caused by it too. On the ALT.NET mailing list Frans Bouma suggested that most refactorings were small things that take less than a minute to do without a tool like ReSharper or Refactor. To me - that is a speed bump - it is a minute I really shouldn't have to waste, just because I thought of a better way to structure a small part of my code. I don't think I have ever written a piece of code that was right first time, so pretty much I refactor everything I write to some lesser or greater degree. Visual Studio is a great IDE, but it still has lots and lots of annoying things, and the refactoring it supports is pitiful. So for me, ReSharper is essential, it removes so many speed bumps from my daily path, that I can continue onwards and keep watching the road.
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! :)
|