February 2008 - Posts
Holy moly releasing software is quite the process. :) After about a month or so of trying to get my Plug-in Edmx Code Generator released, I'm proud to say that it's finally out on the new Entity Framework Contribution Project (I'm a contributor, scary!). I wanted to take some time to post about this little pet project and its history.
History
First off, I learned a little bit about plug-in architecture from the great EntLib project. I was pretty impressed with it, so it instantly became a new tool in my toolbox.
Upon reading about how the current event hooks work for code generation in the Entity Framework, I was disappointed in the overall process. To me, if someone wants to hook into the code generation process, it should be as easy as dropping an assembly into a plug-in directory and when the EF code generator fires, it should just load all the assemblies in that plug-in directory and register the code generator with any located subscribers.
So that’s what I set out to do. Initially I had to reverse engineer the System.Data.Entity.Design.VisualStudio assembly and do all sorts of wicked code magic to make this work on my personal project. Major props to the ADO.NET team for releasing the SampleEdmxCodeGenerator, from which this new codebase is derived from.
This project is a little rough around the edges. I don’t have the time to acquire a PhD in the Lore of COM to learn how that mire works (no sir, not a fan). So, testing is sporadic, at best. I’ve attempted to make the install process as straight-forward as possible, so no reasonable developer should ever EVER have to touch the registry or go to the command-line (stay away from that filth!). It is 2008, after all. I’d like to think we’ve progressed a little in our development capacities and IQ to ever have to deal with COM or a command prompt…
Oh, am I ranting? My bad. J Let’s look at how to install this sucker, shall we?
Installation
First thing is first: THIS IS A FIRST VERSION RELEASE! This isn't exactly a production-ready piece of software. This is something that I've pieced together over the course of a couple months, and got it working to my needs, and then ported over to the Contrib(UTION) project. Things are not exactly 100% complete, but "should work" (read: "works on my machine"). I'm sure there are a lot of edge cases I may be missing, and the testing project quite frankly leaves much to be desired.
... And with that...
If you get the latest Entity Framework Contribution solution, you’ll notice that there are two new configurations within the Configuration Manager (found by right-clicking the solution and selecting Configuration Manager): Install and Uninstall. Furthermore, you can find another CPU setting for x64 machines for you 64-bit developers (as I am J).
The installation process is pretty simple:
1) Select Install configuration
2) Select the type of processor configuration of Visual Studio you have on your machine (Any CPU for 32-bit, x64 for 64-bit)
3) Build EntityFrameworkContrib.Design.VisualStudio.Install
This will build and register the DLL, and install the necessary registry settings on your machine.
Usage
How does this plug-in system work? The process works as such:
1) Create Visual Studio 2008 Class Library project
2) Create a class that implements the EntityFrameworkContrib.Design.VisualStudio.IEdmxCodeGeneratorSubscriber interface within this class library and implement your custom code within the Subscribe() method.
3) Decorate the assembly with the EdmxCodeGeneratorSubscriberAttribute attribute, like so: [assembly: EdmxCodeGeneratorSubscriber( typeof(MockCodeGenerator) )]
4) Build the assembly.
5) Place the assembly within the plug-in directory. By default this is the same directory as where the devenv.exe is found (something like C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE). You might find this is a little slow since this directory has a bunch of .dlls in it already. I’ve made it so that you can specify a plug-in directory through configuration (more on this below).
6) Set the Custom Tool for each Edmx file that you want to take advantage of this process to “PluginEdmxCodeGenerator” (without quotes, of course).
7) Right-click your .edmx file that you configured in the above step, and select Run Custom Tool.
If the stars aligned correctly, you should get a .cs built and compiled that consists of the output you expected from your custom code defined in step #2.
Plug-in Directory
If you don’t like the default directory (and I don’t, so neither should you), then you can specify where you’d like that directory to be. This is where it gets a little hacky, because it does involve editing the configuration for devenv.exe. If someone is familiar with how to manage a configuration section from outside the executing assembly, I am all open for suggestion and correction. The ideal situation would be to simply drop an EntityFrameworkContrib.dll.config file right into the devenv.exe directory so that devenv.exe automatically reads configuration for EntityFrameworkContrib from this file. But alas, I couldn’t figure out how this works. So in the meantime
To set the configuration:
1) Make a copy of devenv.exe.config just in case. ;)
2) Open devenv.exe.config found in the same directory as in step #5 above (hey, it’s better than driveling through the swine that is The Registry!).
3) Add the following configuration into the <configSections> block at the top:
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="EntityFrameworkContrib.Design.VisualStudio.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
4) Add the following configuration right below the closing </configSections>
<applicationSettings> <EntityFrameworkContrib.Design.VisualStudio.Properties.Settings> <setting name="PluginDirectory" serializeAs="String"> <value>C:\ADO.NET Entity Framework Edmx Code Generation Plug-ins</value> </setting> </EntityFrameworkContrib.Design.VisualStudio.Properties.Settings>
</applicationSettings>
5) Modify the <value></value> block to point to a valid directory path on your system. I’ve setup the pathing resolution within the PluginManager to resolve any environment variable specified in this value.
Yes, overall this is a pretty involved process. IMHO the good folks on the ADO.NET team should implement this pattern for their default code generator so that this functionality is all setup and ready to go out of the box. Plug-ins are the Right Thing to do and make it easy to extend provided framework functionality without having to wrestle with arcane, obsolete concepts like registry settings and COM.
Yes, I feel better now. J
I hope this helps someone out and makes code generation a little easier for the Entity Framework. If you have any questions, there is a Mock assembly included in the Contrib(UTION) project that makes use of the necessary hooks to make this sucker work. Please feel free to take a look at this, and if you still have questions, don’t hesitate to send them my way!
Sweet! Very cool. Another new toy to try out.
For some time now I’ve been thinking about this concept for Visual Studio that I feel would help out development workflow tremendously. I will preface this entry by saying that it’s very unlike me to suggest an idea without actually implementing it myself. I am currently maxed out with my personal project and adding “one more thing” to it would exceed my level of personal time for commitments (yes, that’s me learning how to say “no!”).
I’m hoping that with this post, an influential mind over at Microsoft (ScottGu, perhaps??? J) will see this and create an “actionable item,” (my new favorite phrase) or perhaps spawn a new CodePlex workspace.
The Problem
Consider creating a codebase that consists of common utilities and helper methods. Over time, this codebase grows as you add new classes and functionality to this base, ultimately ending in a variety of projects that tackle different problems (Web, UI, etc.). Now consider porting this codebase over to a new solution entirely, and this solution lies on a new Team Foundation Server.
You have to copy the entire codebase. There’s no way to have one TFS server “point” to another codebase on another server.
You now have two different sources to maintain and manage, one for each TFS server. Bummer. You could of course maintain one codebase on one server, compile it whenever there's a change, and then copy the dll over to the other server (along with the subsequent checkins and outs), but that workflow is a bit cumbersome and tedious, at best. There is still a considerable disconnect between the two solutions.
Now consider the current process for incorporating a 3rd-party assembly such as the Ajax Control Toolkit or Enterprise Library into your project:
1) Find out about the assembly (somehow).
2) Download the assembly (or package that places a versioned assembly onto your machine).
3) Add assembly into project.
4) Develop based on assembly in project.
Pretty straight forward, right? Well it is, in fact. That is, until another version of the assembly is published and made available for consumption. Then things get a little trickier, especially if the assembly is installed by an install package. If you have a team of developers each developer must download the new package, and install the old one.
The Ajax Extensions framework is a perfect example of this. I’ve witnessed four or five instances where developers were in .dll hell (yes, in a .NET project!) trying to figure out why their project failed due to an incorrect assembly version within their project. Granted, this was during the CTP and beta bits of this project, so shame on us for developing on pre-release bits, but it really made me think a little bit about the nature of assemblies and how they are used in development.
The other problem with this paradigm is that when a 3rd-party assembly is used within a project, it is a static versioned copy that is shared across many machines. That is, it’s not “live” or there’s no easy way of knowing when a new version of that assembly is available, and when there is a new version, there’s no easy way of incorporating that assembly into the project.
The Solution: Connected Projects
So what I’ve been thinking for some time is an add-on project type for Visual Studio that I like to call a Connected Project. A Connected Project works much like a regular project. It is a project you can include in your solution and reference from other projects in your solution. The major difference is that it doesn’t include source code (although access to code would be in the same way that the Core .NET libraries are now accessed), and it pulls its compiled assemblies from CodePlex.
So let’s say I install my Connected Project package and everything is set and ready to go.
In the world of Connected Projects, I would right-click my solution and Add Connected Project. I then get an Open Dialog box that peers into the world of CodePlex (much like the web reference dialog box). I can then search for my project or browse for projects. Once I have found my project I can add it to my solution.
Once it’s added to my solution, it functions just like a regular project in Visual Studio. I can check it into source control. It has references to all the assemblies it needs to operate correctly. The key here is that this project sits on CodePlex and is downloaded on my machine on the first compile (or whenever I rebuild). Of course we can cache the assembly output so that the different versions are available locally so that CodePlex isn’t being hammered more than it already is. J
This Connected Project then becomes a live, dynamic project in my solution, in the sense that whenever a new version of this project is available (beta or otherwise), I can then go into the Properties of this project and update the version that my solution is using. I can also set up my debug configuration to always use latest (Automatic) and my release configuration to always use a specific version, for production purposes.
Breaking changes in the latest nightly build version of the Connected Project? No problem. Just revert to the previous version of the project (this is controlled by a new tab/control in the Remote Project’s Property Pages). No need to muck with code or bug regression.
This solves the problem of having to subscribing to an RSS feed or blogs to know when a new version of a project is available. I can have the latest build (public, beta, or otherwise) directly in my solution without even having to open a web browser to download it first.
I also don’t have to worry about copying code over to different servers, or maintaining more than one codebase. Every solution points to the same project, and is connected to its updates and check-ins.
While we’re at it, we can use Connected Projects as a hub to bolt CodePlex functionality right into Visual Studio (I’m a big fan of CodePlex’s vision!). So you can get the latest news and updates for the CodePlex project straight from the Connected Project. Maybe just for the sake of branding and identity we can just stop the foreplay and call these projects CodePlex Projects. J
I hope I’ve explained the problem and have done a decent job proposing a solution for this. I’d really like to get some discussion on this. Perhaps this already exists in some form and I’m completely ignorant on its existence (this does happen from time to time!)
If this makes sense to you, please vote for this on CodePlex!
Awww jyea! I'm officially slated a spot in the Unity Workshop announced earlier this week. This will be a tremendous opportunity to dive further into my latest conceptual toy: Dependency Injection. I learned about DI when I started diving into the bowels of EntLib 3.1. All paths pointed to this ObjectBuilder.dll. I had to find out more about it.
There are a lot of DI frameworks out there, but strangely enough none by the big MS. I found this sort of strange. The more I became enamored by this new toy (and the resulting power it brings), the more I scratched my head wondering why on earth there wasn't something like this for EntLib or from MS.
So, for my first run at building an application block, I set out to build an ObjectBuilder Application Block. :) I actually have it completed, with full-on designer support, and was going to release it on CodePlex until I found out about Unity.
Mr. Hollander brings up a pretty great question about the time being spent on Unity. Although I share his concern with the energy being spent on refactoring (it's the ultimate balance every great developer must learn), I would like to interject a point of my own.
I have great respect for EntLib. In fact, I'd have to rank it in the top 3 public codebases I've encountered in my little journey of software development. It tackles a lot of problems and I believe the design is very well-rounded. I've learned an incredible amount of knowledge from studying this codebase, probably just as much or more so than the .NET Framework (I'm a Reflector Whore). EntLib is a great reference tool, in addition to being a great productivity tool. As such, I believe the refactoring is very much worth the time. A codebase like this should offer Best Practices (since it is Patterns and Practices!) on how to develop a enterprise-level and scalable solution. It's imperative that it shows developers the Right Way of doing things. If that means finding obvious flaws and spending a couple weeks fixing them, then do it.
I guess the point I'm trying to share is that there is a lot more value to this framework than just its functionality. We should keep that in mind when time spent into refactoring comes into play.
And yes, I for one am a little taken aback by all the assemblers and configuration. That didn't stop me from mimmicking them in my own solution, however. (I had to try it out first to get the eyebrow-raise). :)
Finally, I would like to encourage the EntLib team to PLEASE PLEASE PLEASE put more effort into the Configuration Designer in EntLib. In fact, ScottGu or someone over in the .NET team should really take this thing and run with it. We as developers should never ever EVER have to touch a line of XML to configure our applications. That's tantamount to pulling open a command prompt these days. It's 2008, you know. :) I would really like to see the Configuration Editor turn into a full-scale application, complete with Redo/Undo and the like. The interface needs to go through a information architect and user experience expert and make this a Real Deal application. Configuration is King with application development and honestly, I didn't get the big "aha" moment with EntLib until I saw how you could create design components for your application block and run them through the Configuration Design console.
Ok, off my soapbox for now...
More Posts