Different identity behavior from local development to IIS

App is netcore9, using SS 8.7.1

I have an application that uses the autopopulate attributes to assign auditBase values. Code works great running it locally from Rider. However the same exact code published to IIS using the same exact database gives the following error:

Cannot insert the value NULL into column 'CreatedBy', table 'PickTicketAuditTool.dbo.PickTicketAuditLog'; column does not allow nulls. INSERT fails. The statement has been terminated.

Now if I use dotnet .{MYCUSTOMERAPP}.dll from the same exact folder that IIS is hosting the application, it works exactly like my local environment and works as expected. Any clues to what is going on?

This has now become a major issue, as I can’t deliver an app to a customer because something that just worked in the past now doesn’t work.

I have tried lots of things without success:

  • Downgraded to SS 8.4
  • Publish win-x64 only
  • Publish portable
  • downgraded my application to dotnet8 which included installed the dotnet 8 hosting bundle (this took considerable time because I had to copy all the code to another solution because there are large differences between the dotnet 8 and 9 templates)
    *tried it over ssl and regular ole http

Server is 2019 so not that old.

So I downloaded the Blazor Server template and only selected SQL Server for the options, made no changes to it, created a db for it, ran the migration then deployed the application to IIS and I am unable to create new bookings using the provided UI. This was over SSL as well.

Windows Server 2019, IIS 10, App Pool using ApplicationIdentity,

Not sure why it matters, @mythz but only after installing Web Sockets on IIS did the Auth work properly again.

The missing auth sounds like the previous issue with the In Process gateway which was resolved in v8.7.1:

Please confirm that you’re using the v8.7.1 pre-release packages in the new Blazor template? The version is available from app.serviceStackVersion in the App’s /metadata/app.json.

I’ll look at releasing v8.7.2 with the fix early next week, but I want to confirm that this issue has been resolved in v8.7.1.

Please note we only build for and test with LTS versions, e.g. .NET 8. We’ll have a new .NET 10 builds when it’s released later this year.

I verified that 8.7.1 dll’s were copied to the publish folder.

Please confirm the version returned in /metadata/app.json

“serviceStackVersion”: “8.71”

So to confirm, the default template with SQL Server does not have this issue locally but fails when deployed to IIS? But starts working after installing Web Sockets on IIS?

Blazor docs does mention that Web Sockets is recommended as it offers improved security so I’m assuming there are differences and the docs for hosting Blazor Server Apps with IIS does specify:

When using IIS, enable:

Correct to your first two statements.

I understand but figured how one connects to a website shouldn’t impact the web app functionality. Meaning in both instances the application recognized me as being logged in, etc but only AutoQuery Autopopulate was negatively impacted by how signlar is communicating to the browser. I checked the cookies in both instances and they looked to be exactly the same.

In this specific case another programmer had deployed a non-SS blazor app on the same server which would have been using long polling and never had any similar problems.

Now if I just have to make sure Websockets is activated on IIS, no biggie, as at least in this case it did not require a restart of the server and did not impact the other IIS sites running.

I will say that for a different client a few months back I deployed a 8.4 SS app using Azure AD authentication and I would encounter random failures with the Autopopulate attributes where it would complain about the value being null. With it being impossible to reproduce, I changed the code in the service to grab the username from the session and that has been fine ever sense.

AFAICT all the issues are due to missing Authentication, e.g. the Autopopulate attributes that would fail are likely the ones that populating info from the Authenticated user like username.

The difference between ServiceStack and other Blazor Apps are that ServiceStack makes API Requests both InProcess (within the Server Circuit) and over HTTP where non-ServiceStack Apps only make API Requests over HTTP and the issue with missing authentication is always from In Process Gateway which should be resolved in v8.7.1.

Blazor Server Authentication has always been extremely fragile, so much so we ended up giving up trying to maintain our own AuthenticationStateProvider with ServiceStack Auth in .NET 8 and migrated to using ASP .NET Core Identity Auth so that we can use Blazor’s IdentityRevalidatingAuthenticationStateProvider as-is which we’ll continue to do going forward and use the same IdentityAuth AuthenticationStateProvider that’s used in Microsoft’s own LTS Blazor templates in order to use the same tested Authentication lifecycle that Blazor server was designed to use.

A notable difference between Web Sockets and Long polling is that Web Sockets maintain a direct connection between the App and the Blazor’s server circuit (maintaining Auth state) where using long polling would fail if it’s not communicating back to the same server instance that’s hosting the Server circuit which is why load balanced Apps without Session Affinity would sporadically fail. Web Sockets also have differences in CORS behavior.

Either way it appears the same recommended solution for Blazor Server Apps with Web Sockets and the latest ServiceStack v8.7.1 should resolve the missing authentication issue. I’ll look at deploying a new v8.7.2 within the 2 days so you don’t need to depend on pre-release packages.

Roger that. Thanks for the feedback and I will just make it a part of my Blazor deployment process to activate Web Sockets. Too bad Microsoft doesn’t have it enabled by default since it is a core part of one of there flagship product. I really appreciate the product

Also, is below the best/supported way to get the claims/roles of the logged in user? @mythz

var session = await GetSessionAsync();
var roles = session?.Roles;

When using IdentityAuth I’d resolve it directly from the Authenticated ClaimsPrincipal:

var user = Request.GetClaimsPrincipal();
var roles = user.GetRoles();
1 Like