dotnet/systemweb-adapters

Session State is not working or Could not redirect to WebForms page.

AjayKumar22n opened this issue · 28 comments

I am trying to migrate few of the pages from webforms application (Session oriented APP) to .Net core Blazor Server app (.Net 7), either I could not get the session object in the .net core or could not redirect to webforms page. Can you please suggest.

if I invoke RequireSystemWebAdapterSession() after MapBlazorHub middleware pipeline like below , I am able to set the session (System.Web.HttpContext.Current.Session!["sessionstring"] = "Temp Session";)

but System could not navigate from blazor to framework app.

### app.MapBlazorHub().RequireSystemWebAdapterSession();
app.MapRazorPages();
app.MapBlazorPages("/_Host");

app.MapReverseProxy();

suppose if I change code like below without RequireSystemWebAdapterSession, Navigation will work from Blazor Server app to framework app. But could not read or set the session in the core app, Current.Session is showing null.

app.MapBlazorHub();
app.MapRazorPages();
app.MapBlazorPages("/_Host");

app.MapReverseProxy();

if I use both then application is having ambiguous matching endpoint - which is not correct.
app.MapBlazorHub();
app.MapBlazorHub().RequireSystemWebAdapterSession();

here is the error from console:
System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request).
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteAppSessionStateManager.SetOrReleaseSessionData(ISessionState state, CancellationToken cancellationToken)
at Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteSessionState.CommitAsync(CancellationToken token)
at Microsoft.AspNetCore.SystemWebAdapters.SessionMiddleware.ManageStateAsync(HttpContext context, SessionAttribute metadata)

I have set up unique apikey in both places, and tried with both latest adapters version 1.2.0 is also, if i use latest having different error.

Please see the complete code in the Program.cs here.

I have set up everything as described in the documentation -
var app = builder.Build();
app.UseStaticFiles();

app.UseForwardedHeaders();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

//app.UsePathBase("/" + pathBase);
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseSystemWebAdapters();

//app.UseSession();
//app.UseCors(x => x.AllowAnyOrigin());
//app.UseRequestLocalization();
app.UseAuthorization();

//app.MapBlazorHub().BufferResponseStream().PreBufferRequestStream().RequireSystemWebAdapterSession();

// The following Require System Web Adapter session is required for MapBlazorHub to use the session context object.

app.MapBlazorHub().RequireSystemWebAdapterSession();
app.MapRazorPages();//.RequireSystemWebAdapterSession();
app.MapBlazorPages("/_Host");

app.MapReverseProxy();
app.Run();

please let me know if any additional details are needed.
appsettings.json: (reverse proxy)

"ReverseProxy": {
"Routes": {
"fallbackRoute": {
"ClusterId": "fallbackCluster",
"Order": "1",
"Match": {
"Path": "{**catch-all}"
}
}
},
"Clusters": {
"fallbackCluster": {
"Destinations": {
"fallbackApp": {
//This needs to be changed based on the environment.
"Address": "https://localhost/{aaa}"
}
}
}
}
}

@AjayKumar22n I'm a little confused by your example here. Can you clean it up a little so it's something we can easily reproduce?

Thank you so much for responding,

As per our Incremental Migration from ASP.Net webforms 4.8 framework to .Net 7 blazor server,
we need Three features to be done:

  1. Navigation between Framework web forms pages and Blazor server
  2. Share the session between both Framework app and Blazor server.
  3. we might need to use Third party controls like Telerik but those are rely on Blazor.server.js which is not loaded properly.

During this time:

  1. If I Use only the below line - Session is working in both apps but Navigation from Blazor Server to Webforms is not working.
    app.MapBlazorHub().RequireSystemWebAdapterSession();

  2. If I Use only app.MapBlazorHub() then only navigation is working, but Session is not working. Session itself is set to NULL
    image

  3. if I use Both lines - It should not be, both navigation and session are working but got the below error for initializers -
    Blazor.server.js is not loaded.

image

Here is the Middleware pipeline:
app.UseSystemWebAdapters();
app.MapBlazorHub();
//app.MapBlazorHub().RequireSystemWebAdapterSession();
app.MapRazorPages().RequireSystemWebAdapterSession();
app.MapBlazorPages("/_Host");
app.MapReverseProxy();

Our existing system requires this Incremental migration process, I apricate your support on this.

I think you're hitting the issue that is described here: https://learn.microsoft.com/en-us/aspnet/core/migration/inc/blazor?view=aspnetcore-7.0. Take a look and let me know if that solves it

I have gone through this and included as well,
here is the appsettings and extentions: Can you please help me on Do i need to make any changes here:
image

Extentions:
image

and Program.cs:

app.UseSystemWebAdapters();
//app.MapBlazorHub();
app.MapBlazorHub().RequireSystemWebAdapterSession();
app.MapRazorPages().RequireSystemWebAdapterSession();
app.MapBlazorPages("/_Host");
app.MapReverseProxy();

With all this configuration, Could nor redirect to Webforms page and question mark is appended at the end of URI, please see the screeshot for reference after I clik the webforms URL:

image

Can I push my code to github and share the link, plz?

Can I push my code to github and share the link, plz?

Yes - then I can check it out directly :)

Thank You for your valuable time to look into this, Here is the Git Hub path for the sample one.

https://github.com/AjayKumar22n/SystemWebAdapterWithSession

I'm not able to build it (can't find Telerik.UI.for.Blazor) - can you make it so it can build on any computer?

Taking a look, though, I think this is problem:

- app.MapBlazorHub().RequireSystemWebAdapterSession();
+ app.MapBlazorHub();
app.MapRazorPages();//.RequireSystemWebAdapterSession();
- app.MapBlazorPages("/_Host");
+ app.MapBlazorPages("/_Host").RequireSystemWebAdapterSession();
app.MapReverseProxy();

The call to .MapBlazorHub() will set up endpoints for static resources and connect/disconnect calls for the hub; but nothing for the pages. The .MapBlazorPages(...) call is where the actual pages are added as endpoints and where you want to add metadata.

I have tried the recommended steps, still the session is not working for the Razor pages.
Hey Sorry, I removed the Telerik stuff and pushed the code,

Can you please check out the latest of the master branch - https://github.com/AjayKumar22n/SystemWebAdapterWithSession
and help me? I tried with all combinations again, still I am having Session is null in the Context object.

Can you please confirm on the changes that i need to take care, Did I do any mistakes?

Hey Can you please let us know if we have any workaround for this to handle both Session state and navigation?

@AjayKumar22n I'm hitting something weird with your solution and it seems to crash VS whenever I try to load it. I'm going to try on a different machine....

@twsouthwick, Can you please use the following Repo: https://github.com/AjayKumar22n/MigrationUsingAdapters
I have remapped to different folder and tested it is working.

Hi @twsouthwick, It would really help us if you can you provide us any resolution.

Hey Can you please let us know if we have any workaround for this to handle both Session state and navigation?

Sorry for a delayed response. I think I understand the issue, and unfortunately, it's probably not an easy fix. In a Blazor server application, the existence of an HttpContext is not guaranteed and shouldn't be relied on (see dotnet/aspnetcore#17585 (comment)).

However, some good news: with the updates coming in .NET 8 for true server side rendering of blazor, an HttpContext will be available there to enable this scenario (may need some updates on our side, but we think it will be better). It'll be available in RC2 release thanks to this PR: dotnet/aspnetcore#50253.

If you want to try that out (via nightly builds), please let us know if there's anything we need to expose/enable here to integrate with it.

@AjayKumar22n Were you able to get it working using .NET 8?

@twsouthwick I've tried and the session is no longer null, but I keep getting the following errors:

  1. Getting the session in Home.razor if set from web forms
System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).
   at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
   at Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteAppSessionStateManager.GetSessionDataAsync(String sessionId, Boolean readOnly, HttpContext callingContext, CancellationToken token)
   at Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteAppSessionStateManager.CreateAsync(HttpContext context, SessionAttribute metadata)
   at Microsoft.AspNetCore.SystemWebAdapters.SessionMiddleware.ManageStateAsync(HttpContext context, SessionAttribute metadata)
   at Microsoft.AspNetCore.SystemWebAdapters.PreBufferRequestStreamMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)      
  1. Setting the session in Home.razor
System.Net.Http.HttpRequestException: Response status code does not indicate success: 400 (Bad Request).
   at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
   at Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteAppSessionStateManager.SetOrReleaseSessionData(ISessionState state, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteSessionState.CommitAsync(CancellationToken token)
   at Microsoft.AspNetCore.SystemWebAdapters.SessionMiddleware.ManageStateAsync(HttpContext context, SessionAttribute metadata)
   at Microsoft.AspNetCore.SystemWebAdapters.PreBufferRequestStreamMiddleware.InvokeAsync(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Program.cs:

using BlazorApp1Net8.Components;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpForwarder();
builder.Services.AddSystemWebAdapters()
    .AddJsonSessionSerializer(options =>
    {
        options.RegisterKey<string>("test-value");
    })
    .AddRemoteAppClient(options =>
    {
        options.RemoteAppUrl = new(builder.Configuration["ProxyTo"]);
        options.ApiKey = "C63B2E0B-72CF-4AF6-83CD-B9A3A84DACF4";
    })
    .AddSessionClient();

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseAntiforgery();
app.UseSystemWebAdapters();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .RequireSystemWebAdapterSession();

app.MapForwarder("/Scripts", app.Configuration["ProxyTo"]).Add(static builder => ((RouteEndpointBuilder)builder).Order = int.MaxValue);
app.MapForwarder("/Content", app.Configuration["ProxyTo"]).Add(static builder => ((RouteEndpointBuilder)builder).Order = int.MaxValue);
app.MapForwarder("/About", app.Configuration["ProxyTo"]).Add(static builder => ((RouteEndpointBuilder)builder).Order = int.MaxValue);
app.MapForwarder("/Contact", app.Configuration["ProxyTo"]).Add(static builder => ((RouteEndpointBuilder)builder).Order = int.MaxValue);
app.Run();

Global.aspx.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Security;
using System.Web.SessionState;

namespace WebApplication1
{
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            // Code that runs on application startup
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            SystemWebAdapterConfiguration.AddSystemWebAdapters(this)
                .AddJsonSessionSerializer(options =>
                {
                    options.RegisterKey<string>("test-value");
                })
                .AddRemoteAppServer(options =>
                {
                    options.ApiKey = "C63B2E0B-72CF-4AF6-83CD-B9A3A84DACF4";
                })
                .AddSessionServer();
        }
    }
}

Home.razor:

@page "/"
<PageTitle>Home</PageTitle>

<h1>Hello, @TestValue!</h1>

Welcome to your new app.

@code {
    [CascadingParameter]
    public HttpContext? HttpContext { get; set; }

    protected override async Task OnInitializedAsync()
    {
        ((System.Web.HttpContext)HttpContext).Session["test-value"] = "From Blazor";
        TestValue = ((System.Web.HttpContext)HttpContext).Session["test-value"]?.ToString();

        await base.OnInitializedAsync();
    }

    public string? TestValue { get; set; }
}

It seems to be working now. I am not sure what I did, but I am not longer getting any error messages. I tried recreating the problem with the above code and it works fine now.

@pockets3407 this is great to hear! Would you be up for submitting a sample to the repo with this new set up?

@twsouthwick Sure, I can submit something once .NET 8 has been released

Great! Our repo is already targeting. Net 8 so no need to wait if you have something.

@twsouthwick Sorry about the delay. I am in the middle of adding the sample here: https://github.com/pockets3407/systemweb-adapters/tree/blazor-session-sample. I am having issues getting it working.

  1. Sessions are null in Static render mode
    This code isn't executed if I put a breakpoint inside. I think this is related to changes made with SessionStateBehavior. State is never set and always set to null
    .AddRemoteAppClient(options =>
    {
        options.RemoteAppUrl = new(builder.Configuration["ProxyTo"]);
        options.ApiKey = builder.Configuration["RemoteAppApiKey"];
    })

2. I am not sure if this is intended, but when using Server render mode for a component, HttpContext is null

EDIT: I realized that HttpContext is not intended to work with Server render mode.

Thanks @pockets3407 - I'll take a look in the morning

@twsouthwick I was wondering if there was any update on this. I have noticed #453 and #455 have been created and I think these are related.

Hello, i tried an example but seems .net8 and yarp 1.3 is not working together or there is a bug in VS2022. i always get the session values null in asp.net core app. but downgrading to all packages of system web adaptors to 1.2 works seamlessly. please advise what could be the issue. please find the repos links with ver 1.3

https://github.com/erpardeepkaushik/TestWebCore
https://github.com/erpardeepkaushik/TestWeb

Hello @twsouthwick, @AjayKumar22n @pockets3407 is there any solutions exists for this issue. I tried another example where session sharing is working between ASP.net web form app and Razor Core App. but not working with Blazor App. Also if we enable all below settings then it works with Blazor but with lot of error in yarp(no redirecting properly only one Blzoor app tab work at time.)

app.MapBlazorHub().RequireSystemWebAdapterSession();
app.MapRazorPages().RequireSystemWebAdapterSession();
app.MapBlazorPages("/_Host").RequireSystemWebAdapterSession();

Could you please advise a solutions. we have an urgent project and we stuck here now. SystemWebAdapter V1.3 is not working at all. we are working with SystemWebAdapter1.2 at the moment with NET 8.