3

I've been trying to figure out why my console application fails the instant I introduce a new package. Using IdentityModel.OidcClient and Microsoft.AspNetCore.Server.Kestrel only works, but when adding Microsoft.Extensions.Configuration.Json it throws exception. I don't reference the new package in code either, I just add it to the project.

Steps to reproduce:

  1. Clone https://github.com/IdentityModel/IdentityModel.OidcClient.Samples.git

  2. Upgrade NetCoreConsoleClient to .NET 5 (update packages).

  3. Remove Serilog.Sinks.Literate obsolete package.

  4. Remove call to .WriteTo.LiterateConsole for SeriLog in Program.cs and add using IdentityModel.Client.

  5. Add CancellationToken cancellationToken = new CancellationToken() parameter for InvokeAsync method in SystemBrowser class. The signature for the IBrowser interface has changed, the new method should look like this: public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = new CancellationToken())

  6. Run application and login with alice/alice. Acquiring token is successful.

  7. Add package Microsoft.Extensions.Configuration.Json.

  8. Run application. It now throws exception Object reference not set to an instance of an object when writing to the http response.

The exception occurs in LoopbackHttpListener.SetResult when writing to the response: ctx.Response.WriteAsync("<h1>You can now return to the application.</h1>");

Why does adding a package only, have such an impact to the runtime?

Project file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <AssemblyName>NetCoreConsoleClient</AssemblyName>
    <OutputType>Exe</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
    <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
    <PackageReference Include="IdentityModel.OidcClient" Version="3.1.2" />
  </ItemGroup>

</Project>

Complete exception:

System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=Microsoft.AspNetCore.Server.Kestrel.Core
  StackTrace:
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.CreateResponseHeader(Boolean appCompleted)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProduceStart(Boolean appCompleted)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.InitializeResponseAsync(Int32 firstWriteByteCount)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.WriteAsync(ReadOnlyMemory`1 data, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, String text, Encoding encoding, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.HttpResponseWritingExtensions.WriteAsync(HttpResponse response, String text, CancellationToken cancellationToken)
   at ConsoleClientWithBrowser.LoopbackHttpListener.SetResult(String value, HttpContext ctx) in C:\Users\stefa\Source\Repos\IdentityModel.OidcClient.Samples\NetCoreConsoleClient\src\NetCoreConsoleClient\SystemBrowser.cs:line 172

Solution

Get rid of Microsoft.AspNetCore.Server.Kestrel and Microsoft.Extensions.Configuration.Json, change the SDK to Microsoft.NET.Sdk.Web and everything works. Thanks to @JHBonarius for pointing me in the right direction.

Vincent
  • 1,119
  • 11
  • 25
  • Please give more details on step 5. You seem to be declaring a local variable, but you say you're adding a parameter... And what exactly throws? – JHBonarius Mar 27 '21 at 09:46
  • Note that just upgrading major versions of packages AND updrading core 2.0 to 5.0 AND removing packages, without making modifications to the code, could as well be the cause. That's a major risk for unstable behavior. – JHBonarius Mar 27 '21 at 09:50
  • More modifications are required. Need to add `using IdentityModel.Client;` to Program.cs and need to remove `.WriteTo.LiterateConsole(outputTemplate:...` from Program.cs. – JHBonarius Mar 27 '21 at 09:58
  • @JHBonarius, I've added some more context, and I have also tried this without upgrading the repository, but by starting a new project and just copied relevant code over. Using correct packages. – Vincent Mar 27 '21 at 10:44
  • Please add the exception that is thrown. – Polygnome Mar 27 '21 at 10:47

3 Answers3

7

I had exactly the same issue.

 ctx.Response.StatusCode = 200;
 ctx.Response.ContentType = "text/html";
 ctx.Response.Headers.Add("Date", DateTimeOffset.UtcNow.ToString());
 await ctx.Response.WriteAsync(content);
 await ctx.Response.Body.FlushAsync();

Setting the Date Header solved it 4 me, since that is, whats failing in Kestrel.Core

aemarco
  • 101
  • 1
  • 6
  • 1
    Yep, adding the "Date" value on the Header solved it. Thanks. I have to take out the `new` from DateTimeOffset though.`ctx.Response.Headers.Add("Date", DateTimeOffset.UtcNow.ToString());` – Musa Biralo Apr 04 '22 at 08:11
  • 1
    Surprisingly it just works! Suggest to mark it as answer. – Joe Lau Jun 14 '22 at 10:09
1

The exception is thrown in

private void SetResult(string value, HttpContext ctx)
{
    try
    {
        ctx.Response.StatusCode = 200;
        ctx.Response.ContentType = "text/html";
        // below
        ctx.Response.WriteAsync("<h1>You can now return to the application.</h1>"); <--- here
        // ^^
        ctx.Response.Body.Flush();

        _source.TrySetResult(value);
    }
...

I have two comments already.

  1. WriteAsync is an async/Task. You need to await it.
  2. your 'catch' block there will also throw in this case...... you have no 'catch' for that...

Anyhow, I think the problem is you adding a .NET 5.0 version of the new package (and remember that packages often pull in other packages which they rely on) to a quite old project. Especially with ASP.net it's not that simple. Interfaces have changed. Instantiation methods have changed. You often need to put in more work.

Change the version of Microsoft.Extentions.Configuration.Json back to v3.1.13 and the problem seems to be gone...

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
  • The code is cloned from the IdentityModel repository, I've added async/await to my original code. I'm wondering why just adding the package could have such an impact to the other assemblies. I was under the impression that .NET 5 adressed the DLL-hell previously experienced in the .Net Framework. I'll take a deeper look at the actual files in the bin folder. – Vincent Mar 27 '21 at 11:15
  • @Vincent no, that's already with .NET Core. And "DLL-hell" is something else then what you are doing. You are upgrading from .NET core 2.0 to .NET 5.0: that's not a trivial task. Many things change with such a major version upgrade. Things * might * work, but they could break anytime. (In my company we're also trying to upgrade projects to .NET 5.0, but it's weeks and weeks of work.) – JHBonarius Mar 27 '21 at 11:21
  • i was sure NetStandard was sufficient for net 5 compatibility. I’ll try rewriting. – Vincent Mar 27 '21 at 12:42
0

I was having a similar issue with my ASP.NET Core 2.2 project. Making sure I didn't have any Microsoft.Extensions.X packages greater than 3.1.X fixed the issue for me.

  • That may be, but it doesn't really answer the question since this is _specifically_ about .NET 5.0. Obviously, removing contemporary library versions isn't going to solve this for them. – Jeremy Caney Aug 13 '21 at 18:24