oracle / dotnet-db-samples

.NET code samples for Oracle database developers #OracleDotNet
http://otn.oracle.com/dotnet
MIT License
413 stars 191 forks source link

Oracle.ManagedDataAccess.Core 3.21.100 references broken System.Directory.Protocols version #285

Closed mus65 closed 1 year ago

mus65 commented 1 year ago

After upgrading from 3.21.90 to 3.21.100 we got the following runtime error in our application when trying to connect to LDAP.

 ---> System.IO.FileLoadException: Could not load file or assembly 'System.DirectoryServices.Protocols, Version=6.0.0.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The located assembly's manifest definition does not match the assembly reference. (0x80131040)
File name: 'System.DirectoryServices.Protocols, Version=6.0.0.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at OracleInternal.ConnectionPool.PoolManager`3.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, OracleConnection connRefForCriteria, Boolean bMaxSemObtained, Boolean bIgnoreIdleSem, Boolean& bIdleSemObtainedWhileCreatingPR, String instanceName, List`1 switchFailedInstNames)
   at OracleInternal.ConnectionPool.OraclePoolManager.CreateNewPR(Int32 reqCount, Boolean bForPoolPopulation, ConnectionString csWithDiffOrNewPwd, OracleConnection connRefForCriteria, Boolean bMaxSemObtained, Boolean bIgnoreIdleSem, Boolean& bIdleSemObtainedWhileCreatingPR, String instanceName, List`1 switchFailedInstNames)
   at OracleInternal.ConnectionPool.PoolManager`3.Get(ConnectionString csWithDiffOrNewPwd, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
   at OracleInternal.ConnectionPool.OraclePoolManager.Get(ConnectionString csWithNewPassword, Boolean bGetForApp, OracleConnection connRefForCriteria, String affinityInstanceName, Boolean bForceMatch)
   at OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, SecureString securedPassword, SecureString securedProxyPassword, OracleConnection connRefForCriteria)

This took quite some time to figure out, the actual issue is https://github.com/dotnet/runtime/issues/84031 . I'm not going into the technical details here, but the point is that System.DirectoryServices.Protocols 6.0.1 is broken in a way that makes applications referencing System.DirectoryServices.Protocols 7.0.0 fail at runtime with this exception.

While the actual issue is in System.DirectoryServices.Protocols 6.0.1, Microsoft obviously can't patch an already published Package. We currently downgraded to 3.21.90 which references the unaffected System.DirectoryServices.Protocols 5.0.1 .

It would be great if Oracle could fix this by either going back to 5.0.1 or requiring 7.0.0 . Until then, we are stuck with Oracle 3.21.90 .

alexkeh commented 1 year ago

Customers can upgrade their System.DirectoryServices.Protocols to 7.0.0 themselves if needed. A 6.0.1 or higher version is needed in ODP.NET Core 21.10.

ODP.NET can't go back to System.DirectoryServices.Protocols 5.0.1 since there's a minimum .NET 6 requirement in some use cases.

MS could release a 6.0.2 version with a fix. The 6.x line is a long term release and should have regular patches when significant issues are discovered.

mus65 commented 1 year ago

Customers can upgrade their System.DirectoryServices.Protocols to 7.0.0 themselves if needed. A 6.0.1 or higher version is needed in ODP.NET Core 21.10.

Please read the referenced issue. The whole point is that upgrading our application to 7.0.0 is what causes the problem. And we are forced to upgrade to 7.0.0 because of another dependency requiring it.

ODP.NET can't go back to System.DirectoryServices.Protocols 5.0.1 since there's a minimum .NET 6 requirement in some use cases.

MS could release a 6.0.2 version with a fix. The 6.x line is a long term release and should have regular patches when significant issues are discovered.

Even if MS releases 6.0.2, Oracle would have to update their dependency to 6.0.2 to fix the issue.

alexkeh commented 1 year ago

What Oracle does (and any other dependent vendors) depends on when and how MS will fixes the base bug.

alexkeh commented 1 year ago

It looks like the base bug fix will be released in mid-May.

mus65 commented 1 year ago

@alexkeh The newly released 3.21.110 still has the same issue. Will the next version reference System.DirectoryServices.Protocols 6.0.2 ?

alexkeh commented 1 year ago

@mus65 Can you explain why ODP.NET Core's NuGet package needs to make System.DirectoryServices.Protocols to 6.0.2 mandatory for all users?

I just created an app, installed ODP.NET Core 3.21.110, then upgraded System.DirectoryServices.Protocols to 6.0.2.

mus65 commented 1 year ago

@alexkeh see this comment from the linked issue in particular: https://github.com/dotnet/runtime/issues/84031#issuecomment-1487359031

All Nuget Packages of System.DirectoryServices.Protocols are supposed to have an assembly version 4.0.0.0 for .NET Framework compat reasons. But for NuGet Version 6.0.1 Microsoft screwed up and accidentally set the assembly version to 6.0.0.1 . They fixed this in 6.0.2 and 7.0.0 so it has assembly version 4.0.0.0 again.

In our software we now have the following dependencies:

Oracle.ManagedDataAccess -> System.DirectoryServices.Protocols 6.0.1 -> Assembly 6.0.0.1 CoreWCF -> System.DirectoryServices.Protocols 7.0.0 -> Assembly 4.0.0.0

So at build(!) time NuGet will decide to use System.Directory.Protocols 7.0.0 with assembly 4.0.0.0 because CoreWCF needs that.

But at runtime(!) the NuGet version doesn't matter, only the assembly version does. So at runtime Oracle requires Assembly 6.0.0.1, but our software was built with assembly 4.0.0.0, so the requirement isn't met. This is what causes the mentioned exception.

So basically the Oracle package is asking for an assembly version that newer System.DirectoryServices.Protocols don't and probably never again will have. This is why referencing 6.0.2/7.0.0 in our software doesn't fix the issue, it causes it in the first place.

Also note that this is only happens if you actually use LDAP functionality at runtime. Otherwise it will never try to load System.Directory.Protocols in the first place.

Galad commented 1 year ago

Hi, I agree with @mus65, the version of System.DirectoryServices.Protocols needs to be updated in the Oracle package because the assembly reference is currently incorrect.

To trigger the issue you need to actually make the Oracle lib to load System.DirectoryServices.Protocols. This can be achieved by retrieving all the types.

_ = typeof(OracleConnection).Assembly.GetTypes();

See attached a solution where the issue can be reproduced. Oracle-System.Directory.Protocols-Repro.zip

alexkeh commented 1 year ago

@mus65 We're not able to reproduce your issue. Can you provide a simple test case we can try out?

Once we have that, we can fix the issue and be assured that the patch will resolve the problem.

@Galad Your issue appears to be different as we can reproduce this issue with managed ODP.NET, not just with ODP.NET Core.

mus65 commented 1 year ago

@alexkeh clone the repo here and just run dotnet run and it will fail: https://github.com/mus65/oracle-repro

Not sure what you mean by "different issue". @Galad describes the same problem and I even used his example to trigger the exception without actually having to set up LDAP.

alexkeh commented 1 year ago

@mus65 The test case appears to be the same as what @Galad has posted.

We believe these are two distinct issues as what @Galad's issue also occurs with managed ODP.NET, which doesn't have a System.DirectoryServices.Protocols dependency.

mus65 commented 1 year ago

@mus65 The test case appears to be the same as what @Galad has posted.

We believe these are two distinct issues as what @Galad's issue also occurs with managed ODP.NET, which doesn't have a System.DirectoryServices.Protocols dependency.

ah right, I remember now that we also had to explicitly reference the Directory.Protocols package when we were still on .NET Framework. I assumed this was your way of making it an "optional" dependency. So @Galad test case should be fixed by simply referencing the DirectoryServices.Protocols package.

My test case may look the same, but it's using .NET 6 and not .NET Framework, so it's reproducing the actual issue I initially described.

alexkeh commented 1 year ago

The Oracle team has decided to bump the NuGet dependency for ODP.NET Core NuGet to use System.DirectoryServices.Protocols 6.0.2. This will occur in the next releases, 19.21 and 21.12 versions.