Aspnetcore: View assembly location fails when path contains special characters

Created on 27 Sep 2019  ·  15Comments  ·  Source: dotnet/aspnetcore

I'm not sure this is really a bug in _asp.net_ or not but anyway,

As part of a service fabric deployment i have an app deployed in the following folder
C:\SFDevCluster\Data\_App\_Node_0\Fabric.AdminType_App121\Services.AdminPanelPkg.Code.5.29.0.3419f33.lu1b%2B%\ however when the app starts if failes to locate one of the view assemblies because its trying to use the following path C:\SFDevCluster\Data\_App\_Node_0\Fabric.AdminType_App121\Services.AdminPanelPkg.Code.5.29.0.3419f33.lu1b+%

In other words, its unescaping the folder path so that %2B is turned into + causing the lookup to fail.

Additional context

The exception it self:

``System.IO.FileNotFoundException: Related assembly 'Microsoft.AspNetCore.Authentication.AzureAD.UI.Views' specified by assembly 'Microsoft.AspNetCore.Authentication.AzureAD.UI' could not be found in the directory C:\SFDevCluster\Data\_App\_Node_0\Fabric.AdminType_App121\Services.AdminPanelPkg.Code.5.29.0.3419f33.lu1b+%. Related assemblies must be co-located with the specifying assemblies. File name: 'C:\SFDevCluster\Data\_App\_Node_0\Fabric.AdminType_App121\Services.AdminPanelPkg.Code.5.29.0.3419f33.lu1b+%\Microsoft.AspNetCore.Authentication.AzureAD.UI.Views.dll' at Microsoft.AspNetCore.Mvc.ApplicationParts.RelatedAssemblyAttribute.GetRelatedAssemblies(Assembly assembly, Boolean throwOnError, Func2 fileExists, Func2 loadFile) at Microsoft.AspNetCore.Mvc.ApplicationParts.RelatedAssemblyAttribute.GetRelatedAssemblies(Assembly assembly, Boolean throwOnError) at Microsoft.AspNetCore.Authentication.AzureADAuthenticationBuilderExtensions.GetAdditionalParts()+MoveNext() at Microsoft.AspNetCore.Authentication.AzureADAuthenticationBuilderExtensions.<>c__DisplayClass6_0.<AddAdditionalMvcApplicationParts>b__0(ApplicationPartManager apm) at Microsoft.Extensions.DependencyInjection.MvcCoreMvcBuilderExtensions.ConfigureApplicationPartManager(IMvcBuilder builder, Action1 setupAction)
at Microsoft.AspNetCore.Authentication.AzureADAuthenticationBuilderExtensions.AddAdditionalMvcApplicationParts(IServiceCollection services)
at Microsoft.AspNetCore.Authentication.AzureADAuthenticationBuilderExtensions.AddAzureAD(AuthenticationBuilder builder, String scheme, String openIdConnectScheme, String cookieScheme, String displayName, Action`1 configureOptions)


dotnet info:

```.NET Core SDK (reflecting any global.json):
 Version:   3.0.100
 Commit:    04339c3a26

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18985
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\3.0.100\

Host (useful for support):
  Version: 3.0.0
  Commit:  7d57652f33
Duplicate External Resolved area-mvc bug

Most helpful comment

Assembly.Location is strictly better than Assembly.CodeBase.

Assembly.CodeBase is obsolete property. The only reason why it was included in .NET Core was .NET Framework compatibility. The original purpose of Assembly.CodeBase was CAS (Code Access Security). It was meant to describe where the assembly was downloaded from for the Internet Zone security checks. It also explains some of its weird behaviors. For example, if the assembly is loaded as byte array, it returns the location of the caller of the Assembly.Load method.

All 15 comments

@terrajobst who would be the right person to ask about System.Reflection.Assembly? We have a couple of places in ASP.NET Core where we need to locate the assembly path on disk. We use Assembly.CodeBase instead of Assembly.Location because of shadow-copied assemblies ❓ . However, since CodeBase is a URI, we keep running in to strange issues trying to turn it back in to a file path.

a) Should we be using Assembly.Location instead?
b) If we must use Assembly.CodeBase, is there a canonical way to read the file path on disk.
c) Is there another property we've overlooked?

Spoke offline and in .NET Core Assembly.Location and Assembly.CodeBase should be equivalent. There's some concern about using Assembly.Location in general to do things (think of single file exes), but using Assembly.Location wouldn't leave us worse off.

@terrajobst who would be the right person to ask about System.Reflection.Assembly

I think @steveharter is the reflection owner these days.

Spoke offline and in .NET Core Assembly.Location and Assembly.CodeBase should be equivalent. There's some concern about using Assembly.Location in general to do things (think of single file exes), but using Assembly.Location wouldn't leave us worse off.

That is my understanding yes. @steveharter and @jkotas should double check what I told you :-)

Assembly.Location is strictly better than Assembly.CodeBase.

Assembly.CodeBase is obsolete property. The only reason why it was included in .NET Core was .NET Framework compatibility. The original purpose of Assembly.CodeBase was CAS (Code Access Security). It was meant to describe where the assembly was downloaded from for the Internet Zone security checks. It also explains some of its weird behaviors. For example, if the assembly is loaded as byte array, it returns the location of the caller of the Assembly.Load method.

shadow-copied assemblies

Shadow copying does not exist in ,NET Core.

There's some concern about using Assembly.Location in general to do thing

Correct, looking for files on disk like this is not going to work for proper single-exes that we are looking into for .NET 5, but that is a topic for a separate discussion. cc @rynowak

@jkotas

Assembly.CodeBase is obsolete property.

I've filed a request to do that.

@aL3891 do you have a small repro-app that I can use to test against?

You can just make a new mvc webapp, build it, and rename the directory its in to test%2B%, run it and opening it in the browser.

For some reason i cant get the exact same issue but you do get an error and renaming the folder back to test fixes the issue. The root issue seems the same though, it can't load the views properly

Calling the folder test%2B% also breaks visual studio, both on project creation and when opening the project after the fact. Of course this is probably less of an issue since people are unlikley to actually name their folders that, but in my case the folder name is generated in our deployment tools

Come to think of it, the error that i do get:

System.InvalidOperationException: The view 'Index' was not found. The following locations were searched:
/Views/Home/Index.cshtml
/Views/Shared/Index.cshtml
   at Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult.EnsureSuccessful(IEnumerable`1 originalLocations)
   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.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)

is one we've seen for some time on asp.net core, probably back to asp.net core 2.0 on full framework and we could never figure out why, but it must have been that our build tools put a %2B% or some other character like that in the path those times...

Of note is also that ´dotnet run´ doesnt work either with the above setup:

PS C:\Users\Allan\source\repos\test\test%2B%\WebApplication1> dotnet run
C:\Program Files\dotnet\sdk\3.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(234,5): error NETSDK1004: Assets file 'C:\Users\Allan\source\repos\test\test+%\WebApplication1\obj\project.assets.json' not found. Run a NuGet package restore to generate this file. [C:\Users\Allan\source\repos\test\test%2B%\WebApplication1\WebApplication1.csproj]

The build failed. Fix the build errors and run again.

So this is probably a deeper issue than asp.net core itself

Yeah, when I tried to do this locally I got

D:\DD\AspNetCore\.dotnet\sdk\3.1.100-preview1-014400\Microsoft.Common.CurrentVersion.targets(1875,5): warning : The referenced project '..\WebSites\SpecialCharacter+%\SpecialCharacter.csproj' does not exist. [D:\DD\AspNetCore\src\Mvc\test\Mvc.FunctionalTests\Microsoft.AspNetCore.Mvc.FunctionalTests.csproj]

This would seem to imply that this is first and foremost a problem with the SDK, with an additional problem in MVC which may or may not continue to happen depending on how the SDK issue is fixed. Given that I'm going to move this issue over to the SDK repo. If we still run into this (or something like it) after their fix we can reassess.

I wonder if its not even deeper than that actually, it seems to be an issue with post launch assembly loading or path handling in general

Possibly. The end result here might be that we just don't support having escaped special characters in the path, but hopefully the SDK team at least knows more.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

danroth27 picture danroth27  ·  130Comments

kevinchalet picture kevinchalet  ·  761Comments

Trcx528 picture Trcx528  ·  85Comments

glennc picture glennc  ·  117Comments

MaximRouiller picture MaximRouiller  ·  338Comments