Skip to main content Home Creators microsoft upgrade-agent-plugins migrating-owin-to-aspnet-core
migrating-owin-to-aspnet-core Migrates OWIN/Katana middleware, authentication, pipeline components, and SignalR 2.x to native ASP.NET Core equivalents. Use when projects reference Microsoft.Owin, IAppBuilder, OwinMiddleware, Microsoft.Owin.Host.SystemWeb, OWIN-based OAuth/cookie/bearer authentication, OWIN startup classes, or SignalR 2.x hubs mapped via OWIN. Triggers for "migrate OWIN", "remove OWIN", "replace OWIN middleware", "convert OWIN pipeline", "migrate Katana", "convert OWIN auth", "upgrade SignalR", "replace OWIN startup", or when assessment signals include UsesOwin, UsesKatana, UsesOwinAuth, UsesOwinMiddleware, or UsesAppBuilder.
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/microsoft/upgrade-agent-plugins --skill migrating-owin-to-aspnet-coreThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository migrating-csharp-nullable-references Enable nullable reference types in a C# project and systematically resolve all warnings. Use when adopting NRTs in existing codebases, performing file-by-file or project-wide nullable migration, fixing CS8602/CS8618/CS86xx warnings, annotating APIs for nullability, cleaning up null-forgiving operators, or upgrading dependencies with new nullable annotations. Also use when the user asks to "enable nullable", "turn on NRTs", "annotate for nullability", "fix nullable warnings", or "migrate to nullable reference types". DO NOT USE FOR: projects already fully migrated with zero warnings (unless auditing suppressions), fixing a handful of nullable warnings in code that already has NRTs enabled, suppressing warnings without fixing them, C# 7.3 or earlier projects. INVOKES: Get-NullableReadiness.ps1 scanner script.
managing-shared-database-schema Governs a SQL database that two hosts read and write at the same time during a side-by-side migration. Use when a legacy .NET Framework app and a new .NET app share one database, point at the same connection string, or must both stay live while the schema changes. Covers which toolchain owns schema changes, expand-then-contract (additive-only) evolution, dual-write and backfill ordering, deployment ordering, and rollback rules. Triggers for "shared database", "who runs migrations", "dual write", "zero downtime schema change", or "add a column safely". Applies to EF6, EF Core, Dapper, ADO.NET, DACPAC/SqlPackage, DbUp and Flyway, and explains how EF6's __MigrationHistory and EF Core's __EFMigrationsHistory coexist without merging. Also use before deleting a Migrations folder, before enabling Database.Migrate() at startup, or when asked whether renaming or dropping a column is safe while the old app is live.
migrating-edmx-to-code-first Migrates Entity Framework 6 EDMX-based models (Database-First/Model-First) to EF Core Code-First. Use when upgrading projects containing .edmx files, .Context.tt templates, EntityClient connection strings, or ObjectContext references. Triggers for "migrate EDMX", "convert EDMX to code first", "EF6 to EF Core", "remove EDMX", "database first to code first", and "scaffold DbContext". Also relevant when encountering EntitySQL, EntityObject, or ObjectSet patterns during .NET modernization.
Related occupations SOC
Based on SOC occupation classification
name migrating-owin-to-aspnet-core description Migrates OWIN/Katana middleware, authentication, pipeline components, and SignalR 2.x to native ASP.NET Core equivalents. Use when projects reference Microsoft.Owin, IAppBuilder, OwinMiddleware, Microsoft.Owin.Host.SystemWeb, OWIN-based OAuth/cookie/bearer authentication, OWIN startup classes, or SignalR 2.x hubs mapped via OWIN. Triggers for "migrate OWIN", "remove OWIN", "replace OWIN middleware", "convert OWIN pipeline", "migrate Katana", "convert OWIN auth", "upgrade SignalR", "replace OWIN startup", or when assessment signals include UsesOwin, UsesKatana, UsesOwinAuth, UsesOwinMiddleware, or UsesAppBuilder.
metadata {"traits":".NET|CSharp|VisualBasic|DotNetCore","discovery":"lazy"}
OWIN / Katana → ASP.NET Core Middleware Migration
Overview
Migrate ASP.NET MVC applications that rely on OWIN/Katana for middleware hosting, authentication, and SignalR from the Katana pipeline to native ASP.NET Core middleware. Katana (Microsoft.Owin.Host.SystemWeb) ran an OWIN pipeline inside IIS before the MVC pipeline — ASP.NET Core unifies both into a single middleware pipeline, making the OWIN layer unnecessary. Covers all OWIN middleware patterns: custom OwinMiddleware subclasses, IAppBuilder pipeline configuration, OWIN authentication schemes, and SignalR 2.x hub migration.
Workflow
Migration Progress:
- [ ] Step 1: Audit OWIN/Katana usage
- [ ] Step 2: Migrate OWIN startup to Program.cs
- [ ] Step 3: Convert OWIN authentication to Core auth
- [ ] Step 4: Migrate SignalR 2.x to ASP.NET Core SignalR
- [ ] Step 5: Convert custom OWIN middleware
- [ ] Step 6: Remove Katana packages and clean up
Step 1: Audit OWIN/Katana Usage
Search the project for Katana and OWIN dependencies. If none are found, inform the user and skip this skill.
[assembly: OwinStartup(typeof(...))] attribute in Startup.cs or AssemblyInfo
Startup.Configuration(IAppBuilder app) or Startup.ConfigureAuth(IAppBuilder app) methods
Microsoft.Owin.Host.SystemWeb package reference (Katana IIS host)
Microsoft.Owin.Security.* packages (OWIN auth middleware)
Microsoft.AspNet.SignalR and Microsoft.AspNet.SignalR.Owin packages
app.MapSignalR() calls in OWIN startup
Startup.Auth.cs partial class files
Categorize findings into three groups:
Pipeline/hosting — Katana startup, IAppBuilder configuration
Authentication — OAuth, cookie, bearer, external sign-in middleware
SignalR — Hub classes, hub configuration, client scripts
Step 2: Migrate OWIN Startup to Program.cs The Katana startup class splits across Startup.cs and often Startup.Auth.cs. ASP.NET Core consolidates this into Program.cs.
Before — Katana startup with IAppBuilder:
[assembly: OwinStartup(typeof(MyApp.Startup)) ]
namespace MyApp
{
public partial class Startup
{
public void Configuration (IAppBuilder app )
{
ConfigureAuth(app);
app.MapSignalR();
app.Use<RequestLoggingMiddleware>();
}
}
}
After — ASP.NET Core Program.cs:
var builder = WebApplication.CreateBuilder(args );
builder.Services.AddAuthentication();
builder.Services.AddSignalR();
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<RequestLoggingMiddleware>();
app.MapHub<ChatHub>("/chatHub" );
app.MapControllerRoute(name: "default" , pattern: "{controller=Home}/{action=Index}/{id?}" );
app.Run();
Remove the [assembly: OwinStartup] attribute and the old Startup class once all configuration has moved to Program.cs.
Step 3: Convert OWIN Authentication to Core Auth OWIN authentication middleware registers inline on IAppBuilder. ASP.NET Core splits authentication into service registration (builder.Services) and middleware (app.Use*). Convert each OWIN auth scheme:
Cookie Authentication Before — OWIN cookie auth:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login" ),
ExpireTimeSpan = TimeSpan.FromDays(14 )
});
After — ASP.NET Core cookie auth:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Account/Login" ;
options.ExpireTimeSpan = TimeSpan.FromDays(14 );
});
OAuth Bearer / JWT Before — OWIN bearer auth:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenFormat = new JwtFormat(tokenValidationParameters, issuer)
});
After — ASP.NET Core JWT bearer:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true ,
ValidIssuer = "https://myissuer.example.com" ,
ValidateAudience = true ,
ValidAudience = "my-api" ,
ValidateLifetime = true ,
IssuerSigningKey = new SymmetricSecurityKey(keyBytes)
};
});
External Sign-In / OAuth Server Before — OWIN external sign-in:
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseGoogleAuthentication(clientId: "..." , clientSecret: "..." );
After — ASP.NET Core external auth:
builder.Services.AddAuthentication()
.AddCookie()
.AddGoogle(options =>
{
options.ClientId = builder.Configuration["Auth:Google:ClientId" ];
options.ClientSecret = builder.Configuration["Auth:Google:ClientSecret" ];
});
OWIN OAuth Authorization Server If the project hosts its own OAuth token endpoint via app.UseOAuthAuthorizationServer(), this has no built-in ASP.NET Core equivalent. Replace with a dedicated identity server library (OpenIddict or Duende IdentityServer). This is a significant architectural change — flag it to the user and provide guidance:
Add the chosen library's NuGet packages
Configure token endpoints, scopes, and client registrations
Migrate token validation parameters from the old OAuthAuthorizationServerOptions
Update client applications to use the new token endpoint URLs
Step 4: Migrate SignalR 2.x to ASP.NET Core SignalR SignalR 2.x (OWIN-hosted) and ASP.NET Core SignalR share concepts but differ in API surface, client library, and connection lifecycle.
Hub Class Changes Before — SignalR 2.x hub:
using Microsoft.AspNet.SignalR;
public class ChatHub : Hub
{
public void Send (string name, string message )
{
Clients.All.broadcastMessage(name, message);
}
public override Task OnConnected ()
{
Groups.Add(Context.ConnectionId, "general" );
return base .OnConnected();
}
}
After — ASP.NET Core SignalR hub:
using Microsoft.AspNetCore.SignalR;
public class ChatHub : Hub
{
public async Task Send (string name, string message )
{
await Clients.All.SendAsync("BroadcastMessage" , name, message);
}
public override async Task OnConnectedAsync ()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "general" );
await base .OnConnectedAsync();
}
}
Clients.All.broadcastMessage(...) → Clients.All.SendAsync("BroadcastMessage", ...)
Dynamic proxy calls become string-based SendAsync invocations
OnConnected → OnConnectedAsync, OnDisconnected(bool) → OnDisconnectedAsync(Exception)
Groups.Add() → Groups.AddToGroupAsync()
Hub Registration app.MapSignalR();
app.MapSignalR("/messaging" , new HubConfiguration());
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chatHub" );
Each hub is mapped individually in ASP.NET Core instead of a single MapSignalR() call. Map each hub class to its own route path.
IHubContext Injection Before — SignalR 2.x static resolver:
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
context.Clients.All.broadcastMessage("system" , "Hello" );
After — ASP.NET Core dependency injection:
public class NotificationService
{
private readonly IHubContext<ChatHub> _hubContext;
public NotificationService (IHubContext<ChatHub> hubContext )
{
_hubContext = hubContext;
}
public async Task NotifyAll (string message )
{
await _hubContext.Clients.All.SendAsync("BroadcastMessage" , "system" , message);
}
}
Client Library Replace the old jQuery-based SignalR client with the @microsoft/signalr npm package:
Before — SignalR 2.x client:
<script src ="~/Scripts/jquery.signalR-2.4.3.min.js" > </script >
<script src ="~/signalr/hubs" > </script >
<script >
var hub = $.connection.chatHub ;
hub.client .broadcastMessage = function (name, message ) { };
$.connection.hub .start ();
</script >
After — ASP.NET Core SignalR client:
<script src ="~/lib/microsoft/signalr/dist/browser/signalr.min.js" > </script >
<script >
const connection = new signalR.HubConnectionBuilder ()
.withUrl ("/chatHub" )
.build ();
connection.on ("BroadcastMessage" , (name, message ) => { });
connection.start ();
</script >
The auto-generated /signalr/hubs proxy no longer exists. Client method names are registered explicitly with connection.on().
Step 5: Convert Custom OWIN Middleware For each custom OwinMiddleware subclass, convert to ASP.NET Core middleware. The core pattern change is constructor injection of RequestDelegate replacing the OwinMiddleware base class:
Before — OWIN middleware:
public class RequestTimingMiddleware : OwinMiddleware
{
public RequestTimingMiddleware (OwinMiddleware next ) : base (next ) { }
public override async Task Invoke (IOwinContext context )
{
var sw = Stopwatch.StartNew();
await Next.Invoke(context);
sw.Stop();
context.Response.Headers.Add("X-Timing" , new [] { sw.ElapsedMilliseconds.ToString() });
}
}
After — ASP.NET Core middleware:
public class RequestTimingMiddleware
{
private readonly RequestDelegate _next;
public RequestTimingMiddleware (RequestDelegate next )
{
_next = next;
}
public async Task InvokeAsync (HttpContext context )
{
var sw = Stopwatch.StartNew();
await _next(context);
sw.Stop();
context.Response.Headers["X-Timing" ] = sw.ElapsedMilliseconds.ToString();
}
}
Register in Program.cs with app.UseMiddleware<RequestTimingMiddleware>();.
Step 6: Remove Katana Packages and Clean Up
Remove all Katana and OWIN NuGet packages from project files:
Microsoft.Owin
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security
Microsoft.Owin.Security.Cookies
Microsoft.Owin.Security.OAuth
Microsoft.Owin.Security.Google (and other provider-specific packages)
Microsoft.AspNet.SignalR
Microsoft.AspNet.SignalR.Owin
Owin
Delete Startup.cs and Startup.Auth.cs if all logic has moved to Program.cs
Remove the [assembly: OwinStartup(...)] attribute from AssemblyInfo or Startup.cs
Delete old SignalR client scripts (jquery.signalR-*.js) from Scripts/ or wwwroot/
Search for remaining using Microsoft.Owin and using Microsoft.AspNet.SignalR directives and remove them
OWIN → ASP.NET Core API Reference OWIN / Katana ASP.NET Core IAppBuilderIApplicationBuilder (via WebApplication)app.Use() (OWIN delegate)app.Use() (Core delegate) or app.UseMiddleware<T>()OwinMiddlewareMiddleware class with RequestDelegate IOwinContextHttpContextStartup.Configuration(IAppBuilder)Program.cs pipeline[assembly: OwinStartup]Not needed — Program.cs is the entry point app.UseCookieAuthentication()AddAuthentication().AddCookie()app.UseOAuthBearerAuthentication()AddAuthentication().AddJwtBearer()app.UseExternalSignInCookie()AddAuthentication().AddCookie() + .AddGoogle() / etc.app.UseOAuthAuthorizationServer()OpenIddict or Duende IdentityServer app.MapSignalR()app.MapHub<T>("/path")GlobalHost.ConnectionManagerIHubContext<T> via DIHub.Clients.All.method()Hub.Clients.All.SendAsync("Method", ...)Groups.Add()Groups.AddToGroupAsync()
Success Criteria
No Microsoft.Owin.*, Owin, or Microsoft.AspNet.SignalR package references remain
No IAppBuilder, IOwinContext, OwinMiddleware, or OwinStartup references in code
Authentication uses ASP.NET Core AddAuthentication() service pattern
SignalR hubs use Microsoft.AspNetCore.SignalR with SendAsync pattern
SignalR client uses @microsoft/signalr instead of jquery.signalR
Custom middleware uses RequestDelegate and InvokeAsync(HttpContext) pattern
All middleware is registered in Program.cs
Project builds without errors