Strong-naming assemblies and OpenWrap

One of the design principles of OpenWrap is not only to be a glorified Add Reference dialog, but to provide a better way of dealing with dependencies, both at compile-time and at run-time.

When it comes to assemblies, it means we need to be able to choose which assembly you get when you run code. This allows for swapping assemblies based on the version of .net you’re running on, or what platform (x86, x64, unix, osx, etc).

The problem is, on .net, if you strong-name your assemblies, .net will assume that you really meant that one and only that one assembly you compiled against. This prevents us from swapping assemblies as needed based on your environment.

At the time those decisions was made, the unit of deployment was indeed the assembly, and the reasoning was to try and solve the dll-hell that has existed for a long time on windows. At that time, it was probably an acceptable idea, just like at some point in my career I thought webforms were a good idea.

When you switch to a package-based world, the decisions made by .net are getting in the way. If you try to load MyAssembly.dll version 2, and you compiled against version 1, the code will just never, ever be loaded.

Assembly redirection

One way to solve this problem is assembly redirections. You update a .config file for your application, and you redirect version 1 to version 2. If you’re owning the config file and the application, and are only interested in build-time resolution, as is the case with the Visual Studio NuGet tooling, then that’s fine. We could even add it to OpenWrap in an hour or two and be happy with it.

Does that work for my plug-in for a WPF composite application? Does that work for replacing the version of a package used by my web server in serving html pages in my hosted environment?

The short answer is no. The long answer is that we really think that signing assemblies when using a package manager takes away the decisions from the package manager and prevents a good user experience.

That is why, in OpenWrap, we warn you against signing your assemblies when you create a package. If you don’t sign things, everything is easier, as we can make the right decisions the CLR fusion loader cannot make itself by design.

The path forward

We do understand that some customers have corporate policies enforcing that all assemblies should be signed. We also do know that some assemblies out there, for which there is no package, are already strongly-named.

So what is the path forward for OpenWrap? It’s going to depend very much on feedback from developers.

If you want type redirection to be automatically generated for your .config file, at build-time, we’ll add that. It’ll be full of big yellow letters warning you you’re probably not doing the right thing, but it could be there if you need it.

Another thing you can do right now is publish one package with unsigned assemblies, called MyProject.wrap, and another one called MyProject-signed.wrap. Whenever one of your customers want the signed version, they can simply do a dependency override, by specifying “override: MyProject MyProject-signed” in your descriptor. Any package you reference that references MyProject will now get the signed version. This is available now and has been available for months.

Finally, post v1, we will have an extra, more involved approach to it, that will be optional and one that David Ebbo has mentioned in his recent blog posts. You’ll be able to specify in your descriptor that you want everything resigned, and whenever a new assembly is found in a new package, OpenWrap will re-sign the assembly with a key you provide. The process will not touch any existing signed assembly, but will go and re-sign all the assemblies you need with your own key. We will also provide an –unsign flag to the build command to strip-off any existing strong-naming from assemblies when you create a package.

Conclusion

OpenWrap is an open, community-driven OSS projects with a great track record of offering the best technology, and being completely open to other solutions so that you never get locked in, either by an IDE vendor or in an out-dated technical environment. We understand the problems you’re facing in your organization, we have the same ones and that’s why we build this thing, out of need.

If you think we’re heading in the wrong direction, or if you want to cheer us a bit, as usual please come and talk to us on the mailing list, or comment on this blog post. We are by and for the community, always have been. We really want to continue being the most pain-free and most productive dependency management system on .net.

Ads

NuGet feed has changed again, and broken OpenWrap again.

Just a quick note that the NuGet feed has had some more changes that have broken OpenWrap once more. As usual, this wasn’t quite documented anywhere nor did we get told about it in time for their release.

We are waiting on Microsoft to clarify what the changes are, to make sure we don’t implement it wrong. It’s very important, as while OpenWrap supports dependency levelling, NuGet doesn’t, and differences in behaviour between the two managers have to be levelled out somehow.

In the meantime, a new version of OpenWrap is available that should continue functioning with the yet again new format.

The URI to add to your remotes is now nuget://feed.nuget.org/rtm/odata/v1/Packages

We are sorry that we cannot provide guarantees to how long integration with NuGet will stay up-and-running, but as the effort is all on our side, it’s a game of cat and mouse. On the bright side, we still support all the other previous formats NuGet ever had, so by using OpenWrap today you won’t be broken by the multiple incompatibilities introduced by NuGet.

Note that the NuSpec functionality has changed again too, and we don’t support it yet, moving from a simple min/max to the more complex and unreadable maven format. We’ll be adding those back in the conversion process soon.

Ads

Why choosing your own path for packages is asking the wrong question

I’ve had a couple of people asking me if we could change where packages get stored from the /wrap folder to their own folder. I’m not the only one with that feature request, the NuGet guys have had that question asked and even partially implemented a feature for it. I think responding to those requests is not the right thing to do, and this post is to explain why.

When the question “can I change where packages go”, usually the underlying, real question, is one of two: “I want them in /lib with the rest of my traditional libraries”, or “In my corporate environment I don’t want to check-in all the dependencies because I don’t care about xcopy deployment”.

Managing local packages

The first question usually is due to the desire developers have to keep all their dependencies in the same location. While I can understand the psychological reasons behind such a request, the reality of how a package manager usually work is quite incompatible with this approach.

Take the typical example of a command you could issue in OpenWrap: o update-wrap nhibernate-core -clean. This command asks OpenWrap to update a dependency and remove any old dependencies that were present.

To do so, OpenWrap needs a certain level of guarantees that you don’t mess with the structure it relies on to locate packages. Imagine for a second that you copied your usual nunit dlls in /lib/nunit-2.6.0, and also had a package you depend on in one of your packages that happen to be the nunit package.

At that stage, you now have no way to differentiate between the two, the lib you own and the package that, for all intent and purposes, is owned by the package manager.

Allowing you to keep two different beasts, library dependencies you own and packages you depend on and that are owned by your package manager, would introduce a very large amount of complexity, not only for OpenWrap but also for you: it becomes very difficult for everybody to differentiate between an immutable package and a mutable dependency you pulled yourself.

For that reason, while I certainly understand why it doesn’t feel “neat”, keeping packages separate from libraries let everybody know what each of the beasts are, without introducing complexity.

There’s also a secondary scenario to take into account. While we, as the OpenWrap team, don’t see any reason why you would want to run both NuGet and OpenWrap at the same time, we do recognize that it’s a probability that some people will end-up with both solutions running side-by-side in the same projects, and we certainly make sure that this scenario is functional.

As NuGet stores stuff in /packages and we store stuff in /wrap, everything is fine, neither package managers will get confused. If however you were to redirect either systems to the other repository, you’d end up with what I can only define as undefined and probably clusterfucky behaviour, and that’s not something either team would want you to end up in.

Keeping the packages out of source control

Now this scenario I can understand a bit more. A lot of corporate environments, due to the heavy tax they make developers pay by having managed desktops, do have very defined and reliable environments, quite a different thing than what open-source projects and smaller companies can afford to have.

If you do have such an environment, systematically copying new versions of updated packages in your source control increases the size of the repository, while you could potentially live happily without all those binaries.

There is a fundamental issue with this scenario, and one that neither NuGet nor OpenWrap have a solution for at this time: Whenever you don’t include the exact version of a dependency you expect, and rely on a central repository to pull those as needed, you may end up with a different version from the developer sitting next to you.

Let’s say I originally added a dependency by doing o add-wrap nhibernate.core. I shall get whatever version was the latest one at the time I started coding.

A week pass, and nhibernate 3.0 gets released, and breaks your application. The reason is simple, while I still happily run on 2.0, you have the 3.0 package.

Now there are a couple of ways we can enable this. The first one is to restrict you to absolute version definitions in the packages you take dependencies on. While this is the quickest way to get to that point (and the one the NuGet package repository very much has implemented so far), it restricts not only your dependencies at development time when you pull a package you want work on, it also restricts the runtime binding that a system like OpenWrap also takes care of.

The other solution, and the one we’ll implement in OpenWrap (depending on feedback, the more users want it, the higher the priority), is in the case where you use the use-project-repository: false instruction in a project (a hidden feature in OpenWrap that won’t be part of the documentation until we’ve covered cases such as those). When you do that, as well as storing the packages in your development package folder (the wraps/_cache folder), we’ll also keep a list of absolute versions that you were using. Whenever a resolve or update happens, we’ll only rely on that exact list to update your repository.

With this system, you’ll be able to only check-in the openwrap dlls, and let the system auto-download and install all the missing dependencies based on the versions that other developers are also using.

There are a couple of issues with this system to ensure that all packages openwrap depends on are also checked-in in your source control, but those are not a big deal, just one of many features we have planned.

Getting those features in

The OpenWrap team is very committed to features that make life easier for developers that wish to be productive with their dependency management needs.

If you want to see those things happen sooner, why not join us on the mailing list to talk about those features, fork our repository on github and contribute those features? We’re a cool bunch and we’ll provide you with as much help as you need to implement those. And if you don’t have the time, a little message on the mailing list would go a long way to make sure we cover the scenarios you need when we plan for those features.

Ads