This has been noticed in a self-contained project, compiled to be executed as a Windows Service:
dotnet publish -r win-x64 --configuration Release
Steps to reproduce the behavior:
dotnet command./publish folder to a path on the deployment server that contains "%3A" in a folder name, e.g. C:/test%3A/app.New-Service -Name AspCoreTest -BinaryPathName C:/test%3A/app/MyWebApp.exe
The MVC views should be returned.
A 500 status code is returned with the following exceptions:
{"Timestamp":"2019-07-03T13:05:34.3593793+01:00","Level":"Error","MessageTemplate":"The view '{ViewName}' was not found. Searched locations: {SearchedViewLocations}","Properties":{"ViewName":"Collect","SearchedViewLocations":["/Views/DeviceDataCollection/Collect.cshtml","/Views/Shared/Collect.cshtml","/Pages/Shared/Collect.cshtml"],"EventId":{"Id":3},"SourceContext":"Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor","ActionId":"66564cc0-0bdf-49f9-9c6c-d974ac531254","ActionName":"Payments.FakeCardinal.Api.Controllers.DeviceDataCollectionController.Collect (Payments.FakeCardinal.Api)","RequestId":"0HLNVLQLOBPGM:00000002","RequestPath":"/devicedatacollection","CorrelationId":null,"ConnectionId":"0HLNVLQLOBPGM"}}
{"Timestamp":"2019-07-03T13:05:34.3601403+01:00","Level":"Error","MessageTemplate":"An unhandled exception has occurred while executing the request.","Exception":"System.InvalidOperationException: The view 'Collect' was not found. The following locations were searched:\r\n/Views/DeviceDataCollection/Collect.cshtml\r\n/Views/Shared/Collect.cshtml\r\n/Pages/Shared/Collect.cshtml\r\n at Microsoft.AspNetCore.Mvc.ViewEngines.ViewEngineResult.EnsureSuccessful(IEnumerable`1 originalLocations)\r\n at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync(ActionContext context, ViewResult result)\r\n at Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync(ActionContext context)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters()\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()\r\n at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)\r\n at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)\r\n at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)\r\n at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)","Properties":{"EventId":{"Id":1,"Name":"UnhandledException"},"SourceContext":"Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware","RequestId":"0HLNVLQLOBPGM:00000002","RequestPath":"/devicedatacollection","CorrelationId":null,"ConnectionId":"0HLNVLQLOBPGM"}}
Removing the %3A from the path resolves the issue.
Include the output of dotnet --info:
Host (useful for support):
Version: 2.1.2
Commit: 811c3ce6c0
.NET Core SDKs installed:
No SDKs were found.
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.Al
Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.Ap
Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
: is a reserved character in Windows file systems, so this isn't unexpected. Do you have an actual need to have a colon in the directory name?
The funny thing is, there isn't an actual colon in the directory name. But presumably something in ASP.NET Core is "decoding" that into a colon, and then it fails. That's just a guess, though.
Yeah, the problem is how @Eilon describes. Octopus Deploy creates folders on the Windows servers; it would appear that someone has placed a colon in the deployment/application package name which results in a folder being created with a URL Encoded name (i.e. the colon becomes "%3A" in the Windows file system). On the face of it, every looks fine until a view is rendered - I imagine the view engine URL decodes the "%3A" then expects to find a folder name with a colon in it.
Thanks for contacting us, @photomoose.
Are you interested in sending us a PR? We'll happily consider it.
BTW in my personal opinion, even though this is likely a bug somewhere in ASP.NET Core, is that you should avoid any "special-ish" characters in folder names, including colons, percents, etc. So if it's possible to avoid a colon (encoded or otherwise), I would recommend doing that.
@Eilon I agree with you. The problem was, we didn't know we were using special characters - it took us the past day to realise the folder name was the reason for the views not being found.
@mkArtakMSFT I'll take a look at the source and see if I can find anything obvious to fix.
%3A is encoded :
Both browsers and servers tend to decode that before submission because it's valid in a URL
I wouldn't consider this an actual bug, but paranoid good design trying to avoid various file system attacks :)
I agree in general, but this isn't part of a URL. It's a server side path on disk used as an implementation detail of a controller. Nothing to do with clients, browsers, HTTP, HTML, or anything else like that.
I certainly think that this is a fairly low priority bug, but I'm quite certain it's a legitimate bug.