GithubHelp home page GithubHelp logo

systemweb-adapters's Introduction

System.Web adapters for ASP.NET Core

This project provides a collection of adapters that help migrating from System.Web.dll based ASP.NET projects to ASP.NET Core projects. The adapters currently include:

  • Microsoft.AspNetCore.SystemWebAdapters: Subset of the APIs from System.Web.dll backed by Microsoft.AspNetCore.Http types
  • Microsoft.AspNetCore.SystemWebAdapters.CoreServices: Support for adding services to ASP.NET Core applications to enable migration efforts
  • Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices: Support for adding services to ASP.NET Framework applications to enable migration efforts
  • Microsoft.AspNetCore.SystemWebAdapters.Abstractions: A collection of abstractions shared between the ASP.NET Core and .NET Framework implementations, such as session serialization interfaces.

These adapters help enable large scale, incremental migration from ASP.NET to ASP.NET Core. For more details on incremental migration from ASP.NET to ASP.NET Core, see Incremental ASP.NET to ASP.NET Core Migration.

Get started

Use the Get started with incremental ASP.NET to ASP.NET Core migration guide in the docs to start using the System.Web adapters as part of an incremental migration from ASP.NET to ASP.NET Core.

Set up

The following steps are needed to use the System.Web adapters with an ASP.NET project:

  1. Optional for nightly adapter builds: Set up NuGet.config to point to the CI feed:
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <packageSources>
        <!--To inherit the global NuGet package sources remove the <clear/> line below -->
        <clear />
        <add key="nuget" value="https://api.nuget.org/v3/index.json" />
        <add key=".NET Libraries Daily" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-libraries/nuget/v3/index.json" />
      </packageSources>
    </configuration>
  2. Install Microsoft.AspNetCore.SystemWebAdapters to supporting libraries
    • Class libraries can target .NET Standard 2.0 if desired which will ensure you are using the shared surface area
    • If you find that there's still some missing APIs, you may cross-compile with .NET Framework to maintain that behavior and handle it in .NET core in some other way
    • There should be no manual changes to enable using supported surface area of the adapters. If a member is not found, it is not currently supported on ASP.NET Core
  3. Install Microsoft.AspNetCore.SystemWebAdapters.CoreServices to your ASP.NET Core application
  4. Install Microsoft.AspNetCore.SystemWebAdapters.FrameworkServices to your ASP.NET Framework application
    • The package installation will add a new module to your web.config. This module handles any customizations that are required to help migrate to .NET Core.
  5. For your ASP.NET Core application:
    • Register the adapter services:
      builder.Services.AddSystemWebAdapters();
    • Add the middleware after routing but before endpoints (if present);
      app.UseSystemWebAdapters();

Supported Targets

  • .NET 6.0: This will implement the adapters against ASP.NET Core HttpContext. This will provide the following:
    • Conversions between ASP.NET Core HttpContext and System.Web adapter HttpContext (with appropriate caching so it will not cause perf hits for GC allocations)
    • Default implementations against Microsoft.AspNetCore.Http.HttpContext
    • Services that can be implemented to override some functionality such as session/caching/etc that may need to be customized to match experience.
  • .NET Standard 2.0: This will essentially be a reference assembly. There will be no constructors for the types as ASP.NET Core will construct them based on their HttpContext and on framework there are already other constructors. However, this will allow class libraries to target .NET Standard instead of needing to multi-target which will then require everything it depends on to multi-target.
  • .NET Framework 4.7.2: This will type forward the adapter classes to System.Web so that they can be unified and enable libraries built against .NET Standard 2.0 to run on .NET Framework instances.

Known Limitations

Below are some of the limitations of the APIs in the adapters. These are usually due to building off of types used in ASP.NET Core that cannot fully implement the shape of the API in ASP.NET Framework. In the future, analyzers may be used to flag usage to recommend better patterns.

  • A number of APIs in System.Web.HttpContext are exposed as NameValueCollection instances. In order to reduce copying, many of these are implemented on ASP.NET Core using the core containers. This makes it so that for many of these collections, Get(int) (and any API that requires that such as .Keys or .GetEnumerator()) are unavailable as most of the containers in ASP.NET Core (such as IHeaderDictionary) does not have the ability to index by position.

Reporting security issues and bugs

Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the Security TechCenter.

Contributing

See CONTRIBUTING.md

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

Code of conduct

See CODE-OF-CONDUCT

systemweb-adapters's People

Contributors

adityamandaleeka avatar afshinm avatar avremelm avatar birojnayak avatar br3nt avatar changetol8 avatar clounea avatar czemacleod avatar dependabot[bot] avatar dotnet-maestro[bot] avatar dotnet-policy-service[bot] avatar elderry avatar haok avatar jeffhandley avatar jherven avatar johnlwith avatar joperezr avatar kschlobohm avatar maples7 avatar martincostello avatar microsoft-github-operations[bot] avatar microsoftopensource avatar mjrousos avatar ragnarstolsmark avatar rick-anderson avatar sdekock avatar tbertenshaw avatar tratcher avatar twsouthwick avatar wtgodbe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

systemweb-adapters's Issues

Consider dropping .NET Core 3.1 support

The adapter library currently supports targeting .NET Core 3.1. We should consider dropping support for .NET Core 3.1 since it will no longer be supported by the time we expect to ship a stable release.

A 407 Proxy Authentication Required when using remote authentication

Describe the bug

When using the remote authentication which was included in a recent update, after the authentication is complete, when the /systemweb-adapters/authenticate endpoint is loaded, an IIS HTTP 407.0 Proxy Authentication Required page is displayed. After this error page is loaded, any attempt to go to any URL, whether it ends up loading the new ASP.NET Core application, or if it loads the old ASP.NET application, works without any further issues, with the user properly authenticated. Also, the Logon User field on the error page does properly list the username of the person logged in.

This application is not using forms authentication nor bearer jwt. It is instead making use of the WsFederationAuthenticationModule and SessionAuthenticationModule to allow federated login. As I have it set up, the original ASP.NET application ran on localhost:44378, and the STS is set up to post the token to localhost:44378/, which would be processed by the WsFederationAuthenticationModule. After the migration, the new ASP.NET Core application runs on localhost:44395. When a challenge occurs, a redirect to the STS with the proper WS-Federation supplied information does occur, I am able to log in via the STS, and it posts the data to localhost:44378/, which properly processes the token, and then redirects to localhost:44378/systemweb-adapters/authenticate, at which point the Proxy Authentication Required page appears. Attempting to reload localhost:44395 works with the logged in user information available.

I also attempted changing the STS to post the token information to localhost:44395/signin-wsfed (in order to make sure the request gets properly forwarded to the ASP.NET application rather than being handled by the default razor page in ASP.NET Core), the result is exactly the same, with the exception that the Proxy Authentication Required page is loaded from localhost:44395/systemweb-adapters/authenticate. Also, just like before, reloading localhost:44395 after this results in proper authenticated access.

I do not have enough information to determine if this issue is caused by trying to use this with WsFederationAuthenticationModule, or if this is due to having something else not set up properly.

To Reproduce

After performing a migration via the VS extension and then updating the SystemWebAdapters package to a locally built package containing the remote authentication implementation, I added code to enable the remote authentication.

ASP.NET Core application

    .AddRemoteAppAuthentication(true, opts => {
        opts.RemoteServiceOptions.ApiKey = "Some secret key";
        opts.RemoteServiceOptions.RemoteAppUrl = 
            new(builder.Configuration["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"])
        ;
    })

ASP.NET Application

    .AddProxySupport(opts => {
        opts.UseForwardedHeaders = true;
    })
    .AddRemoteAppAuthentication(opts => {
        opts.RemoteServiceOptions.ApiKey = "Some secret key";
    })

Further technical details

Please include the following if applicable:

ASP.NET Framework Application:

  • Technologies and versions used (i.e. MVC/WebForms/etc): WebForms
  • .NET Framework Version: 4.7.2
  • IIS Version: 10 Express
  • Windows Version: 10

ASP.NET Core Application:

  • Targeted .NET version: 6.0
  • .NET SDK version: 6.0.300

Adding an ASP.NET Core migration project should not disrupt the existing ASP.NET app

Currently, when you run the migration tool to add an ASP.NET Core project, the ASP.NET Core project contains routes that most likely disrupt existing routes in the ASP.NET app (like "/"). For example, if you start with a default ASP.NET MVC app and then run the migration tool, the app is now appears replaced by the ASP.NET Core app when you run it. Ideally, after running the migration tool the app still functions as it did previously without any disruption. I think this means the ASP.NET Core migration project should initially be empty of any initial endpoints. The user then adds the endpoints that they want to migrate.

Missing Cookies

Describe the bug

Numerous cookies are missing from our requests from our .net core site that proxies back to our legacy site. LIke the ASP.NET_SessionId and __RequestVerificationToken cookies. And multiple cookies we write from our site.

For most of our form posts, we are getting an error: The required anti-forgery cookie "__RequestVerificationToken" is not present.

Further technical details

ASP.NET Framework Application:
.net 4.8 hybrid application web forms/mvc

ASP.NET Core Application:
.Net 6.0

Add some missing APIs for HttpContext, HttpRequest and HttpResponse

Summary

Most primary APIs of HttpContext, HttpRequest and HttpResponse are provided, which is fantastic! And some missing APIs could be considered to be added to make this adapter more universal.

Motivation and goals

Some missing APIs are frequently used for .NET Framework and adding them to the adapter will make the migration smoother and more doable for large projects.

In scope

For HttpContext:

  • DisposeOnPipeline #88
  • CurrentHandler #146
  • CurrentNotification #146
  • IsCustomErrorEnabled #152
  • IsDebuggingEnabled #106
  • PreviousHandler #146
  • Timestamp #104
  • GetGlobalResourceObject #23
  • GetLocalResourceObject #23
  • GetSection #23
  • RewritePath #145
  • SkipAuthorization #147
  • SetSessionStateBehavior #147

For HttpRequest:

For HttpResponse:

  • AppendCookie #102
  • AppendToLog #153
  • ApplyAppPathModifier #149
  • BinaryWrite #102
  • ClearHeaders #102
  • BufferOutput #147
  • IsRequestBeingRedirected #102
  • SubStatusCode #102
  • RedirectPermanent #102
  • Expires #155
  • SuppressFormsAuthenticationRedirect #154
  • TransmitFile #102
  • WriteFile #102
  • WriteSubstitution

Risks / unknowns

I can imagine not all of them make sense for ASP.NET Core, or fit .NET Core's design philosophy, or are easy to implement.

Examples

More APIs covered, more large projects could be benefited.

Allow ASP.NET Core session APIs to be used with remote session state

Once users have moved some code from their ASP.NET app to the ASP.NET Core one, it may be valuable, as a next step, to be able to update that code to use "real" ASP.NET Core APIs instead of adapters.

In order to enable that, it may be useful to have ISessionStore and ISession implementations that allow ASP.NET Core session APIs to be used while still storing session items in remote session storage for interoperability with other endpoints that are still on ASP.NET.

The user would still have to use the ASP.NET Core session API (that's the whole point of this migration) so their code would need to change to only read/write byte[]s and any code in other parts of the solution that works with those session items would also need to be updated to work with byte[]s, but those changes would be necessary sooner or later as part of migration anyhow. Having the ability for those session items to be shared between the two apps just enables some parts of the solution to be more completely migrated even before the entire app is running on Core.

Application fails to start

If either the core app or 4.7.2 app are set as Startup, the application fails to run. If I then rerun the migration tool, its sets neither to startup and the app runs again. I am using VS2022 latest.

Add incremental upgrade support for WCF

Migrating from WCF to Core WCF has many similarities to upgrading from ASP.NET to ASP.NET Core. WCF is often hosted in ASP.NET and often uses HTTP as the transport (although it can do TCP and other transports as well). For an HTTP based WCF service, you could
incrementally migrate by setting up an ASP.NET Core project with the same YARP based fallback that we already have. The tooling could setup Core WCF in the new ASP.NET Core project and the user could then migrate over their services one at time.

@samsp-msft

webforms migration

I've got an asp .net webforms app. There are probably 40 webforms pages, but only a couple of really big webforms pages. The app uses ado.net datasets/datatables for database access to sql server and a little bit to mysql. The app pretty much uses simple stuff in webforms, but does use the updatepanel/updateprogress, but nothing from the ajax control toolkit. I use some basic session state, but not a lot. We are trying to figure out how to migrate to asp .net core (I understand that this is a manual conversion and one page at a time). All of the talk in this is about migrating from asp .net mvc. Has anyone updated a webforms app with this tool? Is updating with webforms possible?

TIA.

Logging out from ASP.NET Core app using ASP.NET Identity with remote app auth doesn't work

Using remote app auth to share identity between an ASP.NET and ASP.NET Core app during incremental migration works for solutions using ASP.NET Identity for auth except for attempting to logout from an ASP.NET Core-served page.

The problem is that logging out in MVC apps using Identity is usually done via a form post to a logout endpoint. But when the logout form comes from the ASP.NET Core app and the endpoint that is posted to comes from the ASP.NET app, the operations fails due to not having a valid anti-forgery field.

The 'MvcApp' and 'MvcCoreApp' in this repo's samples folder demonstrates this problem.

A workaround is to logout from a page served by the ASP.NET portion of the app, but a better user experience would be to be able to logout from any part of the site.

Exception:

System.Web.Mvc.HttpAntiForgeryException: The required anti-forgery form field "__RequestVerificationToken" is not present.

[HttpAntiForgeryException (0x80004005): The required anti-forgery form field "__RequestVerificationToken" is not present.]
   System.Web.Helpers.AntiXsrf.TokenValidator.ValidateTokens(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken sessionToken, AntiForgeryToken fieldToken) +692
   System.Web.Helpers.AntiXsrf.AntiForgeryWorker.Validate(HttpContextBase httpContext) +128
   System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) +168
   System.Web.Mvc.Async.<>c__DisplayClass3_1.<BeginInvokeAction>b__0(AsyncCallback asyncCallback, Object asyncState) +1082
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +163
   System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object state) +463
   System.Web.Mvc.<>c.<BeginExecuteCore>b__152_0(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState) +48
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +163
   System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +787
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +163
   System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +630
   System.Web.Mvc.<>c.<BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState) +99
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState) +73
   System.Web.Mvc.Async.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +163
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +544
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +1128
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +220
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +134

Error reporting when serialization an unknown session key

Summary

When serializing session, we require keys to be registered with the type they represent. However, people will probably not know the keys they have and will need a way to identify that. The simplest would be to turn on some messaging around keys that aren't registered. This issue is to decide on how we want to do that.

This will focus on the scenario where we have remote app session state enabled.

Reproduce

Create a remote app session without registering known keys. Attempt to load session on core side. An InvalidOperationException is thrown at the point of serializing an unknown key.

  • When serializing/deserializing on the framework side, this leads to a 500 error on the framework handler, which propagates down to the core app as a failure. There is no actionable message available here.
  • If the framework side has successfully serialized a payload (it knows about all the keys), but the core app encounters a key it is unaware of, it will surface as a InvalidOperationException that causes the request to fail. Same thing occurs if a key is added that is unknown when we attempt to serialize.

Recommendations

Option 1

This option still causes the request to fail, but attempts to provide the information to mitigate it.

public class UnknownSessionKeyException
{
  public IReadOnlyCollection<string> UnknownKeys { get; }
}
  • The request to the framework app should not result in a 500 error. Instead, it should provide a https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.problemdetails object that lists the unknown keys
  • Upon error from the framework app, the core app will raise an UnknownSessionKeyException which lists all the unknown keys
  • Upon deserialization/serialization attempt, the session middleware will raise an UnknownSessionKeyException if an unknown key is encountered
  • This will still cause a failure of the request on the ASP.NET Core side, but will provide a list of unknown keys

Option 2

This option will not fail if an unknown key is found, but will log error messages that clearly identify the unknown keys.

  • The request to the framework app should not result in a 500 error. If an unknown key is found, it should be added to the payload as a new field that will convey that information to the client.
  • When the core app receives its payload, it will right out a message of the unknown keys at an Error level to communicate to the developer that a key was used that has not been registered
  • When the session middleware serializes the new keys, it will write out any unknown keys to the log

Option 3

A combination of Option 1 and Option 3 that can be opted into via the Session options

Additional thoughts

  • Do we want to include the type info of the key that was found if attempting to serialize and it's not registered?

Feedback from initial API Review

Summary

We had an API review and here are the list of changes we need to make:

  • Remove constructors from HttpContext, HttpRequest, HttpResponse #113
  • Add [Obsolete] to APIs that will cause sync over async and expose async counterparts on the ASP.NET Core build #164
  • Move builders to System.Web namespace for framework helpers and Microsoft.AspNetCore.Builders for the core helpers
  • Remove interfaces from attributes #113
  • Rename IsEnabled to IsDisabled from metadata attributes #113
  • Rename PreLoad to Preload #113
  • Make DelegatingSessionState internal (#134)
  • Make DefaultRequestHeadersToForward and DefaultResponseHeadersToForward internal (#120)
  • #138
  • AuthenticationEndpointPath should be a PathString on ASP.NET Core. (#120)
  • Avoid using the same name for types that are at all structurally different and will not ever have shared code calling it from top (#120)
  • Rethink builder pattern for remote app functionality (#120 #165)

Original feedback:

Response.end exception

Describe the bug

Response.End causes a exception the the application.

To Reproduce

System.Web.HttpResponse.End()

Exceptions (if any)

      The response has already started, the error page middleware will not be executed.
fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HMI7TLM8OSIL", Request id "0HMI7TLM8OSIL:00000027": An unhandled exception was thrown by the application.
      System.InvalidOperationException: Response buffering must be enabled on this endpoint for this feature via the IBufferResponseStreamMetadata metadata item
         at System.Web.HttpResponse.get_BufferedFeature()
         at System.Web.HttpResponse.End()

Further technical details

Please include the following if applicable:
ASP.NET Core Application:

  • Targeted .NET version: 6.0
  • .NET SDK version: 6.0

MvcCoreApp does not compile

Building the repo locally, the MvcCoreApp project fails to compile if Yarp.ReverseProxy 1.1.0 is not already in the user's local NuGet package cache.

It appears that the package is not available in any of the configured NuGet package sources in AzDo.

<clear />
<add key="dotnet6" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json" />
<add key="dotnet-eng" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json" />
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
<add key="myget-legacy" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/myget-legacy/nuget/v3/index.json" />

Manually adding the package source below to NuGet.config and running dotnet restore resolves the issue.

<add key="NuGet" value="https://api.nuget.org/v3/index.json" />

Simplify registration of remote app urls

For things like remote app session, we require setting up the remote app. This is currently being done by digging into the same config value that YARP is using:

builder.Services.AddSystemWebAdapters()
    .AddRemoteAppSession(options =>
    {
        // Provide the URL for the remote app that has enabled session querying
        options.RemoteApp = new(builder.Configuration["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]);

        // Provide a strong API key that will be used to authenticate the request on the remote app for querying the session
        options.ApiKey = "strong-api-key";
    });

This looks a little ugly - can we refine this at all?

IIS + UseForwardedHeaders + System.Web.HttpContext.Current.Request.Url

I created a brand new MVC .Net Framework App.

Then i used the Microsoft Project Migration Extension to create a new .Net Core App.

Changed the .Net Framework App to add

protected void Application_Start()
{
...
this.Application.AddSystemWebAdapters()
.AddProxySupport(options =>
{
options.UseForwardedHeaders = true;
});
}

I run the app in IISExpress and when i check the System.Web.HttpContext.Current.Request.Url value in the .Net Framework i have the .Net core url.

Then i change the hosting of the apps to run in IIS. I create 2 Application with 2 different Pools

Now when i check the System.Web.HttpContext.Current.Request.Url i have the .Net Framework url.

Am i missing something?

Thx

Release: end-to-end guide in docs site for how to get started

Include in docs:

  • Security concerns around exposing the endpoint for remote session
    • Communication should be locked down (i.e. SSL)
    • Potentially long lived requests between core and framework apps
  • Some unsupported APIs:
    • Thread.CurrentPrincipal
    • CultureInfo.Current
  • Known behavior differences:
    • There was a concept around a request thread in ASP.NET - core does not have this and this difference may be observable

Getting "Serialized session state has different version than expected" error when attempting to utilize Session.

Describe the bug

I have setup my 2 projects (1 asp.net web forms app, and 1 asp.net core Razor Pages app).

When I attempt to force the usage of Session state to all pages, I get the exception noted below.

To Reproduce

asp.net core is configured as:

            builder.Services.AddSystemWebAdapters()
                .AddJsonSessionSerializer(options => {
                    options.RegisterKey<int>("LookupKey");
                    //RemoteServiceUtils.RegisterSessionKeys(options.KnownKeys);
                })
                .AddRemoteAppSession(options => {
                    options.RemoteAppUrl = new Uri(builder.Configuration["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]);
                    options.ApiKey = RemoteServiceUtils.ApiKey;
                })
                .AddRemoteAppAuthentication(true, options => {
                    options.RemoteServiceOptions.RemoteAppUrl = new Uri(builder.Configuration["ReverseProxy:Clusters:fallbackCluster:Destinations:fallbackApp:Address"]);
                    options.RemoteServiceOptions.ApiKey = RemoteServiceUtils.ApiKey;
                });

asp.net web forms project is configured as:

			Application.AddSystemWebAdapters()
				.AddProxySupport(options => {
					options.UseForwardedHeaders = true;
				})
				.AddRemoteAppAuthentication(options => {
					options.RemoteServiceOptions.ApiKey = RemoteServiceUtils.ApiKey;
				})
				.AddRemoteAppSession(options => {
					options.ApiKey = RemoteServiceUtils.ApiKey;
				}, options => {
					//RemoteServiceUtils.RegisterSessionKeys(options.KnownKeys);
					options.RegisterKey<int>("LookupKey");
                });


            app.MapRazorPages()
                .RequireSystemWebAdapterSession();

If I do not force the Session usage, the proxying works as I would expect. Session state is using the Microsoft.Web.Redis.RedisSessionStateProvider, so potentially that is causing some issues?

Exceptions (if any)

info: Yarp.ReverseProxy.Configuration.ConfigProvider.ConfigurationConfigProvider[1]
      Loading proxy data from config.
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:7109
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5109
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: D:\projects\4.5.6\source\websites\dashboards\CI.Website.Analysts.Core\
info: System.Net.Http.HttpClient.IRemoteAppAuthenticationService.LogicalHandler[100]
      Start processing HTTP request GET https://localhost:44300/systemweb-adapters/authenticate
info: System.Net.Http.HttpClient.IRemoteAppAuthenticationService.ClientHandler[100]
      Sending HTTP request GET https://localhost:44300/systemweb-adapters/authenticate
info: System.Net.Http.HttpClient.IRemoteAppAuthenticationService.ClientHandler[101]
      Received HTTP response headers after 29.7402ms - 302
info: System.Net.Http.HttpClient.IRemoteAppAuthenticationService.LogicalHandler[101]
      End processing HTTP request after 34.2488ms - 302
info: System.Net.Http.HttpClient.ISessionManager.LogicalHandler[100]
      Start processing HTTP request GET https://localhost:44300/systemweb-adapters/session
info: System.Net.Http.HttpClient.ISessionManager.ClientHandler[100]
      Sending HTTP request GET https://localhost:44300/systemweb-adapters/session
info: System.Net.Http.HttpClient.ISessionManager.ClientHandler[101]
      Received HTTP response headers after 29.5322ms - 200
info: System.Net.Http.HttpClient.ISessionManager.LogicalHandler[101]
      End processing HTTP request after 29.6101ms - 200
fail: Microsoft.AspNetCore.SystemWebAdapters.SessionState.RemoteSession.RemoteAppSessionStateManager[1]
      Unable to load remote session state for session rbhmqjyyln3ycfpwcab5blqj
      System.InvalidOperationException: Serialized session state has different version than expected
         at Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.BinarySessionSerializer.Read(BinaryReader reader)
         at Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.BinarySessionSerializer.DeserializeAsync(Stream stream, CancellationToken token)
         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, ISessionMetadata metadata)
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.InvalidOperationException: Serialized session state has different version than expected
         at Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.BinarySessionSerializer.Read(BinaryReader reader)
         at Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization.BinarySessionSerializer.DeserializeAsync(Stream stream, CancellationToken token)
         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, ISessionMetadata metadata)
         at Microsoft.AspNetCore.SystemWebAdapters.SessionMiddleware.ManageStateAsync(HttpContext context, ISessionMetadata metadata)
         at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Further technical details

Please include the following if applicable:

ASP.NET Framework Application:

  • Technologies and versions used (i.e. MVC/WebForms/etc): Web Forms
  • .NET Framework Version: 4.8
  • IIS Version: IIS Express
  • Windows Version: Windows 11

ASP.NET Core Application:

  • Targeted .NET version: .net 6.0
  • .NET SDK version:

Question about migration process without strangler fig

Summary

I am trying to migrate an ASP.NET webapi app to ASP.NET Core webapi app. I will have 2 apps side by side, (no strangler fig, as the need for running the two apps side-by-side) but I thought using SystemWebAdapters nuget package could still help.

Motivation and goals

I have 50 library projects stuffed with controllers. I would like to make the same controllers usable in both ASP.NET and ASP.NET Core, without duplication (or with minimal duplication - where a common abstraction is not possible). Which means I am looking for a common abstractions. That is where I believe this library may come into the picture to help me.

I have the 2 app hosts (ASP.NET and ASP.NET Core prepared), filters, middlewares, etc. migrated. Now comes the controllers.

Question

My understanding the library would provide these abstractions, so that I can also build and use the existing controllers as-is in the ASP.NET Core app, and once the legacy ASP.NET host decommissioned, migrate from the types in this library to the types provided by ASP.NET Core.

For example: initially I use IHttpActionResult from ASP.NET. Then switch to a type IHttpActionResult that comes from SystemWebAdapters package. Finally, once I can deco the ASP.NET app, I can remove SystemWebAdapters nuget package and migrate the controllers using IActionResult from ASP.NET Core.

I add (your daily nuget package) to the library project with the controllers. I remove System.Web reference and target the library against .NET6 and .NET462. At this point the .NET462 - ASP.NET version of the app compiles and works.

However, when I get to the ASP.NET Core (.NET6 version) I get all build errors for types missing: HttpGetAttribute, IHttpActionResult, ResponseTypeAttribute. Did I miss any obvious step?

At what point would you suggest to add the following to the library containing the controllers?

<ItemGroup Condition="'$(TargetFramework)' != 'net462'">
  <FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

Consider adding MS.Extensions.DependencyInjection and MS.Extensions.Options for framework adapters

Summary

We should add the Microsoft.Extensions.DependencyInjection and Microsoft.Extensions.Options packages to the framework app so that configuration between the two apps can be similar.

Motivation and goals

There's currently two separate mechanisms for configuring the core app and the framework app. The core app uses the standard dependency injection patterns as the rest of ASP.NET Core. The framework app uses a similar fluent syntax, but doesn't have the full dependency injection available to it. This will make it difficult for users to fully customize things, such as custom session serializers.

As customers move to ASP.NET Core, they will start taking advantage of using the new DI and options frameworks, and this can be a way to simplify things in their ASP.NET Framework code base. This will also allow the adapters to be more flexible and have a consistent usage across app stacks.

In scope

  • Main use will be to update ISystemWebBuilder to expose IServiceCollection rather than ICollection<IHttpModule> on framework. No changes will be seen to the core adapters.

Out of scope

  • If we want to expose ISystemWebBuilder on .NET Standard, we could just add the abstractions packages. However, I'm leaning towards not exposing it to reduce that dependency if someone is targeting .NET Standard

Risks / unknowns

  • This may bring in new dependencies to the users framework app.

Document how to deploy while migrating

Hey all,

A question - how do I actually deploy this to something like Azure App Services. Do I need 2 web apps? I am guessing I can't just run a .NET6 app and its all going to work?

Add support for migrating using Blazor

Cocoon Offers support for migrating ASP.NET projects using Blazor. This is appealing for ASP.NET Web Form developers that are used to a component-based event-driven programming model.

Cocoon does some clever things to enable migration with Blazor using the strangler-fig pattern, like collecting the routable components in the app so that the fallback to the ASP.NET app happens correctly.

Consider supporting APIs for HttpBrowserCapabilities

Summary

HttpBrowserCapabilities is a common set of APIs that users use to interrogate info about a client. We probably don't want to support the full API set, but should identify the low hanging fruit (such as Browser, Version, etc) that are most common in code bases.

In scope

  • TBD

Out of scope

We probably don't want to bring in the whole provider system that System.Web had, but have a way of collecting the regex patterns that may be user supplied.

Risks / unknowns

The HttpBrowserCapabilities infrastructure in System.Web is quite large and we need to scope it to what is a good minimal set.

Virtual Application and Redirects

Describe the bug

Our application is installed on-premise in various locations. On some places the application is hosted in the root of an IIS Website and in other places it is an Application under the root. Our migration path using this project would be to do the switcheroo: the current application would be moved to a new WebSite and the new Core application would take it's original place so the URLs stay the same.

When the application is a Website in IIS, this works pefectly. However, as a Virtual Application the redirects fail because the proxied application ignores the fact that the public URL lives under a path.

To Reproduce

Core Application: https://localhost/application
Webforms Application: https://localhost:666/redirect.aspx -> contains a redirect to ~/test.aspx

Navigate to https://localhost/application/redirect.aspx
-> Response: 302 to https://localhost/test.aspx

I would expect the Redirect to go to https://localhost/application/test.aspx

Further technical details

Please include the following if applicable:

ASP.NET Framework Application:

  • Technologies and versions used (i.e. MVC/WebForms/etc): WebForms, WebApi, MVC (the whole shebang)
  • .NET Framework Version: 4.8
  • IIS Version: 10.0.22000.675
  • Windows Version: 11

ASP.NET Core Application:

  • Targeted .NET version: 6.0
  • .NET SDK version: 6.0.300

An unhandled exception occurred while processing the request

Describe the bug

When using Sessionstate I get the above error injected into the page where I access a session variable. It seems to go away when I don't use the sessionstate, remove the [Session] attribute from the controller for that page (and the nobviously session values are not available)

To Reproduce

Just start the the app and go to a page that has [Session] added to the controller. See: repro github repo

Exceptions (if any)

System.Net.Http.HttpRequestException: Response status code does not indicate success: 404 (Not Found).
   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, ISessionMetadata metadata)
   at Microsoft.AspNetCore.SystemWebAdapters.SessionMiddleware.ManageStateAsync(HttpContext context, ISessionMetadata metadata)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Further technical details

Please include the following if applicable:

ASP.NET Framework Application:

  • Technologies and versions used (i.e. MVC/WebForms/etc): Webforms
  • .NET Framework Version: net48
  • IIS Version: IISExpress included with VS2022
  • Windows Version: Windows 11 Pro 21H2 22000.675

ASP.NET Core Application:

  • Targeted .NET version: net6.0
  • .NET SDK version: 6.0.300
  • NET runtime version: 6.0.5

Transition from web.config to appsettings

Incremental Configuration Migration

A lot of code uses System.Configuration.ConfigurationManager.[AppSettings|ConnectionStrings] and migrating away from that may be difficult. This is somewhat similar to HttpContext.Current as it is a static property that had always been available, and now the option to replace it requires rearchitecting things to use IOptions<> or some other pattern to propagate configuration.

As applications started to move to the cloud, ConfigurationManager didn't work as well as it expected all values to come from local sources. With .NET 4.7.1, .NET Framework added configuration buidlers that provide a way to populate the values of ConfigurationManager from different sources. This infrastructure is not available in the .NET Core implementation of System.Configuration.ConfigurationManager.

Potential directions

There are a number of potential directions we could go:

  1. Bring over configuration builders to .NET Core. This is potentially a lot of code that would mimic what IConfigurationSource does, but in a different way.
  2. Provide analyzers/codefixers to identify and refactor code using ConfigurationManager. This is difficult as the static AppSettings/ConnectionStrings doesn't have an analog and would probably require a sizeable refactoring to support.
  3. Enable IConfiguration and ConfigurationManager to stay in sync of what values they are exposing.

(3) appears to be the simplest option and will be the basis for this proposal.

Design Goals

This proposal is built on the following principles to enable an incremental configuration migration:

  1. Values must be able to be accessed via ConfigurationManager.[AppSettings|ConnectionStrings] so legacy code continues to function
  2. Values must be accessible via IConfiguration to facilitate migration away from ConfigurationManager
  3. Values must be able to be updated externally to the app (i.e. environment variables, AppService, etc)

The following are commonly discussed, but violate at least one of these principles:

  • Recommending replacing web.config with appsettings.json: This can solve (2) and (3), but fails to satisfy (1)
  • Support web.config being loaded by ConfigurationManager: By default, this file is not loaded, and must be renamed to [main-assembly].dll.config to be loaded. This can solve (1), but does not satisfy (2) or (3)
  • Support web.config as an IConfiguration source: This achieves (2) and (3), but fails to satisfy (1)
  • Continue using ConfigurationManager where you are, but update incrementally to IConfiguration: This fails all 3 principles

Proposal

A migration path can be created by combining the recommendations into a single approach:

  1. We add support for web.config/app.config as a source for IConfiguration
  2. We add support to update ConfigurationManager entries with values from IConfiguration (and potentially support reloading)

By supporting these two scenarios, we can enable users to use their current set up, but also have a pathway to migrate to IConfiguration as the data in both of the configuration storage systems will be the same.

Example

An example of how this could work is available here. The usage in a core app would be simple:

var builder = WebApplication.CreateBuilder(args);

// Register `web.config` for `IConfiguration`
builder.Configuration.AddWebConfig();

// Enable binding `IConfiguration` to `ConfigurationManager` (with potential for reloads
builder.Services.AddConfigurationManager();

Challenges

There are a few challenges with this:

  • System.Configuration.ConfigurationManager.ConnectionStrings is readonly. The POC works around this by some reflection trickery, but we would want to handle this better
  • If you link a file (i.e. web.config) from a separate project into the core project, it will work fine on publish. However, on F5 debug it will not find the web.config file because the content root is the project directory when debugging and not the published output.

Original Posting

When migrating to core, configuration is drastically different. In framework, people would often use web.config as the source of configuration, but in core, the source of configuration is composed from many sources. Out of the box, core will read from environment variables, appsettings.json, and command line. Additional sources are available from NuGet as well.

During a migration, with a framework and a core app running, this may cause a system to have to duplicate the configuration values and can create keeping them in sync. There are a few options we should explore to ensure this pathway is seemless:

  • Explore adding web.config as a potential source for configuration values
  • Point to using config builds in ASP.NET framework to move the source of the config to some other file

YARP Proxy Not Working With IIS Express

I'm able to load the new .net core endpoints like / and /home/privacy, but any requests back to my old .net MVC application, I'm just getting an error in the browser, "This page isn't working right now".

In the launchsettings.json I see the following. Both the old and new sites are indepentely accessible, I just can't access both sites through https://localhost:7266.

"profiles": {
    "Mouser_Web.Core": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7266;http://localhost:5266",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ReverseProxy__Clusters__fallbackCluster__Destinations__fallbackApp__Address": "https://www.oldsite.com:44333"
      }
    },

Is anything supposed to be filled out in the appsettings.json file in fallbackApp/Address section? And the Path is supposed to be **catch-all?

    "ReverseProxy": {
    "Routes": {
      "fallbackRoute": {
        "ClusterId": "fallbackCluster",
        "Order": "1",
        "Match": {
          "Path": "{**catch-all}"
        }
      }
    },
    "Clusters": {
      "fallbackCluster": {
        "Destinations": {
          "fallbackApp": {
            "Address": ""
          }
        }
      }
    }

ASP.NET Framework Application:
We are running .net 4.8 site with a mixture of MVC and Web Forms running out of the application. This old site uses IIS Express

ASP.NET Core Application:
.Net 6.0

Add AspNet Core side shim for System.Web.VirtualPathUtility

Summary

Add the System.Web.VirtualPathUtility class to systemweb adapters to allow the use from AspNet Core and class libraries whilst migrating an application.

Motivation and goals

Within our application we make use of this class, mainly to handle dynamic paths and in areas where we need to return absolute paths regardless of the request url (e.g. in webapi call, middleware, partial views etc.).

In scope

Handle the following methods on System.Web.VirtualPathUtility

namespace System.Web;

public static class VirtualPathUtility
{
  public static string Combine(string basePath, string relativePath);
  public static string GetDirectory(string virtualPath);
  public static string GetExtension(string virtualPath);
  public static string GetFileName(string virtualPath);
  public static bool IsAppRelative(string virtualPath);
  public static string MakeRelative(string fromPath, string toPath);
  public static string ToAbsolute(string virtualPath);
  public static string ToAppRelative(string virtualPath);
}

Out of scope

The overloads which allow you to include the applicationPath would not be needed (at least not for my project).

Risks / unknowns

Most of these functions relate to translating paths starting ~/ to the base url which should be available with #81 as HttpRuntime.AppDomainAppVirtualPath.
The naïve implementation could use UrlBuilder and/or combinations of StartsWith and SubString to implement the main functions.
The Get* methods would probably need to get the IFileProvider interface registered to get the appropriate physical file paths and names for virtual paths.
GetFileName and GetExtension should work regardless of whether the file resolved to a physical file or not.
Most of these functions are no longer in use in web applications since it is now common to have each web application at the root, rather than installed as a sub site in IIS so this is largely for legacy projects where these abstractions have not yet been removed, or where configuration files or similar use 'app relative paths' like ~/App_Data/myconfig.json

Examples

public static class ThemeClaims
{
	public static string GetThemeOrDefault(this ClaimsIdentity identity, string @default = "default")
	{
		var claim = identity?.FindFirst("myapp:Theme");
		if (claim is null) return @default;
		return claim.Value;
	}
}

public class ThemeModel
{
	public string Theme { get; set; } = 
		(System.Web.HttpContext.Current.User?.Identity as ClaimsIdentity).GetThemeOrDefault();
	public string ThemeURL { 
		get => System.Web.VirtualPathUtility
			.ToAbsolute($"~/custom/themes/{Theme}/theme.css"); 
	}
}

Response.End not working inside Razor Class Library

Describe the bug

Trying to use Response.End from a Controller inside a Razor Class Library causes the exception bellow.

To Reproduce

        app.MapControllerRoute(
                name: "DataDictionary",
                pattern: "{culture}/{area:exists}/{controller=Element}/{action=Index}/{dictionaryName?}/")
            .PreBufferRequestStream().BufferResponseStream();
        app.MapControllerRoute(
                name: "MasterData",
                pattern: "{culture}/{area:exists}/{controller=Log}/{action=Index}/{dictionaryName?}/")
            .PreBufferRequestStream().BufferResponseStream();

Exceptions (if any)

Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HMJ5RQTKTINH", Request id "0HMJ5RQTKTINH:00000175": An unhandled exception was thrown by the application.
System.InvalidOperationException: Headers are read-only, response has already started.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpHeaders.ThrowHeadersReadOnlyException()
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseHeaders.Microsoft.AspNetCore.Http.IHeaderDictionary.set_ContentType(StringValues value)
at Microsoft.AspNetCore.Http.DefaultHttpResponse.set_ContentType(String value)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable1 statusCode) at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable1 statusCode)
at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)
at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.SystemWebAdapters.BufferResponseStreamMiddleware.BufferResponseStreamAsync(HttpContext context, IHttpResponseBodyFeature feature, IBufferResponseStreamMetadata metadata)
at Microsoft.AspNetCore.SystemWebAdapters.PreBufferRequestStreamMiddleware.PreBufferAsync(HttpContext context, IPreBufferRequestStreamMetadata metadata)
at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.HandleException(HttpContext context, ExceptionDispatchInfo edi)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)


*ASP.NET Core Application*:
- Targeted .NET version:6.0
- .NET SDK version:6.0

Is not JSON serialization of the session state to limiting?

When ASP.NET session is using out of process storage the binary serialization is used as far as I know. I understand that binary serialization is very picky but with JSON serialization I am concerned about preserving internal state without any public representation.

I have done a test with System.Web.Script.Serialization.JavaScriptSerializer and adding parameter less constructor was required and private only field was lost in serialization/deserialization.

Binary serializer also supports the IDeserializationCallback Interface to enable the object recover from a serialized state. I wonder whether this interface used when deserializing objects.

I our company we have a rather large (~250 forms) Webforms application which is to be transformed in coming years. Side by side migration library could be a great help.

Migration tool doesn't save changes to ASP.NET Core project file that add the adapter libraries

When you run the migration tool on an ASP.NET project it creates a new ASP.NET Core project and then adds the adapter libraries and YARP packages to that project. However, the changes to the ASP.NET Core project file to add the package references aren't saved to disk.

Repro steps:

  • Create a new ASP.NET MVC project
  • Run "Migrate project" on the ASP.NET project
  • Open the generated ASP.NET Core project file in Notepad (not VS)

Expected results:

  • The project file has the adapter libraries and YARP project references

Actual results:

  • VS added the packages references (you can see them in VS) but didn't save them to disk
  • If you immediate try to close the solution after running the migration tool without running, building, or saving anything, then VS will complain that the ASP.NET Core project file has changes that need to be saved

Workaround:

  • Click Save All to persist the added package references

@abpiskunov

Analyzer for detecting use of Headers[int]

If someone is using the adapters and using Headers[int] we should flag it and tell them to index by string. This will also be seen if you enumerate the collection.

Low priority for now since we haven't seen it in the wild.

The controller for path '/systemweb-adapters/authenticate' was not found or does not implement IController

Using the blog post i was able to successfully get the authentication working on brand new sample app.

However when i tried to plug it into my legacy aspnet framework mvc app i got the following error, from the .Net core app.

System.IO.EndOfStreamException: Unable to read beyond the end of the stream.
   at System.IO.BinaryReader.InternalRead(Int32 numBytes)
   at System.IO.BinaryReader.ReadInt32()
   at System.Security.Claims.ClaimsPrincipal..ctor(BinaryReader reader)
   at Microsoft.AspNetCore.SystemWebAdapters.Authentication.RemoteAppAuthenticationResultFactory.CreateRemoteAppAuthenticationResultAsync(HttpResponseMessage response, RemoteAppAuthenticationOptions options)
   at Microsoft.AspNetCore.SystemWebAdapters.Authentication.RemoteAppAuthenticationService.AuthenticateAsync(HttpRequest originalRequest, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.SystemWebAdapters.Authentication.RemoteAppAuthenticationAuthHandler.GetRemoteAppAuthenticationResultAsync()
   at Microsoft.AspNetCore.SystemWebAdapters.Authentication.RemoteAppAuthenticationAuthHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I have found the following in the debug output of the .NET Framework app

The controller for path '/systemweb-adapters/authenticate' was not found or does not implement IController
ASP.NET Framework Application:

  • Technologies and versions used (i.e. MVC/WebForms/etc): MVC 5,WebApi, Autofac
  • .NET Framework Version: NET 4.72
  • IIS Version: Both IIS with a CNAME and IISexpress (Same error)
  • Windows Version: 11

ASP.NET Core Application:

  • Targeted .NET version: 6
  • .NET SDK version: 6

Enable ASP.NET Core app to share auth/identity decisions with ASP.NET app

Current tooling allows incremental migration to share ASP.NET authentication with an ASP.NET Core app for quick startup moving endpoints.

In addition to this existing functionality, it would be useful to be able to have the ASP.NET Core authenticate users and forward identity information to the ASP.NET app (in cases where it's necessary to fall back to the ASP.NET app to handle a request). This would allow developers to migrate authentication at any point in the migration process that was convenient instead of having to wait until all ASP.NET endpoints have been migrated first.

Instrument adapters to identify usage in apps

Summary

By instrumenting the adapters users can identify what the adapter usage looks like in their application given their actual loads.

Motivation and goals

Once a user has migrated their project to ASP.NET Core but is still using the adapters, it would be nice to understand how much of the adapters are being used and what the cost will look like to migrate off of them. By instrumenting the adapters with diagnostics that surface information about usage, a user can collect data and identify what their reliance on the adapters look like.

The main goal behind in providing the adapters is that it is difficult to move off of them while running on ASP.NET framework. The adapters have a bit more flexibility while running on core to provide insights into their usage than could be obtained on framework. Because System.Web itself is essentially frozen and not serviceable, this kind of information would be difficult to instrument there. However, the adapters can provide this and will help identify what is actually being used.

In scope

We should use the types in System.Diagnostics.Activity to instrument code that can then be sent to wherever a user may be sending their personal telemetry. This can be AppInsights or any other service of the sort. By using the these types, we can be agnostic to what the service looks like, but provide information that could be useful.

We should emit an activity for each of the middlewares we provide to measure their impact and understand their usage:

  • SessionMiddleware
  • PreBufferRequestMiddleware
  • BufferResponseMiddleware
  • Additional ones as they are added

To understand how much a code base may be accessing the adapters, the events that would be helpful to emit on each access:

  • HttpContext.Current
  • HttpContext.Items
  • HttpContext.Request
  • HttpContext.Response
  • HttpContext.Cache
  • HttpContext.Session

Other potentially useful items:

  • Emit an event for each session key that is retrieved or added

Out of scope

We don't want to go to fine-grained on this as emitting the events has a cost, even if the activity source is not available. Starting with the high level events of general usage and soliciting feedback on if there's others that make sense.

Risks / unknowns

We would want to minimize any data being exposed beyond what is necessary due to privacy concerns.

Examples

This would be hooked up as any OpenTelemetry would (see https://devblogs.microsoft.com/dotnet/opentelemetry-net-reaches-v1-0/ for details). Once hooked up, a trace for a request will provide information that can be analyzed using industry tools. An example where the data is funneled into Zipkin is shown below:

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.