diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorProjectEngine.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorProjectEngine.cs index 89b667979a..e5993ce1a3 100644 --- a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorProjectEngine.cs +++ b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorProjectEngine.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace Microsoft.AspNetCore.Razor.Language @@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Razor.Language var importFeature = GetRequiredFeature(); var importItems = importFeature.GetImports(projectItem); - var importSourceDocuments = GetImportSourceDocuments(importItems); + var importSourceDocuments = GetImportSourceDocuments(importItems, suppressExceptions: true); var parserOptions = GetRequiredFeature().Create(ConfigureDesignTimeParserOptions); var codeGenerationOptions = GetRequiredFeature().Create(ConfigureDesignTimeCodeGenerationOptions); @@ -137,7 +138,9 @@ namespace Microsoft.AspNetCore.Razor.Language } // Internal for testing - internal static IReadOnlyList GetImportSourceDocuments(IReadOnlyList importItems) + internal static IReadOnlyList GetImportSourceDocuments( + IReadOnlyList importItems, + bool suppressExceptions = false) { var imports = new List(); for (var i = 0; i < importItems.Count; i++) @@ -146,8 +149,17 @@ namespace Microsoft.AspNetCore.Razor.Language if (importItem.Exists) { - var sourceDocument = RazorSourceDocument.ReadFrom(importItem); - imports.Add(sourceDocument); + try + { + // Normal import, has file paths, content etc. + var sourceDocument = RazorSourceDocument.ReadFrom(importItem); + imports.Add(sourceDocument); + } + catch (IOException) when (suppressExceptions) + { + // Something happened when trying to read the item from disk. + // Catch the exception so we don't crash the editor. + } } } diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorProjectEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorProjectEngineTest.cs index 2ca4da9881..c70cdab663 100644 --- a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorProjectEngineTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorProjectEngineTest.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.IO; using Moq; using Xunit; @@ -23,5 +24,39 @@ namespace Microsoft.AspNetCore.Razor.Language var sourceDocument = Assert.Single(sourceDocuments); Assert.Equal(existingItem.FilePath, sourceDocument.FilePath); } + + [Fact] + public void GetImportSourceDocuments_UnreadableItem_Throws() + { + // Arrange + var projectItem = new Mock(MockBehavior.Strict); + projectItem.SetupGet(p => p.Exists).Returns(true); + projectItem.SetupGet(p => p.PhysicalPath).Returns("path/to/file.cshtml"); + projectItem.Setup(p => p.Read()).Throws(new IOException("Couldn't read file.")); + var items = new[] { projectItem.Object }; + + // Act & Assert + var exception = Assert.Throws(() => DefaultRazorProjectEngine.GetImportSourceDocuments(items)); + Assert.Equal("Couldn't read file.", exception.Message); + } + + [Fact] + public void GetImportSourceDocuments_WithSuppressExceptions_UnreadableItem_DoesNotThrow() + { + // Arrange + var projectItem = new Mock(MockBehavior.Strict); + projectItem.SetupGet(p => p.Exists).Returns(true); + projectItem.SetupGet(p => p.PhysicalPath).Returns("path/to/file.cshtml"); + projectItem.SetupGet(p => p.FilePath).Returns("path/to/file.cshtml"); + projectItem.SetupGet(p => p.RelativePhysicalPath).Returns("path/to/file.cshtml"); + projectItem.Setup(p => p.Read()).Throws(new IOException("Couldn't read file.")); + var items = new[] { projectItem.Object }; + + // Act + var sourceDocuments = DefaultRazorProjectEngine.GetImportSourceDocuments(items, suppressExceptions: true); + + // Assert - Does not throw + Assert.Empty(sourceDocuments); + } } }