Mvc: Injecting IViewLocalizer into Razor Page causing IndexOutOfRangeException.

Created on 22 Aug 2017  路  7Comments  路  Source: aspnet/Mvc

From https://github.com/aspnet/Localization/issues/407

Title

When injecting IViewLocalizer using @inject directive into any Razor Page (not using MVC), System.IndexOutOfRangeException: Index was outside the bounds of the array. will be thrown.

Minimal repro steps

See this repo.

Expected result

The page should load successfully without ant error.

Actual result

The following error was thrown:

fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
      An unhandled exception has occurred: Index was outside the bounds of the array.
System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at Microsoft.AspNetCore.Mvc.Localization.ViewLocalizer.BuildBaseName(String path)
   at Microsoft.AspNetCore.Mvc.Localization.ViewLocalizer.Contextualize(ViewContext viewContext)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.RazorPagePropertyActivator.<>c__DisplayClass8_0.<CreateActivateInfo>b__1(ViewContext context)
   at Microsoft.Extensions.Internal.PropertyActivator`1.Activate(Object instance, TContext context)
   at Microsoft.AspNetCore.Mvc.Razor.Internal.RazorPagePropertyActivator.Activate(Object page, ViewContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.DefaultPageFactoryProvider.<>c__DisplayClass4_0.<CreatePageFactory>b__0(PageContext pageContext, ViewContext viewContext)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.<InvokeHandlerMethodAsync>d__29.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.<InvokeNextPageFilterAsync>d__31.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Internal.PageActionInvoker.<InvokeInnerFilterAsync>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeNextResourceFilter>d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeFilterPipelineAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.<InvokeAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>d__6.MoveNext()
3 - Done bug

All 7 comments

Looks like the issue steams from us not setting the ViewContext.ExecutingFilePath when rendering a Razor Page. One possible workaround until we fix this would be to replace the Page Factory provider to set the value:

```C#
using System;
using System.Diagnostics;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
public class LocFixPageFactoryProvider : DefaultPageFactoryProvider
{
public LocFixPageFactoryProvider(
IPageActivatorProvider pageActivator,
IModelMetadataProvider metadataProvider,
IUrlHelperFactory urlHelperFactory,
IJsonHelper jsonHelper,
DiagnosticSource diagnosticSource,
HtmlEncoder htmlEncoder,
IModelExpressionProvider modelExpressionProvider)
: base(pageActivator, metadataProvider, urlHelperFactory, jsonHelper, diagnosticSource, htmlEncoder, modelExpressionProvider)
{
}

    public override Func<PageContext, ViewContext, object> CreatePageFactory(CompiledPageActionDescriptor actionDescriptor)
    {
        var result = base.CreatePageFactory(actionDescriptor);
        return (pageContext, viewContext) =>
        {
            viewContext.ExecutingFilePath = actionDescriptor.RelativePath;
            return result(pageContext, viewContext);
        };
    }
}

}


And change your Startup to use this service:

services.AddSingleton();
services.AddMvc().
```

@Eilon \ @rynowak would this be a 2.0.1 worthy? The workaround isn't very pleasant.

Thanks for the workaround.

However, I still unable to show the localized string. I have done the following:

  1. services.AddLocalization(options => options.ResourcesPath = "Resources");
  2. services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, options => options.ResourcesPath = "Resources")
  3. Create Resources folder.
  4. Create RESX file inside the folder and name is as Pages.Index.en.resx by following the documentation here.
  5. Inside Pages/Index.cshtml file, I have set: ViewData["Title"] = Localizer["Home Page"];
  6. When running the project and navigate to the home page, the page title still show as 'Home Page' not 'Home Page in English' as I set in the RESX file.

For repro project, please see here and checkout to branch fix-test.

@Eilon self-assigning this for further investigation.

@zulfahmi93 I tried your fix-test branch and it prints the right localized string. Could you verify you're not running in to some sort of browser caching oddity?

@pranavkm sorry my bad. I tried to rerun it and now it's already working. Thanks for your help!

Thanks @zulfahmi93. We'll use this work item to track the actual fix.

@Eilon - this is a bug.

Was this page helpful?
0 / 5 - 0 ratings