abpframework / abp

Open Source Web Application Framework for ASP.NET Core. Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET and the ASP.NET Core platforms. Provides the fundamental infrastructure, production-ready startup templates, application modules, UI themes, tooling, guides and documentation.
https://abp.io
GNU Lesser General Public License v3.0
12.31k stars 3.32k forks source link

How to create local Identity User when using AAD? #2815

Closed Znow closed 4 years ago

Znow commented 4 years ago

Hi,

As asked in a previous issue #2614 , I would like to request help on how to create a user in the DB, when signing in with AAD.

I have implemented the AAD logic in ProjectNameWebModule.cs "ConfigureAuthentication"-method, but how can in here, when "OnTokenValidated", create a user, if it does not exist in the DB?

So I can login a user when logging in with AAD? :-)

Thanks in advance,

Regards

gterdem commented 4 years ago

You are looking for Signin with External Provider. Did you check the documentation?

Znow commented 4 years ago

@gterdem I have implemented signin with AAD... So what I need is to create a local user, when a user signs in with AAD, so I can bypass the other login mechanism, enforced by ABP? :-)

gterdem commented 4 years ago

@Znow So you connected AAD as External OIDC provider (like google, facebook etc), seeing as external provider in your login page right? When user selects Login with AAD (or whatever you named it), it will be redirected to AAD login page to sign in. After user logs in to AAD Login page successfully; If user is logging to your app first time, external registry screen will be displayed; asking email address to save (you can modify as you like). So your new user will be created on this step.

Abp uses aspnet identity underneath so you can make any modifications you want in registry or login flow as in aspnet identity.

Znow commented 4 years ago

@gterdem Thanks alot - I can now see a "Azure AD login"-button on my Login page. Buuut, with correct setup in WebModule file, I am being thrown this error:

image

I have seen this error several times before also with Azure AD integration

hikalkan commented 4 years ago

I suppose the problem is that AD sets user id claim which is obviously not a GUID and the ABP framework tries to read it as GUID. You should somehow change this claim to another one (after return from the AD).

Znow commented 4 years ago

@hikalkan I have a total standard implementation, so can't see how I should or can change this? :-)

hikalkan commented 4 years ago

We can work on that to see details, but unfortunately now in this week (because we will release 2.1 in this week). If you have time, we can better help on this. I believe this is needed by many developers.

Znow commented 4 years ago

@hikalkan I can sure try to help, but please try and point me in some direction. I'm not that much into how Identity Server 4 works.

gterdem commented 4 years ago

@Znow Let's go step by step to troubleshoot and debug; Here are some steps I tried to reproduce your issue but since I don't have AAD i couldn't reproduce; maybe it can help for you.

Create a page to override current login logic and override CreateExternalUserAsync method

[ExposeServices(typeof(LoginModel))]
public class MyLoginModel : IdentityServerSupportedLoginModel
{
        public MyLoginModel(IAuthenticationSchemeProvider schemeProvider, IOptions<AbpAccountOptions> accountOptions,
                            IIdentityServerInteractionService interaction, IClientStore clientStore,
                            IEventService identityServerEvents) 
            : base(schemeProvider, accountOptions, interaction, clientStore, identityServerEvents)
        {
        }
        protected override async Task<IdentityUser> CreateExternalUserAsync(ExternalLoginInfo info)
        {
            return base.CreateExternalUserAsync(info);
        }
}

Lets replace return base.CreateExternalUserAsync(info); with the source code https://github.com/abpframework/abp/blob/037ef9abe024c03c1f89ab6c933710bcfe3f5c93/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs#L206-L217 And you can put a debugger to see which claim causes the issue.

protected override async Task<IdentityUser> CreateExternalUserAsync(ExternalLoginInfo info)
        {
            var emailAddress = info.Principal.FindFirstValue(AbpClaimTypes.Email);

            var user = new IdentityUser(GuidGenerator.Create(), emailAddress, emailAddress, CurrentTenant.Id);

            CheckIdentityErrors(await UserManager.CreateAsync(user));
            CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress));
            CheckIdentityErrors(await UserManager.AddLoginAsync(user, info));

            return user;
        }

Let me know what causes the problem for you so we can make improvements about it.

Znow commented 4 years ago

@gterdem Thanks, I will look at it today or tomorrow and give you an update

Znow commented 4 years ago

@gterdem Could you please provide an example of your source code? I have trouble with getting the method to be debugged.

image

gterdem commented 4 years ago

@Znow Remember this will hit only once after returning from SSO (AAD login page in your case) if the user doesn't exist in your db.

var emailAddress = info.Principal.FindFirstValue(AbpClaimTypes.Email); Could you be able to debug this line down to user creation?

I don't have AAD SSO, but i tested with a IdentityServer external login. Explain the flow if you are having trouble debugging please.

Znow commented 4 years ago

@gterdem

From my exhibit in previous comment, the method is not being debugged at all, no breakpoint are being hit.

These are my steps:

  1. Start project and run website
  2. Access /account/login
  3. Microsoft login page shows
  4. Enter credentials, and the click "Login", below is being shown image

XWebModule.cs

private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
        {
            context.Services.AddAuthentication()
                .AddIdentityServerAuthentication(options =>
                {
                    options.Authority = configuration["AuthServer:Authority"];
                    options.RequireHttpsMetadata = false;
                    options.ApiName = "Preact";
                });

            #region Azure Auth
            context.Services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            context.Services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
                    .AddAzureAD(options => configuration.Bind("AzureAd", options));

            context.Services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
            {
                options.Authority = options.Authority + "/v2.0/";         // Microsoft identity platform

                options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants (here simplified)
            });

            context.Services.AddMvc(options =>
            {
                var policy = new AuthorizationPolicyBuilder()
                                .RequireAuthenticatedUser()
                                .Build();
                options.Filters.Add(new AuthorizeFilter(policy));
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
            #endregion
        }
Znow commented 4 years ago

@gterdem @ebicoglu @hikalkan
The fix that was made, solved the issue with not being able to login initially.

But now a new problem have arisen.

  1. Run project
  2. Azure AD (Microsoft) login page shows
  3. Login with AD credentials
  4. Logged in
  5. Application start page shows

So far so good.

But, I should actually be presented with the "/Account/Login"-page when I start the application, shouldn't I?

Because when I just get prompted for login with the Microsoft login page, no Identity user is created in the database, at all...

If I then access "/Account/Login", I will be presented with the login page: image

But if I click on "Azure Active Directory"-button, and thus should be logged in and have a local user created, nothing happens - I am being redirected to the same page... Even if I am correctly logged in with Azure AD

I am also getting alot of "Authorization failed", even after a "Authorization was successfull" in the logs.txt:

2020-03-05 12:01:54.991 +01:00 [INF] Request starting HTTP/2.0 GET https://localhost:44310/Account/Login application/x-www-form-urlencoded 
2020-03-05 12:01:54.993 +01:00 [INF] Executing endpoint '/Account/Login'
2020-03-05 12:01:54.993 +01:00 [INF] Route matched with {page = "/Account/Login", action = "", controller = "", area = ""}. Executing page /Account/Login
2020-03-05 12:01:54.993 +01:00 [INF] Authorization was successful.
2020-03-05 12:01:54.995 +01:00 [INF] Executing handler method Volo.Abp.Account.Web.Pages.Account.LoginModel.OnGetAsync - ModelState is "Valid"
2020-03-05 12:01:54.995 +01:00 [INF] Executed handler method OnGetAsync, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
2020-03-05 12:01:55.016 +01:00 [DBG] Added bundle 'Basic.Global' to the page in 0.77 ms.
2020-03-05 12:01:55.017 +01:00 [DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:NkKPJ479_9U5x7o_fX7SzBg8DAUErIgyKrFS4HZrBUU,n:AbpIdentity.Roles
2020-03-05 12:01:55.017 +01:00 [DBG] Found in the cache: pn:U,pk:NkKPJ479_9U5x7o_fX7SzBg8DAUErIgyKrFS4HZrBUU,n:AbpIdentity.Roles
2020-03-05 12:01:55.017 +01:00 [INF] Authorization failed.
2020-03-05 12:01:55.017 +01:00 [DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:NkKPJ479_9U5x7o_fX7SzBg8DAUErIgyKrFS4HZrBUU,n:AbpIdentity.Users
2020-03-05 12:01:55.017 +01:00 [DBG] Found in the cache: pn:U,pk:NkKPJ479_9U5x7o_fX7SzBg8DAUErIgyKrFS4HZrBUU,n:AbpIdentity.Users
2020-03-05 12:01:55.017 +01:00 [INF] Authorization failed.
2020-03-05 12:01:55.018 +01:00 [DBG] PermissionStore.GetCacheItemAsync: pn:U,pk:NkKPJ479_9U5x7o_fX7SzBg8DAUErIgyKrFS4HZrBUU,n:AbpTenantManagement.Tenants
2020-03-05 12:01:55.018 +01:00 [DBG] Found in the cache: pn:U,pk:NkKPJ479_9U5x7o_fX7SzBg8DAUErIgyKrFS4HZrBUU,n:AbpTenantManagement.Tenants
2020-03-05 12:01:55.018 +01:00 [INF] Authorization failed.
2020-03-05 12:01:55.021 +01:00 [DBG] Added bundle 'Basic.Global' to the page in 1.58 ms.
2020-03-05 12:01:55.021 +01:00 [INF] Executed page /Account/Login in 28.1609ms
2020-03-05 12:01:55.021 +01:00 [INF] Executed endpoint '/Account/Login'
2020-03-05 12:01:55.021 +01:00 [INF] Request finished in 30.127ms 200 text/html; charset=utf-8
Znow commented 4 years ago

@gterdem @ebicoglu @hikalkan bump - any update on this?

I can't even hit breakpoints when "overriding" Login.cshtml in "Pages/Account", with same code as from your repo:

image

yekalkan commented 4 years ago

@Znow

  <ItemGroup>
    <Content Remove="Pages\Account\Login.cshtml" />
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Include="Pages\Account\Login.cshtml" />
  </ItemGroup>
            Configure<AbpVirtualFileSystemOptions>(options =>
            {
                options.FileSets.AddEmbedded<MyProjectNameWebModule>("MyCompanyName.MyProjectName.Web");
            });
Znow commented 4 years ago

@yekalkan - Added - Same, still not hitting breakpoints in Login.cshtml.cs

Clicking the marked button, it just redirects to same page. image

yekalkan commented 4 years ago

image

I'm able to debug, following the steps above.

Znow commented 4 years ago

@yekalkan Okay, and what are your steps?

I am not hitting any breakpoints?

image

image

yekalkan commented 4 years ago

image

image

Same as yours. Does your project have MyCompanyName as prefix? If so, it is missing in AddEmbedded<MyProjectNameWebModule>("MyCompanyName.MyProjectName.Web"). Check it, just in case.

Znow commented 4 years ago

Nope it hasn't - it's just "X.Web" etc.

Znow commented 4 years ago

@yekalkan - Reading up on https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface told me that I should have my Login.cshtml.cs as below:

[Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(LoginModel))]
    public class MyLoginModel : LoginModel
    {

But with this, I get the error below when accessing "/Account/Login" (still no breakpoints being hit): image

Login.cshtml:

@page
@using Volo.Abp.Account.Settings
@using Volo.Abp.Settings
@model X.Web.Pages.Account.MyLoginModel
@inherits Volo.Abp.Account.Web.Pages.Account.AccountPage
@inject Volo.Abp.Settings.ISettingProvider SettingProvider
Znow commented 4 years ago

@yekalkan @gterdem @hikalkan Another observation - I cannot login with the standard local "admin" user when AAD login is enabled.... This seems to be a bug aswell, even if I have applied:

Appsettings.json

  "Settings": {
    "Abp.Account.EnableLocalLogin": "true" 

  }

UPDATE: @yekalkan Finally got the Login.cshtml and .cs file working - now I can debug. Please see the attached animated GIF. When I click on the "Azure Active Directory" (already logged in with AD account), it just returns "null" from SignInManager....

aadlogin

gterdem commented 4 years ago

@Znow Hello, sorry couldn't look into anything for sometime because of RL issues.

The problem is, there is no ClaimTypes.NameIdentifier (Microsoft Claim type of http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier) is provided by AzureAD. That's why you are getting SignInManager.GetExternalLoginInfoAsync() null.

Try overriding SignInManager and change the ClaimTypes.NameIdentifier to sub

https://github.com/aspnet/Identity/blob/feedcb5c53444f716ef5121d3add56e11c7b71e5/src/Identity/SignInManager.cs#L611

It should fix your problem.

Znow commented 4 years ago

@gterdem Hi, thanks for still looking into this.

Yeah, I got so far that I'm overriding SignInManager, and can debug GetExternalLoginInfoAsync(), but "auth" doesnt get me further:

image

Have tried for several hours to investigate the cause of not being signed in with AAD...

UPDATE: Got very much further by changing: CustomSignInManager.cs (commented lines)

public override async Task<ExternalLoginInfo> GetExternalLoginInfoAsync(string expectedXsrf = null)
        {
            //var auth = await Context.AuthenticateAsync(IdentityConstants.ExternalScheme);
            var auth = await Context.AuthenticateAsync();
            var items = auth?.Properties?.Items;
            if (auth?.Principal == null || items == null || !items.ContainsKey(LoginProviderKey))
            {
                return null;
            }

            if (expectedXsrf != null)
            {
                if (!items.ContainsKey(XsrfKey))
                {
                    return null;
                }
                var userId = items[XsrfKey] as string;
                if (userId != expectedXsrf)
                {
                    return null;
                }
            }

            //var providerKey = auth.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
            var providerKey = auth.Principal.Claims.FirstOrDefault(x => x.Type == "sub")?.Value;
            var provider = items[LoginProviderKey] as string;
            if (providerKey == null || provider == null)
            {
                return null;
            }

            var providerDisplayName = (await GetExternalAuthenticationSchemesAsync()).FirstOrDefault(p => p.Name == provider)?.DisplayName
                                      ?? provider;
            return new ExternalLoginInfo(auth.Principal, provider, providerKey, providerDisplayName)
            {
                AuthenticationTokens = auth.Properties.GetTokens()
            };
        }

Login.cshtml.cs (commented lines)

protected virtual async Task<IdentityUser> CreateExternalUserAsync(ExternalLoginInfo info)
        {
            //var emailAddress = info.Principal.FindFirstValue(AbpClaimTypes.Email);
            var emailAddress = info.Principal.Claims.FirstOrDefault(x => x.Type == "preferred_username")?.Value;

            var user = new IdentityUser(GuidGenerator.Create(), emailAddress, emailAddress, CurrentTenant.Id);

            CheckIdentityErrors(await UserManager.CreateAsync(user));
            CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress));
            CheckIdentityErrors(await UserManager.AddLoginAsync(user, info));

            return user;
        }

The user is now created in the DB, but not logged in directly after, which I need to investigate.

gterdem commented 4 years ago

@Znow Nice to hear you got it moving. It is signing in but authenticating against wrong scheme after user created. You may want to look into that.

I will try to reproduce the whole flow once I get time for it. It would be nice if you can put some code on a public repository when you are done so that we can troubleshoot better and help better.

Znow commented 4 years ago

@gterdem Ah, that enlightens some more, thanks! I can ofcourse create a public repo during today, thanks.

Reproducible repository: https://github.com/Znow/AbpAzureAdLogin

Znow commented 4 years ago

@hikalkan Why is it removed from 2.3? It's still an issue...

hikalkan commented 4 years ago
Znow commented 4 years ago

@gterdem I get signed in now with my Azure AD account - but ABP doesn't see me as signed in. I can see that there are cookies etc.

image

Znow commented 4 years ago

@gterdem Have you had a chance to look at the repo I created?

gterdem commented 4 years ago

Hello @Znow, I sent a PR to your repository. There are some problems with setting CurrentUser authenticated status while HttpContextUser is authenticated just fine.

I need to investigate further about schemes to find a viable solution to this AD External Login. Thanks for your patience.

Znow commented 4 years ago

@gterdem Yeah I saw it, and it's merged in already =)

Thanks alot for your help so far, really appreciate it.

Znow commented 4 years ago

@hikalkan - @gterdem was so kind and "solved" the issue, in the repository on my account, which I linked to previously, its a working solution now.

So I think this issue can be closed, if there are no stuff to be fixed in ABP.

Thanks

gterdem commented 4 years ago

@Znow Thanks Znow, I am glad if i could help. We fixed a problem on our side about guid generation. There will be blogpost about detailed AzureAD integration for abp Mvc app soon to help others having trouble with integration.

Guide release for How to Use the Azure Active Directory Authentication for MVC / Razor Page Applications.

Znow commented 4 years ago

@gterdem Seems there is still an issue occuring when deploying to production.

I have deployed the test repository I created to reproduce the error, which you forked and created PR for.

image

2020-05-07 10:15:21.460 +00:00 [ERR] An unhandled exception has occurred while executing the request.
System.ArgumentNullException: Value cannot be null. (Parameter 'userName')
   at Volo.Abp.Check.NotNull[T](T value, String parameterName)
   at Volo.Abp.Identity.IdentityUser..ctor(Guid id, String userName, String email, Nullable`1 tenantId)
   at Volo.Abp.Account.Web.Pages.Account.LoginModel.CreateExternalUserAsync(ExternalLoginInfo info)
   at Volo.Abp.Account.Web.Pages.Account.LoginModel.OnGetExternalLoginCallbackAsync(String returnUrl, String returnUrlHash, String remoteError)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Convert[T](Object taskAsObject)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_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>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Volo.Abp.AspNetCore.Serilog.AbpSerilogMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Volo.Abp.AspNetCore.Auditing.AbpAuditingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at IdentityServer4.Hosting.IdentityServerMiddleware.Invoke(HttpContext context, IEndpointRouter router, IUserSession session, IEventService events)
   at IdentityServer4.Hosting.MutualTlsTokenEndpointMiddleware.Invoke(HttpContext context, IAuthenticationSchemeProvider schemes)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at IdentityServer4.Hosting.BaseUrlMiddleware.Invoke(HttpContext context)
   at Volo.Abp.AspNetCore.MultiTenancy.MultiTenancyMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass5_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Builder.ApplicationBuilderAbpJwtTokenMiddlewareExtension.<>c__DisplayClass0_0.<<UseJwtTokenMiddleware>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
gterdem commented 4 years ago

@Znow hello,

Can you create a new issue explaining with reproduce steps.

Thanks.