--- lang: ja-jp breaks: true --- # ASP.NET Core `AddDefaultIdentity` を使用したアカウントの確認時に「No page named '/Index' matches the supplied values.」が発生する 2023-06-23 ![](https://hackmd.io/_uploads/rJoDVKzuh.png) ```shell= An unhandled exception occurred while processing the request. InvalidOperationException: No page named '/Index' matches the supplied values. Microsoft.AspNetCore.Mvc.Infrastructure.RedirectToPageResultExecutor.ExecuteAsync(ActionContext context, RedirectToPageResult result) ``` ```shell= InvalidOperationException: No page named '/Index' matches the supplied values. Microsoft.AspNetCore.Mvc.Infrastructure.RedirectToPageResultExecutor.ExecuteAsync(ActionContext context, RedirectToPageResult result) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync<TFilter, TFilterAsync>() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) ``` ```shell= Show raw exception details System.InvalidOperationException: No page named '/Index' matches the supplied values. at Microsoft.AspNetCore.Mvc.Infrastructure.RedirectToPageResultExecutor.ExecuteAsync(ActionContext context, RedirectToPageResult result) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]() --- End of stack trace from previous location --- 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.<InvokeNextResourceFilter>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.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context) ``` ## 発生環境 * Visual Studio 2022 * Blazor Server * スキャフォールディングは一切行っていない状態 * メール送信にSendGridを使用 ## 発生状況 メール確認の本文にあるリンクをクリックすると発生する。 ![](https://hackmd.io/_uploads/rk5sBFzd3.png) ## 参考資料 > RegisterConfirmation failing > https://learn.microsoft.com/en-us/answers/questions/1254239/registerconfirmation-failing ## 調査 ### `ConfirmEmail`をスキャフォールディングし、デバッグ実行 ![](https://hackmd.io/_uploads/B1_bsFG_3.png) `userID`には値が入っているが、`code`が`null`となっていることで発生していた。 ![](https://hackmd.io/_uploads/HkK1CKGOn.png) ### `Confirm your email`の本文にある`a`タグのURL中の`&`がエンコードされて`&amp;`となっていることで`code`が取得出来なかった模様 ``` Please confirm your account by <a href='https://localhost:7199/Identity/Account/ConfirmEmail?userId=1f19a918-5154-49ce-aaf7-0721b2ef0564&amp;code=Q2ZESjhLek1mczlxcDROS253Z2U4K05QS1NZbWRsY0N1SytNUTFIQ01QU24veWJNSHE1THg4SlVodzZibWlRbXNCMUlhamFBUGc0dFUvZWNTcDdNSTF6dlplYTMzUW9TZWRJUm5PclJsWi9wam13UWhaM3dXRzA2UVRXb0owUllTSDNDRFZndkFzU2M0MVpLdG5GRkdGMlBhZXpUUm0wcDBpUEZLa2U0dUJGTU10Yy9vbDQvS0QrbmpVVFBLcFgyVVVCUi9nbGNkNUtKQzd0U1hYRS9LckhJNkVab3VMMXJtbXZuMkxLS054VEpPOWxMR05HeXN6ejdkaEtrNTZkMWFQb0xXQT09&amp;returnUrl=%2F'>clicking here</a>. ``` トラブルの元となる為、HTMLメールは送信しないほうがよさそう。。。スマホからだとHTMLメールの方が便利か。。。 ### 該当のソースコード > src/Identity/UI/src/Areas/Identity/Pages/V5/Account/Register.cshtml.cs > https://github.com/dotnet/aspnetcore/blob/da8a6f0766d1f333cc2faec72f97751e3c605dac/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/Register.cshtml.cs#L149C20-L149C20 :::info `HtmlEncoder.Default.Encode`されている。 ::: ![](https://hackmd.io/_uploads/S11ra6M_2.png) ### 一時しのぎの対応 メール送信部分で、メール本文をHTMLデコードすることでとりあえずは動作する。 ```csharp= public class EmailSender : IEmailSender { private readonly ILogger _logger; public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor, ILogger<EmailSender> logger) { Options = optionsAccessor.Value; _logger = logger; } public AuthMessageSenderOptions Options { get; } //Set with Secret Manager. public async Task SendEmailAsync( string toEmail, string subject, string message ) { if (string.IsNullOrEmpty(Options.SendGridKey)) { throw new Exception("Null SendGridKey"); } await Execute(Options.SendGridKey, subject, message, toEmail); } public async Task Execute( string apiKey, string subject, string message, string toEmail ) { var client = new SendGridClient(apiKey); var from = new EmailAddress( Options.FromEmail, Options.FromEmailName ); var to = new EmailAddress(toEmail, ""); // 確認用のURLに `&amp;` が含まれるのでデコードする。 var plainTextContent = HttpUtility.HtmlDecode(message); _logger.LogInformation($"[{subject}]"); _logger.LogInformation($"[{plainTextContent}]"); // HTMLメールはそのまま string htmlContent = message; SendGridMessage msg = MailHelper.CreateSingleEmail( from, to, subject, plainTextContent, htmlContent ); // Disable click tracking. // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html msg.SetClickTracking(false, false); var response = await client.SendEmailAsync(msg); _logger.LogInformation(response.IsSuccessStatusCode ? $"Email to {toEmail} queued successfully!" : $"Failure Email to {toEmail}"); } } ```