C
C#9mo ago
Ploxi

❔ How to Package Multiple Versions of a Library Targeting Different Dependency Versions into a Nuget

I am working on a C# library (mylib) which has a dependency on another library (thatlib). Now, the problem is, that thatlib has breaking changes between versions 1.0 and 2.0, and I need to support both versions of thatlib in my library. I need to create two different versions of mylib, each targeting different versions of thatlib, and package them into a single NuGet package. Here are the version ranges I am targeting: 1. mylib_v1 targeting thatlib versions [1.0,2.0) 2. mylib_v2 targeting thatlib versions [2.0,5.0) I want to achieve this ideally using a single .csproj file without creating separate projects for each version. My goal is to ensure that consumers of my library get the correct version of mylib based on the version of thatlib they are using.
98 Replies
JakenVeina
JakenVeina9mo ago
you wouldn't bundle them together in the same package you would release two different versions of your package
Ploxi
Ploxi9mo ago
But thats also far from ideal. What if i want to release an update for my package?
JakenVeina
JakenVeina9mo ago
then you update it? the nuspec format simply doesn't support specifying multiple versions of the same dependency
Ploxi
Ploxi9mo ago
My initial idea was to follow the versioning of thatlib, but that would prevent me from following my own schedule/needs for updates Thats what ive guessed
JakenVeina
JakenVeina9mo ago
so, like the breaking changes in thatlib they affect YOU, or you're worried about them affecting your consumers?
Ploxi
Ploxi9mo ago
Its just that
No description
JakenVeina
JakenVeina9mo ago
oof, they actually DROPPED the overload?
Ploxi
Ploxi9mo ago
"customers" well i want my lib to be available to as much ppl as possible WELL its complicated i actually hacked the lib the class is internal
JakenVeina
JakenVeina9mo ago
F
Ploxi
Ploxi9mo ago
I MEAN I could just use the 47 version and if it does not work, i could use reflection as a fallback
JakenVeina
JakenVeina9mo ago
that's possible
Ploxi
Ploxi9mo ago
but its SLOWWWWW i mean "slow"
JakenVeina
JakenVeina9mo ago
you'd only have to do it once one initial reflection to lookup the delegate, then you cache that and reuse it
Ploxi
Ploxi9mo ago
well yes but its complicated...again xDD
JakenVeina
JakenVeina9mo ago
anyway, to me, this seems like.... not that big of a deal
Ploxi
Ploxi9mo ago
its way more complex than u think
JakenVeina
JakenVeina9mo ago
it's fairly normal for a library publisher to update their own dependencies
Ploxi
Ploxi9mo ago
the purpose of my lib is that the complete runtime only lives for under a sec
JakenVeina
JakenVeina9mo ago
and consumers are required to update them as well, to be able to update your lib
Ploxi
Ploxi9mo ago
tab completion for spectre console to be exact
JakenVeina
JakenVeina9mo ago
okay so you're like a plugin?
Ploxi
Ploxi9mo ago
yes
JakenVeina
JakenVeina9mo ago
gotcha
Ploxi
Ploxi9mo ago
like a super illegal hack plugin which uses internals
JakenVeina
JakenVeina9mo ago
illegal?
Ploxi
Ploxi9mo ago
"illegal"
JakenVeina
JakenVeina9mo ago
well
Ploxi
Ploxi9mo ago
accessing internals = "illegal"
JakenVeina
JakenVeina9mo ago
like, are you breaking their ToS in some way?
Ploxi
Ploxi9mo ago
nonono
JakenVeina
JakenVeina9mo ago
okay, okay
Ploxi
Ploxi9mo ago
nothing like that
JakenVeina
JakenVeina9mo ago
so
Ploxi
Ploxi9mo ago
its just not nice 😄
JakenVeina
JakenVeina9mo ago
what you said earlier is basically the way to go track THEIR version numbers if they release 1.0, you have your plugin that is 1.0 (or whatever)
Ploxi
Ploxi9mo ago
yea but what if i want to extend my library...i cant just go out of sync
JakenVeina
JakenVeina9mo ago
if you add new features, you increment, 1.0.1, 1.1.0, etc. if they update to 2.0, you do the same and what you CAN possibly do if you want to add new features, you can maintain two streams if you have something new to add, you release 2.0.1, and 1.0.2 or whatever
Ploxi
Ploxi9mo ago
Its actually funny, they dont leave space for my numbers
No description
JakenVeina
JakenVeina9mo ago
a little documentation on the NuGet page should clarify "if you're using Spectre X, you use the latest subversion of Y" etc.
Ploxi
Ploxi9mo ago
i mean i could do -preview.26.[MYNUMBER]
JakenVeina
JakenVeina9mo ago
huh?
Ploxi
Ploxi9mo ago
i mean how would i publish an update a version of my library which is already on 0.47.1-preview.0.26
JakenVeina
JakenVeina9mo ago
you aren't limited to only pushing versions newer than what you've done already you can push 2.0.1 and then turn around and push 1.0.1 I'm pretty sure the version number is just a field in the nuspec
Ploxi
Ploxi9mo ago
i thought i would follow their versioning scheme
Ploxi
Ploxi9mo ago
What i meant with "illegal", i cant use the class here
No description
Ploxi
Ploxi9mo ago
But its ok there
No description
JakenVeina
JakenVeina9mo ago
right
Ploxi
Ploxi9mo ago
https://github.com/aelij/IgnoresAccessChecksToGenerator If ure interested, found it a couble of days ago
GitHub
GitHub - aelij/IgnoresAccessChecksToGenerator: Generates reference ...
Generates reference assemblies where all the internal types & members become public, and applies the IgnoresAccessChecksTo attribute - GitHub - aelij/IgnoresAccessChecksToGenerator: Generat...
Ploxi
Ploxi9mo ago
still kinda hyped 😄
JakenVeina
JakenVeina9mo ago
yes, that's a fairly common trick
Ploxi
Ploxi9mo ago
Like u know how it works? I have to admit, i dont quite i have an idea but im not sure
JakenVeina
JakenVeina9mo ago
you patch the target dependency, develop against that, and the swap it out, yeah?
Ploxi
Ploxi9mo ago
I think it mocks it at dev time but apart from that, thats what my impression is yea
JakenVeina
JakenVeina9mo ago
yeah
Ploxi
Ploxi9mo ago
Dirty, dirty trick 😄
Aaron
Aaron9mo ago
yeah, i would never do this in a library just use reflection it is not worth building multiple versions to do otherwise
Ploxi
Ploxi9mo ago
Tried, was too much work. I might be using reflection to activate that class tho
Aaron
Aaron9mo ago
swaps the DLL you reference for one where everything is public then adds a (completely unsupported!) attribute that the runtime recognizes to allow you to access private/internal things from that assembly at runtime
JakenVeina
JakenVeina9mo ago
reflection wouldn't be any better, except that you can maybe detect if some APIs don't exist, and fall back to different ones either way, if you're using internals, you're breaking when the target makes minor updates
Aaron
Aaron9mo ago
reflection is better because its actually something supported by the runtime kekw can be removed at any time it was added silently and can be taken away in the same way
Ploxi
Ploxi9mo ago
So the runtime would actually care?
JakenVeina
JakenVeina9mo ago
care about what?
Aaron
Aaron9mo ago
if they stopped recognizing the attribute, yes accessing the internals of other assemblies
JakenVeina
JakenVeina9mo ago
it's not the runtime that recognizes it, it's Roslyn
Aaron
Aaron9mo ago
no, its not roslyn does not recognize IgnoreAccessChecksTo in fact they have refused to do so
JakenVeina
JakenVeina9mo ago
then how does code compile when you're using internal members?
Aaron
Aaron9mo ago
the generator swaps the assembly for one with everything public then it has roslyn reference that
JakenVeina
JakenVeina9mo ago
hmm, okay I thought the generator just attached InternalsVisibleTo to the assembly so InternalsVisibleTo actually has nothing to do with any of this
Aaron
Aaron9mo ago
yeah
JakenVeina
JakenVeina9mo ago
so, what was your point about the runtime?
Aaron
Aaron9mo ago
IgnoreAccessChecksTo can stop existing at any moment
JakenVeina
JakenVeina9mo ago
so what?
Aaron
Aaron9mo ago
if it does, the runtime will just throw when you access internal things
JakenVeina
JakenVeina9mo ago
it doesn't do anything here
Aaron
Aaron9mo ago
yes, it does
JakenVeina
JakenVeina9mo ago
how?
Aaron
Aaron9mo ago
roslyn isnt the only thing that checks accessibility the runtime does too
JakenVeina
JakenVeina9mo ago
so what?
Aaron
Aaron9mo ago
the public assembly is not kept for runtime its still private at runtime
JakenVeina
JakenVeina9mo ago
and doesn't have InternalsVisibleTo on it
Aaron
Aaron9mo ago
yes
JakenVeina
JakenVeina9mo ago
how is it relevant?
Aaron
Aaron9mo ago
okay IgnoreAccessChecksToAttribute replaces InternalsVisibleTo
JakenVeina
JakenVeina9mo ago
oh, right
Aaron
Aaron9mo ago
its a secret sibling attribute
JakenVeina
JakenVeina9mo ago
did I screw that up?
Ploxi
Ploxi9mo ago
*crazy secret sibling
Aaron
Aaron9mo ago
if the runtime stops supporting it, it will now realize you have no permission to access the things are are accessing
Ploxi
Ploxi9mo ago
Lets hope that never happens kekw
Aaron
Aaron9mo ago
god github search sucks
Aaron
Aaron9mo ago
GitHub
Compiler support for IgnoresAccessChecksToAttribute by aelij · Pull...
The IgnoresAccessChecksToAttribute is the reverse of the InternalsVisibleToAttribute - it allows an assembly to declare assemblies whose internals would be visible to it. The attribute class isn&#3...
Ploxi
Ploxi9mo ago
@just eepy I managed to do this hack without IgnoresAccessChecksToAttribute i am simply able to abuse the InternalsVisibleTo attribute
No description
No description
Ploxi
Ploxi9mo ago
*CommandModel is internal
Aaron
Aaron9mo ago
yeah but that means modifying the runtime version of the DLL you're referencing which isn't always an option
Ploxi
Ploxi9mo ago
What does that mean? I created a library that has that exact name
Aaron
Aaron9mo ago
ah I see what you mean now yeah that works, as long as they don't change that
Ploxi
Ploxi9mo ago
they won't otherwise i would just not release an update for that version my plan would be to add this lib to the nuget ... do you have a better idea? can i host multiple assemblies in a dll? ik ILMerge but does the merged library have the advantages of the InternalsVisibleTo attribute?
Accord
Accord9mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.