Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Net.Security doesn't support coreclr #15719

Closed
benaadams opened this issue Nov 16, 2015 · 103 comments
Closed

System.Net.Security doesn't support coreclr #15719

benaadams opened this issue Nov 16, 2015 · 103 comments
Assignees
Labels
area-System.Net packaging Related to packaging
Milestone

Comments

@benaadams
Copy link
Member

It targets .NETFramework 4.6 but not .NETPlatoform 5.4/netstandard 1.3 or dnxcore5.0

Myget feed

myget

Libs installed

installedlibs

Error using

errors

@davidsh
Copy link
Contributor

davidsh commented Nov 16, 2015

cc: @ericstj

It actually does support CoreCLR. The NET46 target applies generally to all .NET. This package has runtime platform dependency packages attached to it. If you follow the runtime.json inside the package, you'll see the other packages such as runtime-System.Net.Security-win7 and other packages for *Nix etc.

@davidfowl
Copy link
Member

The NET46 target applies generally to all .NET.

Are you talking about the DLL? That's irrelevant. It's in the wrong folder regardless.

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

The packaging is correct, you are looking at the reference package. To pull in the implementation you need to make sure you set a runtime in your project.json and pull in the Microsoft.NETCore.Platforms package.

Most of the implementations are in the runtime specific packages defined by runtime.json in both the reference package (System.Net.Security) and the lineup package (eg: Microsoft.NETCore.Targets.DNXCore). We do this so that Windows users don't download Linux implementations and vice-versa. Also it is a requirement in NuGet to represent the packages this way so that they can express their platform specific dependencies.

You noticed the net46 lib folder in the package. This is an artifact of compression optimization. On net46 we already have to include the facade in the package in the ref folder so that the types exposed by the contract unify with those in system.dll
kage in the ref folder so that the types exposed by this library unify with those in system.dll at compile time. The runtime implementation is the same DLL so rather than make you download it twice for desktop we put it in the same package and let the duplicate files get compressed away.

@benaadams can you let me know if you are actually having any trouble using the package after following my suggestions?

@davidfowl
Copy link
Member

I guess that image is only showing the lib no ref.

@guardrex
Copy link

@ericstj I just had the workaround break. This was a dup of https://github.com/dotnet/corefx/issues/4230, correct? I put my question over there. I've had to go back to System.Net.Security -23405.

Is that a package name change?

Microsoft.NETCore.Platforms

to

Microsoft.NETCore.Targets.DNXCore

... that might explain why it broke for me.

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

No Microsoft.NETCore.Platforms pulls down Microsoft.NETCore.Targets.DNXCore as part of its closure. I was just giving you the specific package to look in if you wanted to see the lineup runtime.json.

@guardrex
Copy link

@ericstj Ah, I see. Any idea then why this used to work ...

"System.Net.Security": "4.0.0-beta-*",
"Microsoft.NETCore.Platforms": "1.0.1-beta-*",

... but doesn't now.

[EDIT] Answered at https://github.com/dotnet/corefx/issues/4230#issuecomment-157106465

@benaadams
Copy link
Member Author

ref folder does has it, VS tooling doesn't understand a runtime section; System.Security.Cryptography.X509Certificates works fine; but also gets pulled down as a dependency of a different package, but it doesn't pull down System.Net.Security so I had to reference it directly.

Having a little investigation to see if there are other issues.

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

@guardrex When you say "doesn't work" can you elaborate on the mode of failure? In the other thread you mentioned using a beta8 DNX. That would result in runtime issues due to torn state.

@benaadams share your project.json & project.lock.json. Latest build of packages should not require direct references to bring in implementation packages.

@guardrex
Copy link

@ericstj It throws this again ... like before I had the Microsoft.NETCore.Platforms package in place.

FileNotFoundException: Could not load file or assembly 'System.Net.Security, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system 
cannot find the file specified.

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

@guardrex can you share your project.lock.json for that case?

@guardrex
Copy link

@ericstj Sure ... brb with it.

@benaadams
Copy link
Member Author

Project json

{
  "version": "1.0.0-*",
  "description": "AgeOfAscent.Space Console Application",
  "authors": [ "Ben" ],
  "tags": [ "" ],
  "projectUrl": "",
  "licenseUrl": "",

  "dependencies": {
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
    "Microsoft.AspNet.Server.Kestrel.Https": "1.0.0-*",
    "Microsoft.AspNet.WebSockets.Server": "1.0.0-*",
    "Microsoft.AspNet.WebSockets.Protocol": "1.0.0-*",
    "Microsoft.Extensions.Logging.Console": "1.0.0-*",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-*"
  },

  "content": "space.aoa.pfx",

  "commands": {
    "web": "Microsoft.AspNet.Server.Kestrel --server.urls=http://*:80;http://*:443"
  },

  "compilationOptions": {
    "allowUnsafe": true
  },


  "frameworks": {
    "dnxcore50": {
      "dependencies": {
        "System.Runtime": "4.0.21-*",
        "Microsoft.CSharp": "4.0.1-*",
        "System.Collections": "4.0.11-*",
        "System.Console": "4.0.0-*",
        "System.Linq": "4.0.1-*",
        "System.Threading": "4.0.11-*",
        "System.Threading.Thread": "4.0.0-*",
        "System.Threading.Tasks.Parallel": "4.0.1-*",
        "System.Numerics.Vectors": "4.1.1-*"
      }
    }
  }
}

lock

https://gist.github.com/benaadams/f786108b1b45f2368800

@benaadams
Copy link
Member Author

It also got upset when I didn't have "System.Runtime": "4.0.21-*" in there

@guardrex
Copy link

@ericstj I changed it back to ...

"System.Net.Security": "4.0.0-beta-*",
"Microsoft.NETCore.Platforms": "1.0.1-beta-*",

... packages and VS auto-restored everything. I ran the app and confirmed the "could not load file or assembly" exception. Here is the project.lock.json on that ...

https://gist.github.com/GuardRex/74cb9764fe2f8da988fc

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

@benaadams I can't access your gist.

@guardrex what runtime are you running on? The lock file has an implementation dll in both DNXCore,Version=v5.0/win7-x64 and DNXCore,Version=v5.0/win7-x86.

  "targets": {
...
    "DNXCore,Version=v5.0/win7-x86": {
...
      "runtime.win7.System.Net.Security/4.0.0-beta-23409": {
...
        "runtime": {
          "lib/DNXCore50/System.Net.Security.dll": {}
        }
      },
...
    },
    "DNXCore,Version=v5.0/win7-x64": {
...
      "runtime.win7.System.Net.Security/4.0.0-beta-23409": {
...
        "runtime": {
          "lib/DNXCore50/System.Net.Security.dll": {}
        }
      },
...

With both of those present it tells me that DNX should be picking that up for those RIDs at least. If you were running on a different RID or TFM that might explain it. Just examining the diff between 23405 and 23409 the difference is that in 23405 we used a single package for all platforms (no unix support) and in 23409 it split it out into multiple packages per OS. That points to a problem with the RID being used by DNX not picking up the right target section in your lock file.

/CC @davidfowl @anurse

@benaadams
Copy link
Member Author

@ericstj missed out a 0 should be ok now

@benaadams
Copy link
Member Author

There's a "System.Net.Security/4.0.0-rc2-23513": section that doesn't have a runtime?

Though there is also a ""runtime.win7.System.Net.Security/4.0.0-rc2-23513" that does.

And also a "System.Net.Security/4.0.0-rc2-23513" section that has all the files

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

@benaadams yours looks fine just like @guardrex. The packages are providing an implementation DLL for this assembly on all targets listed in the lock file. I think we need someone from DNX to tell us why they aren't loading it. @davidfowl @anurse.

If you guys want to do more self diagnosis you can look at the log spew from DNX run to see if it echos which RID and TFM it is using, thus confirming whether or not it is looking at the right targets section.

PS: @benaadams you are looking at different sections of the lock file. The way to digest this is the targets sections are what determine which assets are used. The one that has just a TFM is used a compile time, only the compile: assets. The one with TFM/RID is the section that gets used at runtime, only the runtime: and native: assets. If any package provides a runtime asset that should be available at runtime: we happen to split our ref and implementation into multiple packages but that's completely supported and in fact ideal for these cases where the implementation differs per platform. The libraries section is just a listing of the package content from all packages in all targets sections.

@benaadams
Copy link
Member Author

No sure how get get the log going?

Tried running in VS to scoop the output and its happy; but packaged is unhappy

@ericstj
Copy link
Member

ericstj commented Nov 16, 2015

but packaged is unhappy

What do you mean by this? It sounds like its working for you in VS but not from the commandline, is that true? That would point a problem with the different versions of DNX you are using. You should be able to use DNX run on the project from the commandline to see the output. You had a partial screenshot of it at the beginning of this thread. I'm looking for the whole thing.

@benaadams
Copy link
Member Author

I:\aspnet\approot>dnvm use 1.0.0-rc2-16177 -r coreclr -a x64
Adding C:\Users\Ben.dnx\runtimes\dnx-coreclr-win-x64.1.0.0-rc2-16177\bin to process PATH

I:\aspnet\approot>web
verb: Microsoft.AspNet.Hosting.Internal.HostingEngine[4]
Hosting starting
verb: Microsoft.AspNet.Hosting.Internal.HostingEngine[5]
Hosting started
Hosting environment: Production
Now listening on: http://:5080
Now listening on: https://
:5443
Application started. Press Ctrl+C to shut down.
dbug: Microsoft.AspNet.Server.Kestrel[1]
Connection id "1" started.
fail: Microsoft.AspNet.Server.Kestrel[0]
UbReadCb
System.IO.FileNotFoundException: Could not load file or assembly 'System.Net.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Net.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.IO.FileNotFoundException: Could not load the specified file.
File name: 'System.Net.Security'
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyName(AssemblyName assemblyName)
at System.Runtime.Loader.AssemblyLoadContext.Resolve(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
at Microsoft.AspNet.Server.Kestrel.Https.HttpsConnectionFilter.d__3.MoveNext()
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.AspNet.Server.Kestrel.Https.HttpsConnectionFilter.OnConnection(ConnectionFilterContext context)
at Microsoft.AspNet.Server.Kestrel.Http.Connection.Start()
at Microsoft.AspNet.Server.Kestrel.Http.ListenerSecondary.ReadStartCallback(UvStreamHandle handle, Int32 status)
at Microsoft.AspNet.Server.Kestrel.Networking.UvStreamHandle.UvReadCb(IntPtr handle, Int32 status, uv_buf_t& buf)
verb: Microsoft.AspNet.Hosting.Internal.HostingEngine[6]
Hosting shutdown
System.IO.FileNotFoundException: Could not load file or assembly 'System.Net.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified
.
File name: 'System.Net.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.IO.FileNotFoundException: Could not load the specified file.
File name: 'System.Net.Security'
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyName(AssemblyName assemblyName)
at System.Runtime.Loader.AssemblyLoadContext.Resolve(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)
at Microsoft.AspNet.Server.Kestrel.Https.HttpsConnectionFilter.d__3.MoveNext()
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.AspNet.Server.Kestrel.Https.HttpsConnectionFilter.OnConnection(ConnectionFilterContext context)
at Microsoft.AspNet.Server.Kestrel.Http.Connection.Start()
at Microsoft.AspNet.Server.Kestrel.Http.ListenerSecondary.ReadStartCallback(UvStreamHandle handle, Int32 status)
at Microsoft.AspNet.Server.Kestrel.Networking.UvStreamHandle.UvReadCb(IntPtr handle, Int32 status, uv_buf_t& buf)
at Microsoft.AspNet.Server.Kestrel.Networking.Libuv.NativeMethods.uv_run(UvLoopHandle handle, Int32 mode)
at Microsoft.AspNet.Server.Kestrel.Networking.Libuv.run(UvLoopHandle handle, Int32 mode)
at Microsoft.AspNet.Server.Kestrel.KestrelThread.ThreadStart(Object parameter)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNet.Server.Kestrel.KestrelThread.Stop(TimeSpan timeout)
at Microsoft.AspNet.Server.Kestrel.KestrelEngine.Dispose()
at Microsoft.AspNet.Server.Kestrel.KestrelServer.Dispose()
at Microsoft.AspNet.Hosting.Internal.HostingEngine.<>c__DisplayClass35_0.b__1()
at Microsoft.AspNet.Hosting.WebApplication.Run(Type startupType, String[] args)
at Microsoft.AspNet.Server.Kestrel.Program.Main(String[] args)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Microsoft.Dnx.Runtime.Common.EntryPointExecutor.Execute(Assembly assembly, String[] args, IServiceProvider serviceProvider)
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
System.IO.FileNotFoundException: Could not load the specified file.
File name: 'System.Net.Security'
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyName(AssemblyName assemblyName)
at System.Runtime.Loader.AssemblyLoadContext.Resolve(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName)

Unhandled Exception: Microsoft.AspNet.Server.Kestrel.Networking.UvException: Error -4082 EBUSY resource busy or locked
at Microsoft.AspNet.Server.Kestrel.Networking.Libuv.Check(Int32 statusCode)
at Microsoft.AspNet.Server.Kestrel.Networking.UvLoopHandle.ReleaseHandle()
at System.Runtime.InteropServices.SafeHandle.InternalFinalize()
at System.Runtime.InteropServices.SafeHandle.Finalize()

@guardrex
Copy link

@ericstj The app is dnx-coreclr-win-x64.1.0.0-beta8 ... dnxcore50-only.

look at the log spew from DNX run to see if it echos which RID and TFM

I guess I can make Output detailed in VS to see that spew while running locally ... is that right?

@benaadams
Copy link
Member Author

Yeah, works in VS - not sure quite why? Is same version; though in debug

use-version

dnx-commandline

@benaadams
Copy link
Member Author

Also I package with the following if that is of help

dnu publish -o i:/aspnet --configuration Release --no-source --include-symbols

@guardrex
Copy link

@ericstj Oh ... well I just found out it runs locally just fine. The exception comes up when I run it on the server. Does that mean anything?

btw-- I'd be happy to dig deeper on it. I'm not sure what you mean about determining which RID and TFM ... and espeically how to get that info while on 2012R2.

Would it help you if I put up a proj that demos the exception?

@ericstj
Copy link
Member

ericstj commented Nov 17, 2015

RID is the runtime ID that DNX uses for execution and deployment, EG: win7-x86, win8-x64, etc. RID represents the target OS and architecture to use during package resolution.
TFM is the target framework moniker this is the framework used for execution and deployment. It represents the framework used for package resolution, EG: DNX for desktop based ASP.NET v5, DNXCore for coreCLR based ASP.NET v5, etc.

Both of these need to be correct and match what appears in the targets section lock file. If they don't match then it could mean you end up running on something different than you'd expect.

I dug into the dnx publish code a bit and it looks like it determines TFM and RID from the runtime you pass in as the --runtime option: https://github.com/aspnet/dnx/blob/9430fbabc6db3b6feb93bbf4997e6764514176fb/src/Microsoft.Dnx.Tooling/Publish/PublishManager.cs#L137

If not specified it looks like it would default to some default. I suspect you're getting the right values when publishing in VS but not when publishing from the command line.

@benaadams
Copy link
Member Author

Assume it did all runtimes declared when not specified? Will specify am only using one :)

Wrong arch maybe?

@ericstj
Copy link
Member

ericstj commented Nov 17, 2015

Arch shouldn't cause it. Wrong framework (DNX vs DNXCore) might. Also a RID that wasn't present in the lock file would (win10-x86 for example) or a RID that wasn't part of the RID graph if they happen to be re-restoring on publish.

I'm still waiting for @davidfowl or @anurse to chime in here and explain what's going on during publish. I'm just digging through DNX code to try to find out where this problem is. Seems at the very least there should be logging around this. If we don't hear from them on this thread I reccomend moving this issue over to the DNX repo.

@analogrelay
Copy link
Contributor

I'd rather not change the project file... just delete the lock file to force a new one.

@guardrex
Copy link

Oh, ok, I just want to make sure that MSDeploy picks up that the file has changed so it will sync for sure.

@guardrex
Copy link

Well, that's just outright bizarre ...

The Output window is showing the file getting synced ...

capture

Locally, the file looks like this ...

capture2

On the server, the timestamp seems to show the file was updated ... but it looks like it changed the file ... restored packages itself ...

capture3

Am I even looking at the correct file?

@analogrelay
Copy link
Contributor

It looks like you're comparing your project's source lock file with the published output. Those are expected to be different. I thought you said the local publish output lock file and the server lock file were different?

Either way, can you post the latter file, the one in the publish output?

@guardrex
Copy link

Sure ... brb

no ... you are correct. I wasn't looking at the one in the output folder ... my bad.

I'll get the publish (the output folder) lock file now.

@guardrex
Copy link

good ... 406K ... I'm not going crazy now. have it up in a sec.

@analogrelay
Copy link
Contributor

lol, no worries ;)

@guardrex
Copy link

@analogrelay
Copy link
Contributor

Ok, so. This is without Microsoft.NETCore.Platforms I assume? Try adding that reference (case-sensitive, version is 1.0.1-beta-23516) and redoing the publish, then re-post the lock file. Then I'd suggest re-trying that published output on the server (I know you mentioned trying that already, but hey, who knows) while I review that.

@guardrex
Copy link

Actually, I do have that now following what @ericstj said. I can confirm failure with

"Microsoft.NETCore.Platforms": "1.0.1-beta-*",
"System.Net.Security": "4.0.0-beta-*",

and the lock file I posted (that one I just put up) was with that setup.

@analogrelay
Copy link
Contributor

Hmm, that's very strange because it should at least appear in the lock file if you have it in your project.json. Can you post (yet more stuff ;)) your original project.json?

Also, the publish output should have a packages folder, can you check if Microsoft.NETCore.Platforms is in there and what the content is?

@guardrex
Copy link

The original project.json: https://gist.github.com/GuardRex/0ed609fb3303f249bd86

Yes ...

capture

and yes ...

capture2

@guardrex
Copy link

It's on the server, too.

@analogrelay
Copy link
Contributor

Ok, so to recap, this app works fine locally, but when you publish and deploy to the server, it does not work (failing to load System.Net.Security).

I'm working on trying to track down why that could happen. Out of curiosity mostly, can you try running the app from the publish output on your local machine? I'd expect it to fail there as well (thus taking the server machine basically out of the equation)

@guardrex
Copy link

Yes. Correct.

ok ... I'll try ... brb

@guardrex
Copy link

Ok, good ... it failed when run out of the output folder. I just double-clicked the 'web.cmd` and browsed to the localhost:5000 endpoint and tried to E-mail out of that controller ... 💥 It fails.

capture

@analogrelay
Copy link
Contributor

Ok, I can repro something on my box which is a very good thing. The publish process does seem to be truncating the runtime.win7.System.Net.Security package. It does not seem to be directly related to Microsoft.NETCore.Platforms as it is truncated even if I don't reference that package (but reference System.Net.Security directly). Let me look in to this further and see what I can find.

@guardrex
Copy link

Do you need anything else from me? Can I kill those files I posted?

I was going to head out and be back in the office around 2-3pm PST. I can pickup when I get back if there is more you need me to do.

@analogrelay
Copy link
Contributor

I think I'm good. Go ahead and kill the files, I've got copies and I should be OK without them. Thanks so much for your help gathering data!

@guardrex
Copy link

Oh, no prob at all. Happy I could help. I'll be back in ~3 hours if there's more to do. Later ---

@analogrelay
Copy link
Contributor

We've identified the issue and are working on a fix. I don't know exactly what form it will be released in though, so stand by on that :).

/cc @DamianEdwards @Eilon @danroth27 @davidfowl @glennc

@ericstj
Copy link
Member

ericstj commented Nov 24, 2015

@guardrex I am going to close this out since it was a DNX issue: aspnet/dnx#3183

@ericstj ericstj closed this as completed Nov 24, 2015
@tebeco
Copy link

tebeco commented Dec 4, 2015

Hi there :)
I'm not sure i'm on the good thread but i'll give a shoot here
I'm trying to use the "AuthenticatedStream" in a project where the project.json looks like this :

"dependencies": {
"Microsoft.CSharp": "4.0.1-beta-",
"System.Collections": "4.0.11-beta-
",
"System.Console": "4.0.0-beta-",
"System.Diagnostics.StackTrace": "4.0.1-beta-
",
"System.IO": "4.0.11-beta-",
"System.IO.FileSystem": "4.0.1-beta-
",
"System.Linq": "4.0.1-beta-",
"System.Net.Security": "4.0.0-
",
"System.Reflection": "4.1.0-beta-",
"System.Runtime": "4.0.21-beta-
",
"System.Runtime.Extensions": "4.0.0-",
"System.Security.Cryptography.Algorithms": "4.0.0-beta-
",
"System.Threading": "4.0.11-beta-",
"System.Threading.Thread": "4.0.0-beta-
"
},

"frameworks": {
"dnx46": { },
"dotnet5.4": { }
}

But the class is "Not available for .Net Plateform 5.4", how can I fix it ?
I've tried to add :
"Microsoft.NETCore.Platforms": "1.0.1-beta-23516",
The default Stream used seems to be nuget.org v3

Did I went wrong somewhere ?

@raffaeler
Copy link

I also have the error: "Could not load file or assembly System.Net.Security Version=4.0.0.0" when deploying an asp.net core app inside a docker container.

If I reference: "System.Net.Security": "4.0.0-beta-23516",
The result is:
System.IO.FileNotFoundException: Could not load file or assembly 'System.Net.Security

If instead I reference: "System.Net.Security": "4.0.0-rc2-23826", (taken from the aspnetcidev feed)
dnu fails restoring the package during Docker deploy with the following error:
"Unable to restore packages"

Any hints please?

@benaadams
Copy link
Member Author

Shouldn't be restoring in docker?

@raffaeler
Copy link

it should, but I suspect is missing a (native) dependencies ... I don't know how to get a better diagnostics.
BTW, this only happpens for System.Net.Security. Making requests on an endpoint where that dll is not needed, works fine.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 1.0.0-rc2 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Jan 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net packaging Related to packaging
Projects
None yet
Development

No branches or pull requests

9 participants