-
Versioning in .NET
I have a real question about .NET versioning. It's going to be a rather
long question since I don't master the gift of brevity.
All I hear is that DLL **** is gone now. I can see how it is gone : all
local components are now no longer register on a per-machine base but are
rather found in the local directory of the application (and not registered
at all). Each application ships its own version of the components and no
application can compromise another application (unless they intentionally
want to do so). For "global" components there is always the Global Assembly
Cache (GAC) which allows multiple versions of global components to coexist.
I can see that this works fine for the majority of applications.
So far so good. The architecture of our current VB6 application is
"plug-in-based". Our main application is kind of "dumb". The purpose of
MainApplication is to host a bunch of "plug-ins" (much like windows explorer
and shell extensions) There are +40 possible Plugins. Both the Plugins and
MainApplication are built on top of a SharedToolbox. SharedToolbox contains
classes and state (singletons) shared between MainApplication and Plugin.
COM (and especially VB6) makes upgrading a PeaceOfCake (OK, if you know what
you're doing). I can upgrade any component in my architecture and be sure
that everything still works as planned.
P.E. : upgrading SharedToolbox from version 1 to version 2 will not have any
influence at all on the existing MainApplication and Plugin that where
previously using Version1. They will start using Version2 without
questions.
P.E.2 : upgrading MainApplication from version 1 to version 2 will not be
allowed if the preconditions are not met. If MainApplicationVersion2 needs
SharedToolboxVersion3 (because it was compiled with that version) and the
current installation has SharedToolboxVersion1, then the setup will simply
fail.
After an upgrade old and new components work together. VB6 binary
compatibility (although probably not perfect either) is the stick behind the
door to keep me from doing stupid things.
<SideBar> The SharedToolbox actually consists of 8 components. There are 40
plugins and a MainApplication. If each component is allowed to use its own
private version of another component, the worst case (without counting
dependencies between the components in SharedToolbox) would be (40 +1) X 8 =
328 components loaded in memory (whether they are actually loaded or not is
quite irrelevant here). To make things worse, my singletons in
SharedToolbox will "live" for each version of it there is alive in my
application. A singleton with 41 instances is barely a singleton. This is
my own perception of the problem <\SideBar>
Now for the questions :
1) How would I simulate the behavior of my current APP in .NET ? (If and
when I switch to .NET it will have to be a pure .NET application. Maybe
some temporary Interop support but after the Big Bang, no more ActiveX.
(I'm not switching to a tool which has - for my purposes - a more difficult
approach to activeX). Would all of my components go into the GAC ? )
2) If I change a component, how will .NET guarantee me that it will still
work with old clients (like binary compatibility does in VB6) ?
--
For a work in progress :
http://users.skynet.be/wvdd2/
-
Re: Versioning in .NET
I'll take a stab at this:
If your app is based around a plug-in architecture, I would assume that the
app and the plug-ins communicate through one or more defined interfaces.
All it takes, then, is creating formal interface definitions and placing
them in a separate assembly, which you rarely - if ever - touch. This will
ensure compatibility across versions.
BTW, this is exactly the same architecture I'd have used in VB 6.0, only
then I would probably have created an external type library with IDL to
define the interfaces.
--
Rune Bivrin
- OOP since 1989
- SQL Server since 1990
- VB since 1991
-
Re: Versioning in .NET
Rune Bivrin <rune@bivrin.com> wrote:
>I'll take a stab at this:
>
>If your app is based around a plug-in architecture, I would assume that
the
>app and the plug-ins communicate through one or more defined interfaces.
>All it takes, then, is creating formal interface definitions and placing
>them in a separate assembly, which you rarely - if ever - touch. This will
>ensure compatibility across versions.
I agree that an interface is a solution. However, it's only half of the
story. If the interface is something like
interface iPLugin
public property get Name as string
, i.e. a plugin that uses only primitive types this will work. However,
a plugin needs information from it's "host" be useful. So there will typically
be at least one method in the interface that passes information from the
MainApplication to the Plugin, like in
interface iPLugin2
public sub Initialize (byval objParams as cSomeTypeDefinedInMainApplicationOrMoreLikelyInSharedToolbox)
And it's here the trouble begins. Since the Plugin and the MainApplication
can both be compiled using a different SharedToolbox, there is absolutely
no guarantee that cSomeTypeDefinedInMainApplicationOrMoreLikelyInSharedToolbox
as used by the Main Application is compatible in any way with the cSomeTypeDefinedInMainApplicationOrMoreLikelyInSharedToolbox
as seen by the Plugin.
I can see some solutions to this :
1) all parameters of the plugin interface should be passed as Object and
the plugin has to do the equivalent of "QueryInterface" to see what is passed
in the parameter. I call this "reinventing COM". COM was created to deal
with such problems and VB6 even hide all (most at least) of the gory details
from me. Now I am left to do things manually that where previously done
automatically.
2) Use reflection on the parameters (IMHO the equivalent of late binding).
Allthough VB.NET does a good job at hiding the mechanisms from me, I really
don't want late binding. Certainly not if it worked with early binding in
the existing (VB6) version.
3) Pass generic objects between the boundaries (like XML stuff or DataSets).
Doesn't sound very OO to me.
4) Switch to ActiveX in .NET. This is a possibility but a step backward
since compatibility must be handled manually and since activeX doesn't give
me the promised easy deployment.
5) ...
>
>BTW, this is exactly the same architecture I'd have used in VB 6.0, only
>then I would probably have created an external type library with IDL to
>define the interfaces.
The interface is define in SharedToolbox. All interfaces (iSomething) are
threated as immutable (I confess VB6 doesn't help me to keep them immutable).
In really like VB6's help on upgrading.
Anyway, having different versions of components around doesn't really solve
the problem with singletons. Each version will have it's own copy of the
singleton and in general singletons behave badly in these cases.
>
>--
>Rune Bivrin
> - OOP since 1989
> - SQL Server since 1990
> - VB since 1991
>
Thanks for the reply,
Van den Driessche Willy
-
Re: Versioning in .NET
"willy Van den Driessche" <willy.van.den.driessche@skynet.be> wrote in
news:3db009df$1@tnews.web.devx.com:
> The interface is define in SharedToolbox. All interfaces (iSomething)
> are threated as immutable (I confess VB6 doesn't help me to keep them
> immutable).
> In really like VB6's help on upgrading.
>
> Anyway, having different versions of components around doesn't really
> solve the problem with singletons. Each version will have it's own
> copy of the singleton and in general singletons behave badly in these
> cases.
>
> Thanks for the reply,
> Van den Driessche Willy
>
>
>
You have to keep all interface definitions outside of the operative
components, and you have to define interfaces for every interaction,
including callbacks. Do note that it's possible in .NET to include events
in interface definitions (I haven't tried it, but it's supposed to work).
As far as the singletons, it's hard to be specific without knowing what
they do, and why they have to be singletons. Anyway, I'd let the app
create instances of those components that need to be shared, and then
maybe put those in a SingletonManager, which could be passed around to
the plugins. Generally speaking, singletons are a pain in the nether
regions, but if needed, you're better off managing the singleton-ness of
them yourself.
Anyway, the answer lies in interfaces! I think... Right now...
--
Rune Bivrin
- OOP since 1989
- SQL Server since 1990
- VB since 1991
-
Re: Versioning in .NET
"Rune Bivrin" <rune@bivrin.com> schreef in bericht
news:Xns92ABA6F2DAA8Drunebivrincom@209.1.14.29...
> "willy Van den Driessche" <willy.van.den.driessche@skynet.be> wrote in
> news:3db009df$1@tnews.web.devx.com:
>
> > The interface is define in SharedToolbox. All interfaces (iSomething)
> > are threated as immutable (I confess VB6 doesn't help me to keep them
> > immutable).
> > In really like VB6's help on upgrading.
> >
> > Anyway, having different versions of components around doesn't really
> > solve the problem with singletons. Each version will have it's own
> > copy of the singleton and in general singletons behave badly in these
> > cases.
> >
> > Thanks for the reply,
> > Van den Driessche Willy
> >
> >
> >
> You have to keep all interface definitions outside of the operative
> components, and you have to define interfaces for every interaction,
> including callbacks.
I can see what you're getting at. You want me to define a "typelib"
assembly. I can see that this will work but it's a lot of work for
something VB6 does for me automatically. All VB6 objects are approached via
interfaces automatically. I'll elaborate below...
> Do note that it's possible in .NET to include events
> in interface definitions (I haven't tried it, but it's supposed to work).
I know that. I've tried it and it works. Together with inheritance between
interface I consider those to be A Good Thing.
>
> As far as the singletons, it's hard to be specific without knowing what
> they do, and why they have to be singletons. Anyway, I'd let the app
> create instances of those components that need to be shared, and then
> maybe put those in a SingletonManager, which could be passed around to
> the plugins. Generally speaking, singletons are a pain in the nether
> regions, but if needed, you're better off managing the singleton-ness of
> them yourself.
My current application has singletons for a lot of stuff. A logContext is
one of them, a Translator (for multiligual screens ...). I Know .NET has
it's own implementations of this but that's not really the point. They
suffer the same problems as my own implementation. I will try to argument
some more here :
From the moment you have a componentized application, chances are you have a
dependency graph between them that contains multiple possible paths from a
client component to a server (not in a remote sense) component.
With side-by-side execution inside the same app, you cān get different
versions of that same server component inside the same app. Singletons
point to a problem when the server component contains state. However, the
different versions of the types inside the server component are
type-incompatible (.NET includes the strong name for type checking). This
is a worse problem. You can get around all this by creating "immutable"
assemblies that defie the interfaces and expose all types via these
interfaces. I call this "implementing COM in .NET". It will work, but VB6
does a far better job at this. So my response is : side-by-side versions
inside one app doesn't make sense in this way.
So one could say : ok, I don't want multiple versions of the same assembly
inside my app. I just take the latest one. This cān also work but there is
another problem. There is no guarentee the new version is compatible with
the previous version. .NET doesn't come with tools to check compatibility
(like VB6 does).
So either way, I'm stuck. I remain optmistic into thinking there must be an
(easy) way out but up to today I haven't found one. You have to know that
our current APP is 500.000 lines of VB code. The deployment has (once we
began to understand stuff) always been easy and we now even have an
"autoupdate" feature. I'm not going to even think about switching it to
..NET unless I have a clear understanding of .NET versioning.
>
> Anyway, the answer lies in interfaces! I think... Right now...
>
>
> --
> Rune Bivrin
> - OOP since 1989
> - SQL Server since 1990
> - VB since 1991
--
For a work in progress :
http://users.skynet.be/wvdd2/
-
Re: Versioning in .NET
"Willy Van den Driessche" <wvddwebcomments@skynet.be> wrote in
news:3db126d7@tnews.web.devx.com:
> type checking). This is a worse problem. You can get around all this
> by creating "immutable" assemblies that defie the interfaces and
> expose all types via these interfaces. I call this "implementing COM
> in .NET". It will work, but VB6 does a far better job at this. So my
> response is : side-by-side versions inside one app doesn't make sense
> in this way.
>
> So one could say : ok, I don't want multiple versions of the same
> assembly inside my app. I just take the latest one. This cān also
> work but there is another problem. There is no guarentee the new
> version is compatible with the previous version. .NET doesn't come
> with tools to check compatibility (like VB6 does).
No, you're absolutely right. Side by side execution within the same app
doesn't make sense. But why would you have that? The app loads whatever
is present, and works with the interfaces.
I agree that the work of defining the required interfaces might seem a
little cumbersome, but once you've done that, you're much more protected
against formal incompatibilities than VB6 could ever achieve. In VB6,
there was always the risk of the "expanding interface", where introducing
a new method in a component would silently create a new interface. You
would then have to be aware of that, and make sure you always were
compatible with a good version.
--
Rune Bivrin
- OOP since 1989
- SQL Server since 1990
- VB since 1991
-
Re: Versioning in .NET
--
For a work in progress :
http://users.skynet.be/wvdd2/
"Rune Bivrin" <rune@bivrin.com> schreef in bericht
news:Xns92AC84D6ED675runebivrincom@209.1.14.29...
> "Willy Van den Driessche" <wvddwebcomments@skynet.be> wrote in
> news:3db126d7@tnews.web.devx.com:
>
> > type checking). This is a worse problem. You can get around all this
> > by creating "immutable" assemblies that defie the interfaces and
> > expose all types via these interfaces. I call this "implementing COM
> > in .NET". It will work, but VB6 does a far better job at this. So my
> > response is : side-by-side versions inside one app doesn't make sense
> > in this way.
> >
> > So one could say : ok, I don't want multiple versions of the same
> > assembly inside my app. I just take the latest one. This cān also
> > work but there is another problem. There is no guarentee the new
> > version is compatible with the previous version. .NET doesn't come
> > with tools to check compatibility (like VB6 does).
>
> No, you're absolutely right. Side by side execution within the same app
> doesn't make sense. But why would you have that? The app loads whatever
> is present, and works with the interfaces.
>
> I agree that the work of defining the required interfaces might seem a
> little cumbersome, but once you've done that, you're much more protected
> against formal incompatibilities than VB6 could ever achieve. In VB6,
> there was always the risk of the "expanding interface", where introducing
> a new method in a component would silently create a new interface. You
> would then have to be aware of that, and make sure you always were
> compatible with a good version.
The expanding interfaces are exactly the feature I like in VB6. When you
"expand" an interface, VB6 will automatically create a new interface behind
your back. VB6 will warn you if make an incompatible change but if you stay
compatible, old clients will still continue to work without recompilation.
As far as deployment is concerned, the rule is quite simple : never install
a component if the correct version of the components it was compiled against
are not installed (I've summarized them in
http://users.skynet.be/wvdd2/Compili...ment_rules.htm
l)
..NET simply does give the kind of automatic support for change -management
that VB6 does. Mind you, I'm not blind for the deployment issues of activeX
components. But these deployment issues could have been solved easily :
just use a hierarchy of registries instead of one registry. Then finding
the right components could become a simple chain : search the app registry
first, then up until you reach the global registry. It would be up to you
if you register your component in your local app "registry" or somewhere
else. Each app would see only one version of any given component.
removing an app would also simply mean deleting the directory since the
local app registry would be deleted as well and no trash would be left.
That would finally allow have multiple versions of one app one one and the
same machine. But I'm dreaming here. Back to .NET
To silence my critique on .NET I would just need a tool that automatically
checks for compatibility between two (sets of) assemblies. I only want a
check for "syntactic" compatibility, since "semantic" compatibility is
something beyond testability. I have done an attempt at
http://users.skynet.be/wvdd2/General...lity/_NET_comp
atibility_checker/_net_compatibility_checker.html but I would really like a
tool from the "makers" or at least a definition of compatibility for .NET
assemblies. I don't like relying on "craftsmanship" for this because humans
do make mistakes. It just strikes me that, while we all agree that the most
constant thing is change, there are no tools to guide us in making
compatible changes...
Thanks for you replies.
Van den Driessche Willy.
-
Re: Versioning in .NET
It would seem I saw somewhere that this check is done for you by the
runtime. When the runtime loads a new version of an assembly it makes sure
that all the classes have the requested members to avoid breaking the user
code (actually the current code i.e. deleting a method would not break if
the method is not used, of course it will break if the client code do use
this method).
Try for example :
http://msdn.microsoft.com/library/de...us/cptutorials
/html/deploying_versioned_components.asp
Patrice
"Willy Van den Driessche" <wvddwebcomments@skynet.be> a écrit dans le
message de news: 3db177c5@tnews.web.devx.com...
>
>
> --
> For a work in progress :
> http://users.skynet.be/wvdd2/
> "Rune Bivrin" <rune@bivrin.com> schreef in bericht
> news:Xns92AC84D6ED675runebivrincom@209.1.14.29...
> > "Willy Van den Driessche" <wvddwebcomments@skynet.be> wrote in
> > news:3db126d7@tnews.web.devx.com:
> >
> > > type checking). This is a worse problem. You can get around all this
> > > by creating "immutable" assemblies that defie the interfaces and
> > > expose all types via these interfaces. I call this "implementing COM
> > > in .NET". It will work, but VB6 does a far better job at this. So my
> > > response is : side-by-side versions inside one app doesn't make sense
> > > in this way.
> > >
> > > So one could say : ok, I don't want multiple versions of the same
> > > assembly inside my app. I just take the latest one. This cān also
> > > work but there is another problem. There is no guarentee the new
> > > version is compatible with the previous version. .NET doesn't come
> > > with tools to check compatibility (like VB6 does).
> >
> > No, you're absolutely right. Side by side execution within the same app
> > doesn't make sense. But why would you have that? The app loads whatever
> > is present, and works with the interfaces.
> >
> > I agree that the work of defining the required interfaces might seem a
> > little cumbersome, but once you've done that, you're much more protected
> > against formal incompatibilities than VB6 could ever achieve. In VB6,
> > there was always the risk of the "expanding interface", where
introducing
> > a new method in a component would silently create a new interface. You
> > would then have to be aware of that, and make sure you always were
> > compatible with a good version.
>
> The expanding interfaces are exactly the feature I like in VB6. When you
> "expand" an interface, VB6 will automatically create a new interface
behind
> your back. VB6 will warn you if make an incompatible change but if you
stay
> compatible, old clients will still continue to work without recompilation.
> As far as deployment is concerned, the rule is quite simple : never
install
> a component if the correct version of the components it was compiled
against
> are not installed (I've summarized them in
>
http://users.skynet.be/wvdd2/Compili...ment_rules.htm
> l)
> .NET simply does give the kind of automatic support for change -management
> that VB6 does. Mind you, I'm not blind for the deployment issues of
activeX
> components. But these deployment issues could have been solved easily :
> just use a hierarchy of registries instead of one registry. Then finding
> the right components could become a simple chain : search the app registry
> first, then up until you reach the global registry. It would be up to you
> if you register your component in your local app "registry" or somewhere
> else. Each app would see only one version of any given component.
> removing an app would also simply mean deleting the directory since the
> local app registry would be deleted as well and no trash would be left.
> That would finally allow have multiple versions of one app one one and the
> same machine. But I'm dreaming here. Back to .NET
>
> To silence my critique on .NET I would just need a tool that automatically
> checks for compatibility between two (sets of) assemblies. I only want a
> check for "syntactic" compatibility, since "semantic" compatibility is
> something beyond testability. I have done an attempt at
>
http://users.skynet.be/wvdd2/General...lity/_NET_comp
> atibility_checker/_net_compatibility_checker.html but I would really like
a
> tool from the "makers" or at least a definition of compatibility for .NET
> assemblies. I don't like relying on "craftsmanship" for this because
humans
> do make mistakes. It just strikes me that, while we all agree that the
most
> constant thing is change, there are no tools to guide us in making
> compatible changes...
>
> Thanks for you replies.
>
> Van den Driessche Willy.
>
>
-
Re: Versioning in .NET
> Try for example :
>
http://msdn.microsoft.com/library/de...us/cptutorials
> /html/deploying_versioned_components.asp
Ok, I'm beginning to see some light here. The URL hints at playing with the
..config file. The example they give is a little contrived (?) though. I
honestly can't see an administrator manually keying in the properties for an
application. At most the administrator will install the app but for our app
the administrators will either don't care or will not exist (since we
deliver a standalone app that is also installed for the butcher around the
corner).
So the "publisher policy file" should be my rescue. In there I can
"redirect" old "clients" to new "servers", which is a large part of what I
want to do. The good thing is that it is possible. The bad thing is that I
have to update this file on every deployment and I have a risk of error
which will be hard to detect. I had a diagonal look at these and they are
.... new to me. I'll have to sweat some more to grasp their full potentials.
> It would seem I saw somewhere that this check is done for you by the
> runtime. When the runtime loads a new version of an assembly it makes sure
> that all the classes have the requested members to avoid breaking the user
> code (actually the current code i.e. deleting a method would not break if
> the method is not used, of course it will break if the client code do use
> this method).
The second problem, however still remains. Even when I can upgrade a
component, I am still left to my own craftsmanship to know whether it is
compatible. I am not convinced the runtime does a full check on the
assembly just after loading it. I'm afraid the error will occur when you
use the first method that is no longer implemented and not before.
(Reflection makes it impossible to check an assembly up-front). I feared so
already but I'm beginning to see that there are actually multiple
"compatibilities" possible between assemblies. It all more or less depends
on how the assembly gets used. As you point out, in some cases a method
that gets thrown away might not hurt. However, I am still convinced that
there is some definable absolute compatibility that holds for all
assemblies. It can be too strict in some cases but then at least you know
what you're doing when you're deliberately breaking it. This particular
compatibility should shout when a public method, interface, class, enum, ...
gets thrown out. (BTW, the same compatibility constraints apply to
webservices and other stuff too)
Thanks to all for the replies. I know where to start.
--
For a work in progress :
http://users.skynet.be/wvdd2/
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Development Centers
-- Android Development Center
-- Cloud Development Project Center
-- HTML5 Development Center
-- Windows Mobile Development Center
|