From 79e744f691ac21cb007cb47c3b8786b9fef08d4b Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Mon, 19 Mar 2018 15:04:33 -0700 Subject: [PATCH] Handle unreadable import items in design time --- .../DefaultRazorProjectEngine.cs | 20 +++++++---- .../DefaultRazorProjectEngineTest.cs | 34 +++++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorProjectEngine.cs b/src/Microsoft.AspNetCore.Razor.Language/DefaultRazorProjectEngine.cs index e7eaafec22..114bd3c247 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 @@ -65,7 +66,7 @@ namespace Microsoft.AspNetCore.Razor.Language var importFeature = GetRequiredFeature(); var importItems = importFeature.GetImports(projectItem); - var importSourceDocuments = importItems.Select(ConvertToSourceDocument); + var importSourceDocuments = importItems.Select(i => ConvertToSourceDocument(i)); var parserOptions = GetRequiredFeature().Create(ConfigureParserOptions); var codeGenerationOptions = GetRequiredFeature().Create(ConfigureCodeGenerationOptions); @@ -84,12 +85,11 @@ namespace Microsoft.AspNetCore.Razor.Language var importFeature = GetRequiredFeature(); var importItems = importFeature.GetImports(projectItem); - var importSourceDocuments = importItems.Select(ConvertToSourceDocument); + var importSourceDocuments = importItems.Select(i => ConvertToSourceDocument(i, suppressExceptions: true)); var parserOptions = GetRequiredFeature().Create(ConfigureDesignTimeParserOptions); var codeGenerationOptions = GetRequiredFeature().Create(ConfigureDesignTimeCodeGenerationOptions); - return RazorCodeDocument.Create(sourceDocument, importSourceDocuments, parserOptions, codeGenerationOptions); } @@ -138,12 +138,20 @@ namespace Microsoft.AspNetCore.Razor.Language } // Internal for testing - internal static RazorSourceDocument ConvertToSourceDocument(RazorProjectItem importItem) + internal static RazorSourceDocument ConvertToSourceDocument(RazorProjectItem importItem, bool suppressExceptions = false) { if (importItem.Exists) { - // Normal import, has file paths, content etc. - return RazorSourceDocument.ReadFrom(importItem); + try + { + // Normal import, has file paths, content etc. + return RazorSourceDocument.ReadFrom(importItem); + } + catch (IOException) when (suppressExceptions) + { + // Something happened when trying to read the item from disk. + // Catch the exception so we don't crash the editor. + } } // Marker import, doesn't exist, used as an identifier for "there could be something here". diff --git a/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorProjectEngineTest.cs b/test/Microsoft.AspNetCore.Razor.Language.Test/DefaultRazorProjectEngineTest.cs index 171556ecf0..94ba95813c 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; @@ -33,5 +34,38 @@ namespace Microsoft.AspNetCore.Razor.Language // Assert Assert.NotNull(sourceDocument); } + + [Fact] + public void ConvertToSourceDocument_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.")); + + // Act & Assert + var exception = Assert.Throws(() => DefaultRazorProjectEngine.ConvertToSourceDocument(projectItem.Object)); + Assert.Equal("Couldn't read file.", exception.Message); + } + + [Fact] + public void ConvertToSourceDocument_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.")); + + // Act + var sourceDocument = DefaultRazorProjectEngine.ConvertToSourceDocument(projectItem.Object, suppressExceptions: true); + + // Assert - Does not throw + Assert.NotNull(sourceDocument); + Assert.Equal(0, sourceDocument.Length); + } } }