DNN Community Blog

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


DNN 9.2.0. and Sharpziplib breaking change

 

dodontIn DNN 9.2.0 Sharpziplib is updated to 0.86.0.518. 


This is the most common library used for zip and unzip files in dotnet for years.

This generate a breaking change for all modules witch use Sharpziplib because the assembly name of Sharpziplib change.

In reality most of the apis of Sharpziplib are backward compatible. But because the assembly name change, the module developer need to recreate a module package that reference the new assembly. And because the new SharpZipLib assembly is not present in older DNN versions, the new generated module package is not compatible with older DNN versions.

How module developers can resolve this issue :

1) create a new distribution package specific for dnn version greater then 9.2 

pro : clean project references
cons : maintain 2 VS projects and 2 dnn distribution packages

2)  switch to dotnet 4.5 compression api and force people to use dotnet 4.5 for all dnn version

pro : remove dependecy to SharpZipLib (3th party lib)
cons : new versions of your module, can't run on older dotnet versions and need some code rewrite 

3) create wrapper dnn library around sharpzip that runs on all dnn versions (using reflection)

pro : no impact for end users of your module
cons : no dependency management, no compile time errors

In the 2 opensource modules i manage OpenContent and OpenForm i chose option 3 to impact less as possible the users of the modules, first of all myself :)  

So i will here share the wrapper class i create to solve this issue. It's contains basic apis for zip and unzip.
Once using this wrapper class, you can remove all dependencies to sharpziplib in your project.
It will automatically pickup the right assembly.

https://gist.github.com/sachatrauwaen/6900943e507ec1a3c556121d79bbd04f

Hope this help other dnn module developers.

Comments

Mitchel Sellers
Thanks for this submission! Great way to lay out all of the options. My personal preference is strongly towards Option 2, but you make a valid case for Option 3.
Mitchel Sellers Wednesday, April 4, 2018 1:25 AM (link)
Daniel Mettler
Thanks Sacha!

I also have another option: include the sharpziplib in your distribution. This allows you to code to the newer version, and it's included in old DNNs where it would be missing.
Daniel Mettler Wednesday, April 4, 2018 6:29 AM (link)
Sacha Trauwaen
@Mitchel, Option 2 is surrelly a good long term solution, because it remove a 3th party dependecy. And we know some other exemples where after some years 3th party libraries becames a pain.

@Daniel, yes this is an otter option, but a dont really know how to implement. And i try always avoid to distribute 3th party libraries with modules, because this cause some times clashes with other modules that distribute other versions of the same library.
Sacha Trauwaen Wednesday, April 4, 2018 7:07 AM (link)
Daniel Mettler
Temporary update: my solution with including the DLL does seem to cause side-effects. The DNN Extensions page in DNN 7.4.2 seems to malfunction if it finds both DLLs; apparently it does some kind of scanning of the DLLs and runs into trouble. So I believe your solution works best.
Daniel Mettler Friday, April 6, 2018 6:25 AM (link)
Daniel Mettler
I think I found an even better solution - there is a code-way to provide assembly redirects. Heres' the code:

namespace ToSic.SexyContent.Dnn920
{
public class SharpZipLibRedirect
{

public static bool AlreadyRun { get; private set; }

public static void RegisterSharpZipLibRedirect()
{
if (AlreadyRun) return;
// stop any further attempts to access this
AlreadyRun = true;

try
{
ResolveRenamedSharpZipLib("SharpZipLib", "ICSharpCode.SharpZipLib");
}
catch
{
/* ignore */
}
}


// Note: got the original of code from this blog: https://blog.slaks.net/2013-12-25/redirecting-assembly-loads-at-runtime/
// and the updated version https://gist.github.com/markvincze/10148fbeb41a57c841c7

///Adds an AssemblyResolve handler to redirect all attempts to load a specific assembly name to the specified version.
private static void ResolveRenamedSharpZipLib(string oldName, string newName)
{
Assembly Handler(object sender, ResolveEventArgs args)
{
// only check for access to old SharpZipLib
if (!args.Name.StartsWith(oldName))
return null;

// If the original was not found, it should find the new one - otherwise it will be null
var alreadyLoadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == newName);
return alreadyLoadedAssembly;
}

AppDomain.CurrentDomain.AssemblyResolve += Handler;
}
}
}
Daniel Mettler Friday, April 6, 2018 1:03 PM (link)
Mitchel Sellers
Daniel

Although that works, I would strongly, strongly recommend NOT doing this as something that is done in a third-party module. There are situations where that could get very ugly

1.) What happens if you have multiple modules that do the same thing? It might not "break" anything but it is going to add complexity to the assembly loading process

2.) What happens to other assemblies that might be needing to use the other library. This kind of hook is going to change the used assembly for any module requesting it.

Mitchel Sellers Friday, April 6, 2018 3:00 PM (link)
Daniel Mettler
@Mitchel - I checked all that. This code is only run by the DLL-resolver if it doesn't find an assembly. So if the assembly exists, the code is never used. So even if multiple modules did this, or included other copies, it would still work.

a) it's only used if the DLL doesn't exists
b) first one to provide a resolution gives the DLL, others won't
c) once resolved, the code is never run again
d) only weakly resolved DLLs are even handled - anything in the GAC is completely ignored

So from my tests, this looks very reliable. I would even suggest to put this in DNN. Any concerns?
Daniel Mettler Friday, April 6, 2018 3:19 PM (link)
Mitchel Sellers
@Daniel - Looking at the API docs you are correct that it only fires once, which is good. I think a solution at the DNN Platform level, rather than a module would be more acceptable.

The biggest concern here is that if a person is trying to diagnose a situation with an install, module, or otherwise, this kind of assembly redirect is not going to be captured, or logged in an easy to find manner. If you turn on a bunch of .NET logging you might capture it, but often times you cannot do this in production.

My fundamental $0.02 here I guess is simply "if you could impact anyone else, it shouldn't be part of a module" rule applies. And as such, would only want this at the platform level, if at all.
Mitchel Sellers Friday, April 6, 2018 3:27 PM (link)

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (18)
Alec Whittington (11)
Alex Shirley (10)
Andrew Hoefling (2)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (35)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (212)
Chris Paterra (55)
Clinton Patterson (71)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (165)
Daniel Valadas (1)
Dave Buckner (2)
David Poindexter (9)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (77)
Francisco Perez Andres (6)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (3)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matthias Schlomann (15)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (31)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott S (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (2)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (169)
William Severance (5)

Content Layout

Subscribe to DNN Digest

Subscribe to DNN Digest

DNN Digest is our monthly email newsletter. It highlights news and content from around the DNN ecosystem, such as new modules and themes, messages from leadership, blog posts and notable tweets. Keep your finger on the pulse of the ecosystem by subscribing.  

What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out