5
5
using System . Collections . Immutable ;
6
6
using System . Composition ;
7
7
using System . IO ;
8
+ using Microsoft . AspNetCore . Razor . Telemetry ;
9
+ using Microsoft . AspNetCore . Razor . Utilities ;
8
10
using Microsoft . CodeAnalysis . Razor . Workspaces ;
9
11
10
12
namespace Microsoft . CodeAnalysis . Razor . ProjectSystem ;
@@ -16,49 +18,58 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem;
16
18
/// </summary>
17
19
[ Shared ]
18
20
[ Export ( typeof ( FallbackProjectManager ) ) ]
19
- internal sealed class FallbackProjectManager
21
+ [ method: ImportingConstructor ]
22
+ internal sealed class FallbackProjectManager (
23
+ ProjectConfigurationFilePathStore projectConfigurationFilePathStore ,
24
+ LanguageServerFeatureOptions languageServerFeatureOptions ,
25
+ ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor ,
26
+ ITelemetryReporter telemetryReporter )
20
27
{
21
- private readonly ProjectConfigurationFilePathStore _projectConfigurationFilePathStore ;
22
- private readonly LanguageServerFeatureOptions _languageServerFeatureOptions ;
23
- private readonly ProjectSnapshotManagerAccessor _projectSnapshotManagerAccessor ;
28
+ private readonly ProjectConfigurationFilePathStore _projectConfigurationFilePathStore = projectConfigurationFilePathStore ;
29
+ private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions ;
30
+ private readonly ProjectSnapshotManagerAccessor _projectSnapshotManagerAccessor = projectSnapshotManagerAccessor ;
31
+ private readonly ITelemetryReporter _telemetryReporter = telemetryReporter ;
24
32
25
33
private ImmutableHashSet < ProjectId > _fallbackProjectIds = ImmutableHashSet < ProjectId > . Empty ;
26
34
27
- [ ImportingConstructor ]
28
- public FallbackProjectManager (
29
- ProjectConfigurationFilePathStore projectConfigurationFilePathStore ,
30
- LanguageServerFeatureOptions languageServerFeatureOptions ,
31
- ProjectSnapshotManagerAccessor projectSnapshotManagerAccessor )
32
- {
33
- _projectConfigurationFilePathStore = projectConfigurationFilePathStore ;
34
- _languageServerFeatureOptions = languageServerFeatureOptions ;
35
- _projectSnapshotManagerAccessor = projectSnapshotManagerAccessor ;
36
- }
37
-
38
35
internal void DynamicFileAdded ( ProjectId projectId , ProjectKey razorProjectKey , string projectFilePath , string filePath )
39
36
{
40
- if ( _fallbackProjectIds . Contains ( projectId ) )
37
+ try
41
38
{
42
- // If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
43
- // are the only way to know about files in the project.
44
- AddFallbackDocument ( razorProjectKey , filePath , projectFilePath ) ;
39
+ if ( _fallbackProjectIds . Contains ( projectId ) )
40
+ {
41
+ // If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
42
+ // are the only way to know about files in the project.
43
+ AddFallbackDocument ( razorProjectKey , filePath , projectFilePath ) ;
44
+ }
45
+ else if ( _projectSnapshotManagerAccessor . Instance . GetLoadedProject ( razorProjectKey ) is null )
46
+ {
47
+ // We have been asked to provide dynamic file info, which means there is a .razor or .cshtml file in the project
48
+ // but for some reason our project system doesn't know about the project. In these cases (often when people don't
49
+ // use the Razor or Web SDK) we spin up a fallback experience for them
50
+ AddFallbackProject ( projectId , filePath ) ;
51
+ }
45
52
}
46
- else if ( _projectSnapshotManagerAccessor . Instance . GetLoadedProject ( razorProjectKey ) is null )
53
+ catch ( Exception ex )
47
54
{
48
- // We have been asked to provide dynamic file info, which means there is a .razor or .cshtml file in the project
49
- // but for some reason our project system doesn't know about the project. In these cases (often when people don't
50
- // use the Razor or Web SDK) we spin up a fallback experience for them
51
- AddFallbackProject ( projectId , filePath ) ;
55
+ _telemetryReporter . ReportFault ( ex , "Error while trying to add fallback document to project" ) ;
52
56
}
53
57
}
54
58
55
59
internal void DynamicFileRemoved ( ProjectId projectId , string projectFilePath , string filePath )
56
60
{
57
- if ( _fallbackProjectIds . Contains ( projectId ) )
61
+ try
62
+ {
63
+ if ( _fallbackProjectIds . Contains ( projectId ) )
64
+ {
65
+ // If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
66
+ // are the only way to know about files in the project.
67
+ RemoveFallbackDocument ( projectId , filePath , projectFilePath ) ;
68
+ }
69
+ }
70
+ catch ( Exception ex )
58
71
{
59
- // If this is a fallback project, then Roslyn may not track documents in the project, so these dynamic file notifications
60
- // are the only way to know about files in the project.
61
- RemoveFallbackDocument ( projectId , filePath , projectFilePath ) ;
72
+ _telemetryReporter . ReportFault ( ex , "Error while trying to remove fallback document from project" ) ;
62
73
}
63
74
}
64
75
@@ -101,15 +112,27 @@ private void AddFallbackProject(ProjectId projectId, string filePath)
101
112
private void AddFallbackDocument ( ProjectKey projectKey , string filePath , string projectFilePath )
102
113
{
103
114
var hostDocument = CreateHostDocument ( filePath , projectFilePath ) ;
115
+ if ( hostDocument is null )
116
+ {
117
+ return ;
118
+ }
119
+
104
120
var textLoader = new FileTextLoader ( filePath , defaultEncoding : null ) ;
105
121
_projectSnapshotManagerAccessor . Instance . DocumentAdded ( projectKey , hostDocument , textLoader ) ;
106
122
}
107
123
108
- private static HostDocument CreateHostDocument ( string filePath , string projectFilePath )
124
+ private static HostDocument ? CreateHostDocument ( string filePath , string projectFilePath )
109
125
{
110
- var targetPath = filePath . StartsWith ( projectFilePath , FilePathComparison . Instance )
111
- ? filePath [ projectFilePath . Length ..]
112
- : filePath ;
126
+ // The compiler only supports paths that are relative to the project root, so filter our files
127
+ // that don't match
128
+ var projectPath = FilePathNormalizer . GetNormalizedDirectoryName ( projectFilePath ) ;
129
+ var normalizedFilePath = FilePathNormalizer . Normalize ( filePath ) ;
130
+ if ( ! normalizedFilePath . StartsWith ( projectPath , FilePathComparison . Instance ) )
131
+ {
132
+ return null ;
133
+ }
134
+
135
+ var targetPath = filePath [ projectPath . Length ..] ;
113
136
var hostDocument = new HostDocument ( filePath , targetPath ) ;
114
137
return hostDocument ;
115
138
}
@@ -129,6 +152,11 @@ private void RemoveFallbackDocument(ProjectId projectId, string filePath, string
129
152
}
130
153
131
154
var hostDocument = CreateHostDocument ( filePath , projectFilePath ) ;
155
+ if ( hostDocument is null )
156
+ {
157
+ return ;
158
+ }
159
+
132
160
_projectSnapshotManagerAccessor . Instance . DocumentRemoved ( razorProjectKey , hostDocument ) ;
133
161
}
134
162
0 commit comments