U4-1324 - log4net assembly Umbraco uses and older custom log4net build that is not strongly typed - now on 2.0.8

Created by Jay Gaynor 14 Dec 2012, 20:22:18 Updated by Shannon Deminick 29 May 2017, 18:13:43

Is duplicated by: U4-5775

Relates to: U4-9180

Relates to: U4-9499

Subtask of: U4-7594

Due to legacy reasons Umbraco has used a custom build of log4net that supported medium trust. Now we don't need to support medium trust and we're actually a few versions behind.

We need to update to the latest log4net but to do that we have to do some manual assembly redirects in code and in config - exactly what we did for NHibernate in Courier

We're on version 1.2.11.0 Latest is 2.0.8 and there's quite a few issues resolved: https://logging.apache.org/log4net/release/release-notes.html

Comments

Shannon Deminick 21 Dec 2012, 02:32:52

We can do this but will need everyone to agree on this proposal. We use a custom MyGet feed for this with our Nuget repository so an alternative might be to just use that instead of the default Nuget one but I'd need to verify with @Seb and @Morten if that will work.

I'm also no sure what repercussions there will be with 2 assemblies with the exact same namespaces and classes in one application, TBH I've never done that. How would you do a 'using' clause in your class to target a specific assembly's code since the namespaces will be exactly the same and even using a global:: won't work since the namespaces and classes are identical. I'm not sure how log4net searches for the [assembly: log4net.Config.XmlConfigurator(Watch = false)] attribute, I'd assume it's by a real type and not a name of some sort since if things like this happen by name then we'd end up in trouble i think.


Sebastiaan Janssen 24 Dec 2012, 13:39:05

The MyGet package that the Umbraco core uses (and you can then use as well) can be found at: http://www.myget.org/feed/umbracocore/package/log4net-mediumtrust This feed is available for any developers to use with the added benefit that their code will also run on medium trust if necessary.

I've looked for the source code of our custom build, but can't find it, any idea Shannon? Due to time constraints, we're not going to spend time currently in the core team to investigate your idea as it sounds like we might run into the issues Shannon mentions. But if we can dig up the source code, you're welcome to test and I'd love to hear back from you.


Mel Lota 14 Mar 2013, 09:57:35

Hi guys, this one caused me no end of grief when I upgraded a site from 4.9.1 to 4.11.5. The site was already using log4net so I had to swap out the standard log4net implementation with the custom one which had a knock on effect with some other projects using the shared lib. Also had to implement filtering in the configuration as the Umbraco output was creating a lot of noise in the logs. Definitely worth having a think about how we could improve this one. Many thanks.

[UPDATE] In the end I had to just get the Umbraco source and recompile against the Nuget version of the log4net assembly like the original poster. I can see this being a problem when I have to upgrade to another version of Umbraco though


Shannon Deminick 15 Mar 2013, 15:29:42

Hi @Mel, can you tell me what the 'knock on effect' was ? Were you getting assembly manifest errors?

unfortunately log4net doesn't support medium trust in .Net 4 so we had to add this line in the assembly info to the log4net source and recompile: [assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1)] This shouldn't change the assembly manifest, I've ran a few tests to double check this. If it is this error or a different one, can you please give details and perhaps a way that we can replicate?

Also regarding the filters, you will indeed have to setup at least the standard filtering that we ship with (since you might have already had a config log4net section), the config file that we ship with contains examples of how to filter further based on type.

This is the only change that


Phil Dye 08 Apr 2014, 13:50:38

Since Medium Trust should no longer be much of an issues, can we just revert to using the standard nuget log4net package now? This issue continues to cause me much grief in many projects


Mel Lota 26 Jun 2014, 10:28:42

Hi Guys, any update on this one? I've just hit this problem again when I came to upgrading another older site from v4 to v6. Is there any reason why Umbraco can't use the standard log4net version in line with nuget?


René Voigt 26 Jun 2014, 10:32:25

I totally agree with Mel, it is quite painful to use Umbraco with other projects and libraries when log4net can't be used with standard Nuget functionality.


Shannon Deminick 27 Jun 2014, 04:16:41

We'd like to and since we don't need med trust anymore we can use the normal log4net assembly. BUT, changing it now would mean a breaking change so it will have to wait until v8.


Shannon Deminick 27 Jun 2014, 04:17:58

Might be worth investigating now but AFAIK if we change it in 7.x and people drop the dll into their bin without rebuilding they will get manifest assembly matching errors - pretty sure that will be the case and if so we'll need to wait till v8.


Sebastiaan Janssen 27 Jun 2014, 07:09:32

Yeah I tried that the other day and it does require a recompile.


Ryan Dansie 25 Jul 2014, 14:54:27

If the custom log4net assembly was strongly named, it would be possible to reference it and another version in the same project with some web.config configuration. See the first answer here: http://stackoverflow.com/questions/3158928/referencing-2-differents-versions-of-log4net-in-the-same-solution


Ryan Dansie 25 Jul 2014, 15:44:12

Even better. Its already possible to work with multiple versions. Just put the umbraco version of log4net in the bin folder and the other version in a different folder, and then add this to your web.config.

  <dependentAssembly>
    <assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" />
    <codeBase version="1.2.11.0" href="assemblies\l4n3\log4net.dll" />
  </dependentAssembly>

Just make sure the version and public key token are correct for the version of the assembly you are trying to use, and the href is pointing at the dll location. This command can be used to find out your dll's publik key token.

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin>sn.exe -T "\log4net.dll"


Shannon Deminick 25 Jul 2014, 16:50:57

That's super awesome :) The problem with us signing the assembly is that as soon as you do that it changes the assembly manifest (similar to changing a major version) and then people will get assembly manifest errors and would need to recompile their solutions, worse off, it would break all packages that have been built with the previous non-signed version. This is why we have to wait for v8 since no matter what we do it will be a breaking change.

I didn't know you could do what you mentioned above with the codeBase stuff, hopefully that might solve peoples issues in the interim.


andrew shearer 10 Nov 2014, 22:57:24

hi - any update on this issue? Is it likely to be resolved for umb6? thanks


Shannon Deminick 11 Nov 2014, 04:06:32

umb6 ?

It will be fixed in version 8 since it is a breaking change for all packages since they might need to recompile with the correct version, especially if that version uses strong names


Julien De Groote 17 Dec 2014, 08:50:13

I just ran into the same issue. We are using an signed log4net 1.2.10. We provide a few custom IAppender implementations. When log4net 1.2.11 provided by Umbraco loads the config, it complains that it cannot cast our IAppender impls to IAppender because their are effectivement different types for the runtime (different fully qualified type names).

One way to solve the issue without introducing breaking changes would be to let the client application inject its logging implementaion into Umbraco. Failing that, lazily fallback to the default umbraco log4net 1.2.11.

Basically, we need

  • a ILogHelper interface with the same members as LogHelper.
  • an implementation from umbraco compiled against the custom log4net 1.2.11
  • a new member to inject the ILogHelper impl into the LogHelper facade (eg. UseLogHelper)

In my client app, I can just reuse the log4net source and compile it within my solution. My Application_Start injects my implementation. We won't have issues with assembly loading because the custom log4net will never be loaded. (loading of a specific assembly only occurs when we enter for the first time a method that statically references a type in that assembly).

What do you think ?


James Dartnell 10 Feb 2015, 15:24:48

I was just wondering what the latest with this issue is?

I think the idea by Julien sounds pretty good being able to inject our own implementation etc.


andrew shearer 11 Mar 2015, 20:23:51

it sounds like the only approach I can take in umbraco 6 is to remove the log4net nuget package from all projects in my solution and reference the custom version that ships with umbraco instead?


Ryan Dansie 12 Mar 2015, 09:41:02

@shearer3000 see my workaround posted above. Its quite easy to work with multiple log4net versions using this web.config change.


Julien De Groote 12 Mar 2015, 13:55:07

@rdansie @shearer3000 I've had the issue where the umbraco-provided log4net was initially loading log4net.config. It would try to load a custom appender built against a strong-named log4net version. Even with dependent assembly redirection it would not work complaining about invalid cast between IAppender and IAppender ...

You'll run into similar issues any time one of your dependency depends on log4net


YodasMyDad 12 Jun 2015, 11:45:58

Just had a problem with pulling a nuget package that had a different version of log4net. Total nightmare to figure out what was going on. In the end this blog post solved it.

https://our.umbraco.org/forum/developers/extending-umbraco/45996-log4net-public-token-issues-(could-not-load-file-or-assembly)

Definitely something that needs looking at.


Ajit 24 Jul 2015, 10:22:08

Just for reference feed path has changedto http://www.myget.org/f/umbracocore/


John Smith 29 Feb 2016, 12:14:10

Eh guys..... Why is this issue so complicated?

https://www.nuget.org/packages/Common.Logging/

Use Common.Logging and then pack the current Log4net from the MyGet feed as a custom package or update doco and people to install from the myget feed if they insist on running medium trust. Log4Net, NLog, Azure App Insights all integrate with Common.Logging interface. (On that note, why not chuck in the common service locator while at it. :p)

I seriously do not understand how such a simple issue is dragged through 3 bloody major versions of Umbraco. You guys do an absolute brilliant job of adding other open source packages such as Examine/ImageProcessor/Petapoco and it's awesome that I don't have to learn crappy proprietary special way of doing things. So I really am puzzled why log4net is given such a "special treatment".


Shannon Deminick 07 Mar 2016, 12:39:53

Hi @SleeperSmith the problem is that this log4net version is not signed. Anyone who has built any package that references this log4net version from when it was first shipped, from when medium trust was a requirement, will have their packages totally break if we ship with the Nuget version of log4net because it is signed. There's really nothing that can be done about assembly binding a non-signed assembly to a signed one. This is an unfortunate scenario that we are in and we cannot 'just' replace it since we will break some packages. This is the same reason we cannot ship with an updated version of AutoMapper because they changed from an unsigned version to a signed version.


Tonny 22 Nov 2016, 15:55:37

@Shandem it is not true that you cannot redirect an assembly binding from a non-signed to a signed.

I actually commented this on the AutoMapper issue as well :D https://github.com/AutoMapper/AutoMapper/issues/373#issuecomment-127644405

If you hook into the AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve event and remove the publickey from the ResolveEventArgs.Name and pass that again in Assembly.Load("string with publickey removed") and return that assembly. The appdomain will load the dll with or without a SN token / publickey token


Shannon Deminick 22 Nov 2016, 15:58:17

Yup, i said all of that before I knew the trick. We now use this trick for the Automapper redirect in core and for an NHibernate redirect in courier. We've been talking about fixing this for this log4net thing too for a 7.x release, thanks for the reminder :)


Shannon Deminick 06 Feb 2017, 12:57:48

PR for review: https://github.com/umbraco/Umbraco-CMS/pull/1735

moved all code base assembly bindings to one place, added config assembly bindings in the template/debug files, updates nuspec.

to test: You can drop in Umbraco.Courier.Core and Umbraco.Courier.Persistence into the bin, then in your App_Code you can run this: Umbraco.Courier.Core.Logging.CourierLogHelper.Debug<CustomUmbracoStartup>(() => "hello"); this will force the assembly binding logic to execute since that is built with the old log4net unsigned assembly. This should not throw any exceptions, otherwise you'd see something like: Could not load file or assembly 'log4net, Version=1.2.11.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies . You can also breakpoint into Umbraco.Core.BindingRedirects.CurrentDomain_AssemblyResolve to see when the log4net assembly is being looked up to verify.


Claus Jensen 08 Feb 2017, 08:56:52

Tested that it seems to load correctly after the binding redirects have been moved to separate class (yay!) and logging works as expected.


Joel Cass 11 Apr 2017, 06:38:28

So almost half a decade has passed since the issue was created. The difficulty (as stated) cannot be "easy"? Is there any news on the progress of this?


Sebastiaan Janssen 11 Apr 2017, 06:44:07

Yes there is. It's due in version 7.6.0. :-)


Joel Cass 11 Apr 2017, 06:47:06

Thank you! I've sunk half a day into diagnosing this issue when integrating umbraco into an existing project... so glad to have found the bottom of it


Priority: Normal

Type: Feature (request)

State: Fixed

Assignee:

Difficulty: Easy

Category: Architecture

Backwards Compatible: False

Fix Submitted:

Affected versions: 4.10.0, 4.11.0, 6.0.0, 6.1.0, 7.0.0, 7.1.0, 4.11.1, 6.0.1, 6.0.2, 6.0.3, 6.0.4, 6.1.1, 6.0.6, 6.0.5, 6.0.7, 6.1.2, 6.2.0, 6.1.3, 6.1.4, 6.1.5, 6.1.6, 7.0.1, 7.0.2, 7.0.3, 7.0.4, 7.1.1, 7.2.0, 7.1.2, 7.1.3, 6.2.1, 7.1.4, 7.1.5, 6.2.2, 7.3.0, 7.1.6, 7.1.7, 6.2.3, 7.1.8, 6.2.4, 7.1.9, 7.2.1, 6.2.5, 7.2.2, 7.2.3, 7.2.4, 7.2.5, 7.2.6, 7.2.7, 7.4.0, 7.2.8

Due in version: 7.6.0

Sprint: Sprint 52

Story Points: 0.5

Cycle: