Decouple tooling from MVC assemblies
This commit is contained in:
parent
5008c7803c
commit
0b777dad3f
|
|
@ -10,14 +10,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\RazorDiagnosticJsonConverter.cs">
|
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
|
||||||
<Link>Shared\RazorDiagnosticJsonConverter.cs</Link>
|
<Link>Serialization\%(FileName)%(Extension)</Link>
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\TagHelperDescriptorJsonConverter.cs">
|
|
||||||
<Link>Shared\TagHelperDescriptorJsonConverter.cs</Link>
|
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.VisualStudio.LanguageServices.Razor;
|
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Razor.Performance
|
namespace Microsoft.AspNetCore.Razor.Performance
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
|
||||||
|
{
|
||||||
|
internal class ExtensionInitializer : RazorExtensionInitializer
|
||||||
|
{
|
||||||
|
public override void Initialize(RazorProjectEngineBuilder builder)
|
||||||
|
{
|
||||||
|
if (builder == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builder.Configuration.ConfigurationName == "MVC-1.0")
|
||||||
|
{
|
||||||
|
RazorExtensions.Register(builder);
|
||||||
|
}
|
||||||
|
else if (builder.Configuration.ConfigurationName == "MVC-1.1")
|
||||||
|
{
|
||||||
|
RazorExtensions.Register(builder);
|
||||||
|
RazorExtensions.RegisterViewComponentTagHelpers(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,5 +2,10 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
[assembly: ProvideRazorExtensionInitializer("MVC-1.0", typeof(ExtensionInitializer))]
|
||||||
|
[assembly: ProvideRazorExtensionInitializer("MVC-1.1", typeof(ExtensionInitializer))]
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
|
||||||
throw new ArgumentNullException(nameof(builder));
|
throw new ArgumentNullException(nameof(builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
|
||||||
|
|
||||||
builder.Features.Add(new ViewComponentTagHelperPass());
|
builder.Features.Add(new ViewComponentTagHelperPass());
|
||||||
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
|
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +90,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
|
||||||
|
|
||||||
EnsureDesignTime(builder);
|
EnsureDesignTime(builder);
|
||||||
|
|
||||||
|
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
|
||||||
builder.Features.Add(new ViewComponentTagHelperPass());
|
builder.Features.Add(new ViewComponentTagHelperPass());
|
||||||
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
|
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X
|
||||||
var symbol = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
|
var symbol = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
|
||||||
if (symbol != null)
|
if (symbol != null)
|
||||||
{
|
{
|
||||||
if (string.Equals(symbol.Identity.Name, ViewComponentTypes.Assembly, StringComparison.Ordinal) &&
|
if (string.Equals(symbol.Identity.Name, ViewComponentTypes.Assembly, StringComparison.Ordinal))
|
||||||
symbol.Identity.Version > ViewComponentTypes.AssemblyVersion)
|
|
||||||
{
|
{
|
||||||
enabled = true;
|
enabled = symbol.Identity.Version >= ViewComponentTypes.AssemblyVersion;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
InheritsDirective.Register(builder);
|
InheritsDirective.Register(builder);
|
||||||
SectionDirective.Register(builder);
|
SectionDirective.Register(builder);
|
||||||
|
|
||||||
|
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
|
||||||
|
|
||||||
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
|
builder.AddTargetExtension(new ViewComponentTagHelperTargetExtension());
|
||||||
builder.AddTargetExtension(new TemplateTargetExtension()
|
builder.AddTargetExtension(new TemplateTargetExtension()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,31 +10,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Extensions
|
||||||
{
|
{
|
||||||
internal class ViewComponentTypeVisitor : SymbolVisitor
|
internal class ViewComponentTypeVisitor : SymbolVisitor
|
||||||
{
|
{
|
||||||
private static readonly Version SupportedVCTHMvcVersion = new Version(1, 1);
|
|
||||||
|
|
||||||
private readonly INamedTypeSymbol _viewComponentAttribute;
|
private readonly INamedTypeSymbol _viewComponentAttribute;
|
||||||
private readonly INamedTypeSymbol _nonViewComponentAttribute;
|
private readonly INamedTypeSymbol _nonViewComponentAttribute;
|
||||||
private readonly List<INamedTypeSymbol> _results;
|
private readonly List<INamedTypeSymbol> _results;
|
||||||
|
|
||||||
public static ViewComponentTypeVisitor Create(Compilation compilation, List<INamedTypeSymbol> results)
|
public static ViewComponentTypeVisitor Create(Compilation compilation, List<INamedTypeSymbol> results)
|
||||||
{
|
{
|
||||||
var enabled = false;
|
var vcAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute);
|
||||||
foreach (var reference in compilation.References)
|
var nonVCAttribute = compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute);
|
||||||
{
|
|
||||||
var symbol = compilation.GetAssemblyOrModuleSymbol(reference) as IAssemblySymbol;
|
|
||||||
if (symbol != null)
|
|
||||||
{
|
|
||||||
if (string.Equals(symbol.Identity.Name, ViewComponentTypes.Assembly, StringComparison.Ordinal) &&
|
|
||||||
symbol.Identity.Version > ViewComponentTypes.AssemblyVersion)
|
|
||||||
{
|
|
||||||
enabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var vcAttribute = enabled ? compilation.GetTypeByMetadataName(ViewComponentTypes.ViewComponentAttribute) : null;
|
|
||||||
var nonVCAttribute = enabled ? compilation.GetTypeByMetadataName(ViewComponentTypes.NonViewComponentAttribute) : null;
|
|
||||||
return new ViewComponentTypeVisitor(vcAttribute, nonVCAttribute, results);
|
return new ViewComponentTypeVisitor(vcAttribute, nonVCAttribute, results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// 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;
|
||||||
|
using System.Composition;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
{
|
||||||
|
[Export(typeof(IFallbackProjectEngineFactory))]
|
||||||
|
internal class FallbackProjectEngineFactory : IFallbackProjectEngineFactory
|
||||||
|
{
|
||||||
|
public RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
if (configuration == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileSystem == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(fileSystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a very basic implementation that will provide reasonable support without crashing.
|
||||||
|
// If the user falls into this situation, ideally they can realize that something is wrong and take
|
||||||
|
// action.
|
||||||
|
//
|
||||||
|
// This has no support for:
|
||||||
|
// - Tag Helpers
|
||||||
|
// - Imports
|
||||||
|
// - Default Imports
|
||||||
|
// - and will have a very limited set of directives
|
||||||
|
return RazorProjectEngine.Create(configuration, fileSystem, configure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
{
|
||||||
|
// Used to create the 'fallback' project engine when we don't have a custom implementation.
|
||||||
|
internal interface IFallbackProjectEngineFactory : IProjectEngineFactory
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
for (var i = 0; i< projects.Count; i++)
|
for (var i = 0; i< projects.Count; i++)
|
||||||
{
|
{
|
||||||
var project = projects[i];
|
var project = projects[i];
|
||||||
if (string.Equals(filePath, project.WorkspaceProject.FilePath, StringComparison.OrdinalIgnoreCase))
|
if (FilePathComparer.Instance.Equals(filePath, project.FilePath))
|
||||||
{
|
{
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,20 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.CodeAnalysis.Host;
|
using Microsoft.CodeAnalysis.Host;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Razor
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
{
|
{
|
||||||
internal abstract class RazorProjectEngineFactoryService : ILanguageService
|
internal abstract class RazorProjectEngineFactoryService : ILanguageService
|
||||||
{
|
{
|
||||||
public abstract RazorProjectEngine Create(string projectPath, Action<RazorProjectEngineBuilder> configure);
|
public abstract IProjectEngineFactory FindFactory(ProjectSnapshot project);
|
||||||
|
|
||||||
|
public abstract IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project);
|
||||||
|
|
||||||
|
public abstract RazorProjectEngine Create(ProjectSnapshot project, Action<RazorProjectEngineBuilder> configure);
|
||||||
|
|
||||||
|
public abstract RazorProjectEngine Create(ProjectSnapshot project, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure);
|
||||||
|
|
||||||
|
public abstract RazorProjectEngine Create(string directoryPath, Action<RazorProjectEngineBuilder> configure);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
|
@ -8,6 +9,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
||||||
{
|
{
|
||||||
public sealed class TagHelperResolutionResult
|
public sealed class TagHelperResolutionResult
|
||||||
{
|
{
|
||||||
|
internal static TagHelperResolutionResult Empty = new TagHelperResolutionResult(Array.Empty<TagHelperDescriptor>(), Array.Empty<RazorDiagnostic>());
|
||||||
|
|
||||||
public TagHelperResolutionResult(IReadOnlyList<TagHelperDescriptor> descriptors, IReadOnlyList<RazorDiagnostic> diagnostics)
|
public TagHelperResolutionResult(IReadOnlyList<TagHelperDescriptor> descriptors, IReadOnlyList<RazorDiagnostic> diagnostics)
|
||||||
{
|
{
|
||||||
Descriptors = descriptors;
|
Descriptors = descriptors;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,57 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.CodeAnalysis.Host;
|
using Microsoft.CodeAnalysis.Host;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Razor
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
{
|
{
|
||||||
internal abstract class TagHelperResolver : ILanguageService
|
internal abstract class TagHelperResolver : ILanguageService
|
||||||
{
|
{
|
||||||
public abstract Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project, CancellationToken cancellationToken);
|
public abstract Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
protected virtual async Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, RazorProjectEngine engine)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (engine == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(engine));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.WorkspaceProject == null)
|
||||||
|
{
|
||||||
|
return TagHelperResolutionResult.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var providers = engine.Engine.Features.OfType<ITagHelperDescriptorProvider>().ToArray();
|
||||||
|
if (providers.Length == 0)
|
||||||
|
{
|
||||||
|
return TagHelperResolutionResult.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = new List<TagHelperDescriptor>();
|
||||||
|
var context = TagHelperDescriptorProviderContext.Create(results);
|
||||||
|
|
||||||
|
var compilation = await project.WorkspaceProject.GetCompilationAsync().ConfigureAwait(false);
|
||||||
|
context.SetCompilation(compilation);
|
||||||
|
|
||||||
|
for (var i = 0; i < providers.Length; i++)
|
||||||
|
{
|
||||||
|
var provider = providers[i];
|
||||||
|
provider.Execute(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TagHelperResolutionResult(results, Array.Empty<RazorDiagnostic>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
// 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.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Remote.Razor
|
|
||||||
{
|
|
||||||
internal class DefaultTagHelperResolver : TagHelperResolver
|
|
||||||
{
|
|
||||||
public DefaultTagHelperResolver(bool designTime)
|
|
||||||
{
|
|
||||||
DesignTime = designTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DesignTime { get; }
|
|
||||||
|
|
||||||
private TagHelperResolutionResult GetTagHelpers(Compilation compilation)
|
|
||||||
{
|
|
||||||
var descriptors = new List<TagHelperDescriptor>();
|
|
||||||
|
|
||||||
var providers = new ITagHelperDescriptorProvider[]
|
|
||||||
{
|
|
||||||
new DefaultTagHelperDescriptorProvider() { DesignTime = DesignTime, },
|
|
||||||
new ViewComponentTagHelperDescriptorProvider(),
|
|
||||||
};
|
|
||||||
|
|
||||||
var results = new List<TagHelperDescriptor>();
|
|
||||||
var context = TagHelperDescriptorProviderContext.Create(results);
|
|
||||||
context.SetCompilation(compilation);
|
|
||||||
|
|
||||||
for (var i = 0; i < providers.Length; i++)
|
|
||||||
{
|
|
||||||
var provider = providers[i];
|
|
||||||
provider.Execute(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
var diagnostics = new List<RazorDiagnostic>();
|
|
||||||
var resolutionResult = new TagHelperResolutionResult(results, diagnostics);
|
|
||||||
|
|
||||||
return resolutionResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
return GetTagHelpers(compilation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,12 +7,13 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="..\Microsoft.VisualStudio.LanguageServices.Razor\RazorDiagnosticJsonConverter.cs" />
|
<Compile Include="..\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
|
||||||
|
<Link>Serialization\%(FileName)%(Extension)</Link>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
|
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
|
||||||
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
|
|
||||||
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.Language\Microsoft.AspNetCore.Razor.Language.csproj" />
|
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.Language\Microsoft.AspNetCore.Razor.Language.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,34 +10,22 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
using Microsoft.VisualStudio.LanguageServices.Razor;
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
namespace Microsoft.CodeAnalysis.Remote.Razor
|
namespace Microsoft.CodeAnalysis.Remote.Razor
|
||||||
{
|
{
|
||||||
internal class RazorLanguageService : ServiceHubServiceBase
|
internal class RazorLanguageService : RazorServiceBase
|
||||||
{
|
{
|
||||||
public RazorLanguageService(Stream stream, IServiceProvider serviceProvider)
|
public RazorLanguageService(Stream stream, IServiceProvider serviceProvider)
|
||||||
: base(serviceProvider, stream)
|
: base(stream, serviceProvider)
|
||||||
{
|
{
|
||||||
Rpc.JsonSerializer.Converters.Add(new RazorDiagnosticJsonConverter());
|
|
||||||
|
|
||||||
// Due to this issue - https://github.com/dotnet/roslyn/issues/16900#issuecomment-277378950
|
|
||||||
// We need to manually start the RPC connection. Otherwise we'd be opting ourselves into
|
|
||||||
// race condition prone call paths.
|
|
||||||
Rpc.StartListening();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TagHelperResolutionResult> GetTagHelpersAsync(Guid projectIdBytes, string projectDebugName, CancellationToken cancellationToken = default(CancellationToken))
|
public async Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshotHandle projectHandle, string factoryTypeName, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var projectId = ProjectId.CreateFromSerialized(projectIdBytes, projectDebugName);
|
var project = await GetProjectSnapshotAsync(projectHandle, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var solution = await GetSolutionAsync(cancellationToken).ConfigureAwait(false);
|
return await RazorServices.TagHelperResolver.GetTagHelpersAsync(project, factoryTypeName, cancellationToken);
|
||||||
var project = solution.GetProject(projectId);
|
|
||||||
|
|
||||||
var resolver = new DefaultTagHelperResolver(designTime: true);
|
|
||||||
var result = await resolver.GetTagHelpersAsync(project, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IEnumerable<DirectiveDescriptor>> GetDirectivesAsync(Guid projectIdBytes, string projectDebugName, CancellationToken cancellationToken = default(CancellationToken))
|
public Task<IEnumerable<DirectiveDescriptor>> GetDirectivesAsync(Guid projectIdBytes, string projectDebugName, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
// 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;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Remote.Razor
|
||||||
|
{
|
||||||
|
internal abstract class RazorServiceBase : ServiceHubServiceBase
|
||||||
|
{
|
||||||
|
public RazorServiceBase(Stream stream, IServiceProvider serviceProvider)
|
||||||
|
: base(serviceProvider, stream)
|
||||||
|
{
|
||||||
|
RazorServices = new RazorServices();
|
||||||
|
|
||||||
|
Rpc.JsonSerializer.Converters.RegisterRazorConverters();
|
||||||
|
|
||||||
|
// Due to this issue - https://github.com/dotnet/roslyn/issues/16900#issuecomment-277378950
|
||||||
|
// We need to manually start the RPC connection. Otherwise we'd be opting ourselves into
|
||||||
|
// race condition prone call paths.
|
||||||
|
Rpc.StartListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RazorServices RazorServices { get; }
|
||||||
|
|
||||||
|
protected virtual async Task<ProjectSnapshot> GetProjectSnapshotAsync(ProjectSnapshotHandle projectHandle, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (projectHandle == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
var solution = await GetSolutionAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
var workspaceProject = solution.GetProject(projectHandle.WorkspaceProjectId);
|
||||||
|
|
||||||
|
return new SerializedProjectSnapshot(projectHandle.FilePath, projectHandle.Configuration, workspaceProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SerializedProjectSnapshot : ProjectSnapshot
|
||||||
|
{
|
||||||
|
public SerializedProjectSnapshot(string filePath, RazorConfiguration configuration, Project workspaceProject)
|
||||||
|
{
|
||||||
|
FilePath = filePath;
|
||||||
|
Configuration = configuration;
|
||||||
|
WorkspaceProject = workspaceProject;
|
||||||
|
|
||||||
|
IsInitialized = true;
|
||||||
|
Version = VersionStamp.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RazorConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public override string FilePath { get; }
|
||||||
|
|
||||||
|
public override bool IsInitialized { get; }
|
||||||
|
|
||||||
|
public override VersionStamp Version { get; }
|
||||||
|
|
||||||
|
public override Project WorkspaceProject { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
{
|
||||||
|
// Provides access to Razor language and workspace services that are avialable in the OOP host.
|
||||||
|
//
|
||||||
|
// Since we don't have access to the workspace we only have access to some specific things
|
||||||
|
// that we can construct directly.
|
||||||
|
internal class RazorServices
|
||||||
|
{
|
||||||
|
public RazorServices()
|
||||||
|
{
|
||||||
|
FallbackProjectEngineFactory = new FallbackProjectEngineFactory();
|
||||||
|
TagHelperResolver = new RemoteTagHelperResolver(FallbackProjectEngineFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFallbackProjectEngineFactory FallbackProjectEngineFactory { get; }
|
||||||
|
|
||||||
|
public RemoteTagHelperResolver TagHelperResolver { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
// 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;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
{
|
||||||
|
internal class RemoteTagHelperResolver : TagHelperResolver
|
||||||
|
{
|
||||||
|
private readonly static RazorConfiguration DefaultConfiguration = FallbackRazorConfiguration.MVC_2_0;
|
||||||
|
|
||||||
|
private readonly IFallbackProjectEngineFactory _fallbackFactory;
|
||||||
|
|
||||||
|
public RemoteTagHelperResolver(IFallbackProjectEngineFactory fallbackFactory)
|
||||||
|
{
|
||||||
|
if (fallbackFactory == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(fallbackFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
_fallbackFactory = fallbackFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, string factoryTypeName, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (project.Configuration == null || project.WorkspaceProject == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(TagHelperResolutionResult.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var engine = CreateProjectEngine(project, factoryTypeName);
|
||||||
|
return GetTagHelpersAsync(project, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal RazorProjectEngine CreateProjectEngine(ProjectSnapshot project, string factoryTypeName)
|
||||||
|
{
|
||||||
|
// This section is really similar to the code DefaultProjectEngineFactoryService
|
||||||
|
// but with a few differences that are significant in the remote scenario
|
||||||
|
//
|
||||||
|
// Most notably, we are going to find the Tag Helpers using a compilation, and we have
|
||||||
|
// no editor settings.
|
||||||
|
Action<RazorProjectEngineBuilder> configure = (b) =>
|
||||||
|
{
|
||||||
|
b.Features.Add(new DefaultTagHelperDescriptorProvider() { DesignTime = true });
|
||||||
|
};
|
||||||
|
|
||||||
|
// The default configuration currently matches MVC-2.0. Beyond MVC-2.0 we added SDK support for
|
||||||
|
// properly detecting project versions, so that's a good version to assume when we can't find a
|
||||||
|
// configuration.
|
||||||
|
var configuration = project?.Configuration ?? DefaultConfiguration;
|
||||||
|
|
||||||
|
// If there's no factory to handle the configuration then fall back to a very basic configuration.
|
||||||
|
//
|
||||||
|
// This will stop a crash from happening in this case (misconfigured project), but will still make
|
||||||
|
// it obvious to the user that something is wrong.
|
||||||
|
var factory = CreateFactory(configuration, factoryTypeName) ?? _fallbackFactory;
|
||||||
|
return factory.Create(configuration, RazorProjectFileSystem.Empty, configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IProjectEngineFactory CreateFactory(RazorConfiguration configuration, string factoryTypeName)
|
||||||
|
{
|
||||||
|
if (factoryTypeName == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (IProjectEngineFactory)Activator.CreateInstance(Type.GetType(factoryTypeName, throwOnError: true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,8 +6,6 @@ using System.IO;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
using Mvc1_X = Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X;
|
|
||||||
using MvcLatest = Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.Editor.Razor
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -16,58 +14,127 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
private readonly static RazorConfiguration DefaultConfiguration = FallbackRazorConfiguration.MVC_2_0;
|
private readonly static RazorConfiguration DefaultConfiguration = FallbackRazorConfiguration.MVC_2_0;
|
||||||
|
|
||||||
private readonly ProjectSnapshotManager _projectManager;
|
private readonly ProjectSnapshotManager _projectManager;
|
||||||
|
private readonly IFallbackProjectEngineFactory _defaultFactory;
|
||||||
|
private readonly Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] _customFactories;
|
||||||
|
|
||||||
public DefaultProjectEngineFactoryService(ProjectSnapshotManager projectManager)
|
public DefaultProjectEngineFactoryService(
|
||||||
|
ProjectSnapshotManager projectManager,
|
||||||
|
IFallbackProjectEngineFactory defaultFactory,
|
||||||
|
Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] customFactories)
|
||||||
{
|
{
|
||||||
if (projectManager == null)
|
if (projectManager == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(projectManager));
|
throw new ArgumentNullException(nameof(projectManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (defaultFactory == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(defaultFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customFactories == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(customFactories));
|
||||||
|
}
|
||||||
|
|
||||||
_projectManager = projectManager;
|
_projectManager = projectManager;
|
||||||
|
_defaultFactory = defaultFactory;
|
||||||
|
_customFactories = customFactories;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override RazorProjectEngine Create(string projectPath, Action<RazorProjectEngineBuilder> configure)
|
public override IProjectEngineFactory FindFactory(ProjectSnapshot project)
|
||||||
{
|
{
|
||||||
if (projectPath == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(projectPath));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
// In 15.5 we expect projectPath to be a directory, NOT the path to the csproj.
|
return SelectFactory(project.Configuration ?? DefaultConfiguration, requireSerializable: false);
|
||||||
var project = FindProject(projectPath);
|
|
||||||
var configuration = project?.Configuration ?? DefaultConfiguration;
|
|
||||||
var fileSystem = RazorProjectFileSystem.Create(projectPath);
|
|
||||||
|
|
||||||
RazorProjectEngine projectEngine;
|
|
||||||
if (configuration.LanguageVersion.Major == 1)
|
|
||||||
{
|
|
||||||
projectEngine = RazorProjectEngine.Create(configuration, fileSystem, b =>
|
|
||||||
{
|
|
||||||
configure?.Invoke(b);
|
|
||||||
|
|
||||||
Mvc1_X.RazorExtensions.Register(b);
|
|
||||||
|
|
||||||
if (configuration.LanguageVersion.Minor >= 1)
|
|
||||||
{
|
|
||||||
Mvc1_X.RazorExtensions.RegisterViewComponentTagHelpers(b);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
projectEngine = RazorProjectEngine.Create(configuration, fileSystem, b =>
|
|
||||||
{
|
|
||||||
configure?.Invoke(b);
|
|
||||||
|
|
||||||
MvcLatest.RazorExtensions.Register(b);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return projectEngine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProjectSnapshot FindProject(string directory)
|
public override IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SelectFactory(project.Configuration ?? DefaultConfiguration, requireSerializable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RazorProjectEngine Create(ProjectSnapshot project, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateCore(project, RazorProjectFileSystem.Create(Path.GetDirectoryName(project.FilePath)), configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RazorProjectEngine Create(string directoryPath, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
if (directoryPath == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(directoryPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
var project = FindProjectByDirectory(directoryPath);
|
||||||
|
return CreateCore(project, RazorProjectFileSystem.Create(directoryPath), configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RazorProjectEngine Create(ProjectSnapshot project, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
if (project == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(project));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileSystem == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(fileSystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateCore(project, fileSystem, configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RazorProjectEngine CreateCore(ProjectSnapshot project, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
// When we're running in the editor, the editor provides a configure delegate that will include
|
||||||
|
// the editor settings and tag helpers.
|
||||||
|
//
|
||||||
|
// This service is only used in process in Visual Studio, and any other callers should provide these
|
||||||
|
// things also.
|
||||||
|
configure = configure ?? ((b) => { });
|
||||||
|
|
||||||
|
// The default configuration currently matches MVC-2.0. Beyond MVC-2.0 we added SDK support for
|
||||||
|
// properly detecting project versions, so that's a good version to assume when we can't find a
|
||||||
|
// configuration.
|
||||||
|
var configuration = project?.Configuration ?? DefaultConfiguration;
|
||||||
|
|
||||||
|
// If there's no factory to handle the configuration then fall back to a very basic configuration.
|
||||||
|
//
|
||||||
|
// This will stop a crash from happening in this case (misconfigured project), but will still make
|
||||||
|
// it obvious to the user that something is wrong.
|
||||||
|
var factory = SelectFactory(configuration) ?? _defaultFactory;
|
||||||
|
return factory.Create(configuration, fileSystem, configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IProjectEngineFactory SelectFactory(RazorConfiguration configuration, bool requireSerializable = false)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _customFactories.Length; i++)
|
||||||
|
{
|
||||||
|
var factory = _customFactories[i];
|
||||||
|
if (string.Equals(configuration.ConfigurationName, factory.Metadata.ConfigurationName))
|
||||||
|
{
|
||||||
|
return requireSerializable && !factory.Metadata.SupportsSerialization ? null : factory.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProjectSnapshot FindProjectByDirectory(string directory)
|
||||||
{
|
{
|
||||||
directory = NormalizeDirectoryPath(directory);
|
directory = NormalizeDirectoryPath(directory);
|
||||||
|
|
||||||
|
|
@ -75,9 +142,9 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
for (var i = 0; i < projects.Count; i++)
|
for (var i = 0; i < projects.Count; i++)
|
||||||
{
|
{
|
||||||
var project = projects[i];
|
var project = projects[i];
|
||||||
if (project.WorkspaceProject?.FilePath != null)
|
if (project.FilePath != null)
|
||||||
{
|
{
|
||||||
if (string.Equals(directory, NormalizeDirectoryPath(Path.GetDirectoryName(project.WorkspaceProject.FilePath)), StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(directory, NormalizeDirectoryPath(Path.GetDirectoryName(project.FilePath)), StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Composition;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.CodeAnalysis.Host;
|
using Microsoft.CodeAnalysis.Host;
|
||||||
using Microsoft.CodeAnalysis.Host.Mef;
|
using Microsoft.CodeAnalysis.Host.Mef;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
@ -11,9 +15,34 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
[ExportLanguageServiceFactory(typeof(RazorProjectEngineFactoryService), RazorLanguage.Name, ServiceLayer.Default)]
|
[ExportLanguageServiceFactory(typeof(RazorProjectEngineFactoryService), RazorLanguage.Name, ServiceLayer.Default)]
|
||||||
internal class DefaultProjectEngineFactoryServiceFactory : ILanguageServiceFactory
|
internal class DefaultProjectEngineFactoryServiceFactory : ILanguageServiceFactory
|
||||||
{
|
{
|
||||||
|
private readonly Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] _customFactories;
|
||||||
|
private readonly IFallbackProjectEngineFactory _fallbackFactory;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public DefaultProjectEngineFactoryServiceFactory(
|
||||||
|
IFallbackProjectEngineFactory fallbackFactory,
|
||||||
|
[ImportMany] IEnumerable<Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>> customFactories)
|
||||||
|
{
|
||||||
|
if (fallbackFactory == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(fallbackFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customFactories == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(customFactories));
|
||||||
|
}
|
||||||
|
|
||||||
|
_fallbackFactory = fallbackFactory;
|
||||||
|
_customFactories = customFactories.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
|
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
|
||||||
{
|
{
|
||||||
return new DefaultProjectEngineFactoryService(languageServices.GetRequiredService<ProjectSnapshotManager>());
|
return new DefaultProjectEngineFactoryService(
|
||||||
|
languageServices.GetRequiredService<ProjectSnapshotManager>(),
|
||||||
|
_fallbackFactory,
|
||||||
|
_customFactories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,59 +2,45 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.CodeAnalysis;
|
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.Editor.Razor
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
{
|
{
|
||||||
internal class DefaultTagHelperResolver : TagHelperResolver
|
internal class DefaultTagHelperResolver : TagHelperResolver
|
||||||
{
|
{
|
||||||
// Hack for testability. The view component visitor will normally just no op if we're not referencing
|
private readonly RazorProjectEngineFactoryService _engineFactory;
|
||||||
// an appropriate version of MVC.
|
|
||||||
internal bool ForceEnableViewComponentDiscovery { get; set; }
|
|
||||||
|
|
||||||
public override async Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project, CancellationToken cancellationToken)
|
public DefaultTagHelperResolver(RazorProjectEngineFactoryService engineFactory)
|
||||||
|
{
|
||||||
|
if (engineFactory == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(engineFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
_engineFactory = engineFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (project == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(project));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
|
if (project.Configuration == null || project.WorkspaceProject == null)
|
||||||
var result = GetTagHelpers(compilation);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal for testing
|
|
||||||
internal TagHelperResolutionResult GetTagHelpers(Compilation compilation)
|
|
||||||
{
|
|
||||||
var descriptors = new List<TagHelperDescriptor>();
|
|
||||||
|
|
||||||
var providers = new ITagHelperDescriptorProvider[]
|
|
||||||
{
|
{
|
||||||
new DefaultTagHelperDescriptorProvider() { DesignTime = true, },
|
return Task.FromResult(TagHelperResolutionResult.Empty);
|
||||||
new ViewComponentTagHelperDescriptorProvider() { ForceEnabled = ForceEnableViewComponentDiscovery },
|
|
||||||
};
|
|
||||||
|
|
||||||
var results = new List<TagHelperDescriptor>();
|
|
||||||
var context = TagHelperDescriptorProviderContext.Create(results);
|
|
||||||
context.SetCompilation(compilation);
|
|
||||||
|
|
||||||
for (var i = 0; i < providers.Length; i++)
|
|
||||||
{
|
|
||||||
var provider = providers[i];
|
|
||||||
provider.Execute(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagnostics = new List<RazorDiagnostic>();
|
var engine = _engineFactory.Create(project, RazorProjectFileSystem.Empty, b =>
|
||||||
var resolutionResult = new TagHelperResolutionResult(results, diagnostics);
|
{
|
||||||
|
b.Features.Add(new DefaultTagHelperDescriptorProvider() { DesignTime = true, });
|
||||||
return resolutionResult;
|
});
|
||||||
|
return GetTagHelpersAsync(project, engine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
{
|
{
|
||||||
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
|
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
|
||||||
{
|
{
|
||||||
return new DefaultTagHelperResolver();
|
return new DefaultTagHelperResolver(languageServices.GetRequiredService<RazorProjectEngineFactoryService>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
[ExportCustomProjectEngineFactory("MVC-1.0", SupportsSerialization = true)]
|
||||||
|
internal class LegacyProjectEngineFactory_1_0 : IProjectEngineFactory
|
||||||
|
{
|
||||||
|
private const string AssemblyName = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X";
|
||||||
|
|
||||||
|
public RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
// Rewrite the assembly name into a full name just like this one, but with the name of the MVC design time assembly.
|
||||||
|
var assemblyName = new AssemblyName(typeof(LegacyProjectEngineFactory_1_0).Assembly.FullName);
|
||||||
|
assemblyName.Name = AssemblyName;
|
||||||
|
|
||||||
|
var extension = new AssemblyExtension(configuration.ConfigurationName, Assembly.Load(assemblyName));
|
||||||
|
var initializer = extension.CreateInitializer();
|
||||||
|
|
||||||
|
return RazorProjectEngine.Create(configuration, fileSystem, b =>
|
||||||
|
{
|
||||||
|
initializer.Initialize(b);
|
||||||
|
configure?.Invoke(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// 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;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
[ExportCustomProjectEngineFactory("MVC-1.1", SupportsSerialization = true)]
|
||||||
|
internal class LegacyProjectEngineFactory_1_1 : IProjectEngineFactory
|
||||||
|
{
|
||||||
|
private const string AssemblyName = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X";
|
||||||
|
|
||||||
|
public RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
// Rewrite the assembly name into a full name just like this one, but with the name of the MVC design time assembly.
|
||||||
|
var assemblyName = new AssemblyName(typeof(LegacyProjectEngineFactory_1_1).Assembly.FullName);
|
||||||
|
assemblyName.Name = AssemblyName;
|
||||||
|
|
||||||
|
var extension = new AssemblyExtension(configuration.ConfigurationName, Assembly.Load(assemblyName));
|
||||||
|
var initializer = extension.CreateInitializer();
|
||||||
|
|
||||||
|
return RazorProjectEngine.Create(configuration, fileSystem, b =>
|
||||||
|
{
|
||||||
|
initializer.Initialize(b);
|
||||||
|
configure?.Invoke(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// 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;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
[ExportCustomProjectEngineFactory("MVC-2.0", SupportsSerialization = true)]
|
||||||
|
internal class LegacyProjectEngineFactory_2_0 : IProjectEngineFactory
|
||||||
|
{
|
||||||
|
private const string AssemblyName = "Microsoft.AspNetCore.Mvc.Razor.Extensions";
|
||||||
|
public RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
// Rewrite the assembly name into a full name just like this one, but with the name of the MVC design time assembly.
|
||||||
|
var assemblyName = new AssemblyName(typeof(LegacyProjectEngineFactory_2_0).Assembly.FullName);
|
||||||
|
assemblyName.Name = AssemblyName;
|
||||||
|
|
||||||
|
var extension = new AssemblyExtension(configuration.ConfigurationName, Assembly.Load(assemblyName));
|
||||||
|
var initializer = extension.CreateInitializer();
|
||||||
|
|
||||||
|
return RazorProjectEngine.Create(configuration, fileSystem, b =>
|
||||||
|
{
|
||||||
|
initializer.Initialize(b);
|
||||||
|
configure?.Invoke(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// 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;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
{
|
||||||
|
// Currently we provide a fixed configuration for 2.1, but this is a point-in-time issue. We plan
|
||||||
|
// to make the 2.1 configuration more flexible and less hardcoded.
|
||||||
|
[ExportCustomProjectEngineFactory("MVC-2.1", SupportsSerialization = true)]
|
||||||
|
internal class LegacyProjectEngineFactory_2_1 : IProjectEngineFactory
|
||||||
|
{
|
||||||
|
private const string AssemblyName = "Microsoft.AspNetCore.Mvc.Razor.Extensions";
|
||||||
|
public RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
|
||||||
|
{
|
||||||
|
// Rewrite the assembly name into a full name just like this one, but with the name of the MVC design time assembly.
|
||||||
|
var assemblyName = new AssemblyName(typeof(LegacyProjectEngineFactory_2_1).Assembly.FullName);
|
||||||
|
assemblyName.Name = AssemblyName;
|
||||||
|
|
||||||
|
var extension = new AssemblyExtension(configuration.ConfigurationName, Assembly.Load(assemblyName));
|
||||||
|
var initializer = extension.CreateInitializer();
|
||||||
|
|
||||||
|
return RazorProjectEngine.Create(configuration, fileSystem, b =>
|
||||||
|
{
|
||||||
|
initializer.Initialize(b);
|
||||||
|
configure?.Invoke(b);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
|
||||||
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
|
|
||||||
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -14,23 +15,42 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
// use TagHelperResolver.
|
// use TagHelperResolver.
|
||||||
// ----------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------
|
||||||
[Export(typeof(ITagHelperResolver))]
|
[Export(typeof(ITagHelperResolver))]
|
||||||
internal class LegacyTagHelperResolver : OOPTagHelperResolver, ITagHelperResolver
|
internal class LegacyTagHelperResolver : ITagHelperResolver
|
||||||
{
|
{
|
||||||
|
private readonly Workspace _workspace;
|
||||||
|
|
||||||
[ImportingConstructor]
|
[ImportingConstructor]
|
||||||
public LegacyTagHelperResolver(
|
public LegacyTagHelperResolver([Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
||||||
[Import(typeof(VisualStudioWorkspace))] Workspace workspace)
|
|
||||||
: base(workspace)
|
|
||||||
{
|
{
|
||||||
|
if (workspace == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(workspace));
|
||||||
|
}
|
||||||
|
|
||||||
|
_workspace = workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project)
|
public Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project)
|
||||||
{
|
{
|
||||||
if (project == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentNullException(nameof(project));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetTagHelpersAsync(project, CancellationToken.None);
|
if (project.FilePath == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(TagHelperResolutionResult.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectManager = _workspace.Services.GetLanguageServices(RazorLanguage.Name).GetRequiredService<ProjectSnapshotManager>();
|
||||||
|
var projectSnapshot = projectManager.GetProjectWithFilePath(project.FilePath);
|
||||||
|
if (projectSnapshot == null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(TagHelperResolutionResult.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolver = _workspace.Services.GetLanguageServices(RazorLanguage.Name).GetRequiredService<TagHelperResolver>();
|
||||||
|
return resolver.GetTagHelpersAsync(projectSnapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
using Microsoft.VisualStudio.Editor.Razor;
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
@ -15,53 +16,67 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
internal class OOPTagHelperResolver : TagHelperResolver
|
internal class OOPTagHelperResolver : TagHelperResolver
|
||||||
{
|
{
|
||||||
private readonly DefaultTagHelperResolver _defaultResolver;
|
private readonly DefaultTagHelperResolver _defaultResolver;
|
||||||
|
private readonly RazorProjectEngineFactoryService _engineFactory;
|
||||||
|
private readonly ErrorReporter _errorReporter;
|
||||||
private readonly Workspace _workspace;
|
private readonly Workspace _workspace;
|
||||||
|
|
||||||
public OOPTagHelperResolver(Workspace workspace)
|
public OOPTagHelperResolver(RazorProjectEngineFactoryService engineFactory, ErrorReporter errorReporter, Workspace workspace)
|
||||||
{
|
{
|
||||||
|
if (engineFactory == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(engineFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorReporter == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(errorReporter));
|
||||||
|
}
|
||||||
|
|
||||||
if (workspace == null)
|
if (workspace == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(workspace));
|
throw new ArgumentNullException(nameof(workspace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_engineFactory = engineFactory;
|
||||||
|
_errorReporter = errorReporter;
|
||||||
_workspace = workspace;
|
_workspace = workspace;
|
||||||
_defaultResolver = new DefaultTagHelperResolver();
|
|
||||||
|
_defaultResolver = new DefaultTagHelperResolver(_engineFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<TagHelperResolutionResult> GetTagHelpersAsync(Project project, CancellationToken cancellationToken)
|
public override async Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (project == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(project));
|
throw new ArgumentNullException(nameof(project));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (project.Configuration == null || project.WorkspaceProject == null)
|
||||||
|
{
|
||||||
|
return TagHelperResolutionResult.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not every custom factory supports the OOP host. Our priority system should work like this:
|
||||||
|
//
|
||||||
|
// 1. Use custom factory out of process
|
||||||
|
// 2. Use custom factory in process
|
||||||
|
// 3. Use fallback factory in process
|
||||||
|
//
|
||||||
|
// Calling into RazorTemplateEngineFactoryService.Create will accomplish #2 and #3 in one step.
|
||||||
|
var factory = _engineFactory.FindSerializableFactory(project);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TagHelperResolutionResult result = null;
|
TagHelperResolutionResult result = null;
|
||||||
|
if (factory != null)
|
||||||
// We're being defensive here because the OOP host can return null for the client/session/operation
|
|
||||||
// when it's disconnected (user stops the process).
|
|
||||||
var client = await RazorLanguageServiceClientFactory.CreateAsync(_workspace, cancellationToken);
|
|
||||||
if (client != null)
|
|
||||||
{
|
{
|
||||||
using (var session = await client.CreateSessionAsync(project.Solution))
|
result = await ResolveTagHelpersOutOfProcessAsync(factory, project);
|
||||||
{
|
|
||||||
if (session != null)
|
|
||||||
{
|
|
||||||
var jsonObject = await session.InvokeAsync<JObject>(
|
|
||||||
"GetTagHelpersAsync",
|
|
||||||
new object[] { project.Id.Id, "Foo", },
|
|
||||||
cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
result = GetTagHelperResolutionResult(jsonObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
// Was unable to get tag helpers OOP, fallback to default behavior.
|
// Was unable to get tag helpers OOP, fallback to default behavior.
|
||||||
result = await _defaultResolver.GetTagHelpersAsync(project, cancellationToken);
|
result = await ResolveTagHelpersInProcessAsync(project);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -76,11 +91,61 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TagHelperResolutionResult GetTagHelperResolutionResult(JObject jsonObject)
|
protected virtual async Task<TagHelperResolutionResult> ResolveTagHelpersOutOfProcessAsync(IProjectEngineFactory factory, ProjectSnapshot project)
|
||||||
|
{
|
||||||
|
// We're being overly defensive here because the OOP host can return null for the client/session/operation
|
||||||
|
// when it's disconnected (user stops the process).
|
||||||
|
//
|
||||||
|
// This will change in the future to an easier to consume API but for VS RTM this is what we have.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = await RazorLanguageServiceClientFactory.CreateAsync(_workspace, CancellationToken.None);
|
||||||
|
if (client != null)
|
||||||
|
{
|
||||||
|
using (var session = await client.CreateSessionAsync(project.WorkspaceProject.Solution))
|
||||||
|
{
|
||||||
|
if (session != null)
|
||||||
|
{
|
||||||
|
var args = new object[]
|
||||||
|
{
|
||||||
|
Serialize(project),
|
||||||
|
factory == null ? null : factory.GetType().AssemblyQualifiedName,
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = await session.InvokeAsync<JObject>("GetTagHelpersAsync", args, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
return Deserialize(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// We silence exceptions from the OOP host because we don't want to bring down VS for an OOP failure.
|
||||||
|
// We will retry all failures in process anyway, so if there's a real problem that isn't unique to OOP
|
||||||
|
// then it will report a crash in VS.
|
||||||
|
_errorReporter.ReportError(ex, project);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Task<TagHelperResolutionResult> ResolveTagHelpersInProcessAsync(ProjectSnapshot project)
|
||||||
|
{
|
||||||
|
return _defaultResolver.GetTagHelpersAsync(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JObject Serialize(ProjectSnapshot snapshot)
|
||||||
{
|
{
|
||||||
var serializer = new JsonSerializer();
|
var serializer = new JsonSerializer();
|
||||||
serializer.Converters.Add(TagHelperDescriptorJsonConverter.Instance);
|
serializer.Converters.RegisterRazorConverters();
|
||||||
serializer.Converters.Add(RazorDiagnosticJsonConverter.Instance);
|
|
||||||
|
return JObject.FromObject(snapshot, serializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TagHelperResolutionResult Deserialize(JObject jsonObject)
|
||||||
|
{
|
||||||
|
var serializer = new JsonSerializer();
|
||||||
|
serializer.Converters.RegisterRazorConverters();
|
||||||
|
|
||||||
using (var reader = jsonObject.CreateReader())
|
using (var reader = jsonObject.CreateReader())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,10 @@ namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
{
|
{
|
||||||
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
|
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
|
||||||
{
|
{
|
||||||
var workspace = languageServices.WorkspaceServices.Workspace;
|
return new OOPTagHelperResolver(
|
||||||
return new OOPTagHelperResolver(workspace);
|
languageServices.GetRequiredService<RazorProjectEngineFactoryService>(),
|
||||||
|
languageServices.WorkspaceServices.GetRequiredService<ErrorReporter>(),
|
||||||
|
languageServices.WorkspaceServices.Workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Razor
|
||||||
|
{
|
||||||
|
internal static class JsonConverterCollectionExtensions
|
||||||
|
{
|
||||||
|
public static void RegisterRazorConverters(this JsonConverterCollection collection)
|
||||||
|
{
|
||||||
|
if (collection == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(collection));
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Add(TagHelperDescriptorJsonConverter.Instance);
|
||||||
|
collection.Add(RazorDiagnosticJsonConverter.Instance);
|
||||||
|
collection.Add(RazorExtensionJsonConverter.Instance);
|
||||||
|
collection.Add(RazorConfigurationJsonConverter.Instance);
|
||||||
|
collection.Add(ProjectSnapshotJsonConverter.Instance);
|
||||||
|
collection.Add(ProjectSnapshotHandleJsonConverter.Instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
|
||||||
|
{
|
||||||
|
internal sealed class ProjectSnapshotHandle
|
||||||
|
{
|
||||||
|
public ProjectSnapshotHandle(string filePath, RazorConfiguration configuration, ProjectId workspaceProjectId)
|
||||||
|
{
|
||||||
|
if (filePath == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath = filePath;
|
||||||
|
Configuration = configuration;
|
||||||
|
WorkspaceProjectId = workspaceProjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RazorConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public string FilePath { get; }
|
||||||
|
|
||||||
|
public ProjectId WorkspaceProjectId { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
internal class ProjectSnapshotHandleJsonConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public static readonly ProjectSnapshotHandleJsonConverter Instance = new ProjectSnapshotHandleJsonConverter();
|
||||||
|
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(ProjectSnapshotHandle).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonToken.StartObject)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = JObject.Load(reader);
|
||||||
|
var filePath = obj[nameof(ProjectSnapshotHandle.FilePath)].Value<string>();
|
||||||
|
var configuration = obj[nameof(ProjectSnapshotHandle.Configuration)].ToObject<RazorConfiguration>(serializer);
|
||||||
|
|
||||||
|
var id = obj[nameof(ProjectSnapshotHandle.WorkspaceProjectId)].Value<string>();
|
||||||
|
var workspaceProjectId = id == null ? null : ProjectId.CreateFromSerialized(Guid.Parse(id));
|
||||||
|
|
||||||
|
return new ProjectSnapshotHandle(filePath, configuration, workspaceProjectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var handle = (ProjectSnapshotHandle)value;
|
||||||
|
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WritePropertyName(nameof(ProjectSnapshotHandle.FilePath));
|
||||||
|
writer.WriteValue(handle.FilePath);
|
||||||
|
|
||||||
|
if (handle.Configuration == null)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(nameof(ProjectSnapshotHandle.Configuration));
|
||||||
|
writer.WriteNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(nameof(ProjectSnapshotHandle.Configuration));
|
||||||
|
serializer.Serialize(writer, handle.Configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle.WorkspaceProjectId == null)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(nameof(ProjectSnapshotHandle.WorkspaceProjectId));
|
||||||
|
writer.WriteNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(nameof(ProjectSnapshotHandle.WorkspaceProjectId));
|
||||||
|
writer.WriteValue(handle.WorkspaceProjectId.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
// We can't truly serialize a snapshot because it has access to a Workspace Project\
|
||||||
|
//
|
||||||
|
// Instead we serialize to a ProjectSnapshotHandle and then use that to re-create the snapshot
|
||||||
|
// inside the remote host.
|
||||||
|
internal class ProjectSnapshotJsonConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public static readonly ProjectSnapshotJsonConverter Instance = new ProjectSnapshotJsonConverter();
|
||||||
|
|
||||||
|
public override bool CanRead => false;
|
||||||
|
|
||||||
|
public override bool CanWrite => true;
|
||||||
|
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(ProjectSnapshot).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var project = (ProjectSnapshot)value;
|
||||||
|
var handle = new ProjectSnapshotHandle(project.FilePath, project.Configuration, project.WorkspaceProject?.Id);
|
||||||
|
|
||||||
|
ProjectSnapshotHandleJsonConverter.Instance.WriteJson(writer, handle, serializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
internal class RazorConfigurationJsonConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public static readonly RazorConfigurationJsonConverter Instance = new RazorConfigurationJsonConverter();
|
||||||
|
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(RazorConfiguration).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonToken.StartObject)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = JObject.Load(reader);
|
||||||
|
var configurationName = obj[nameof(RazorConfiguration.ConfigurationName)].Value<string>();
|
||||||
|
var languageVersion = obj[nameof(RazorConfiguration.LanguageVersion)].Value<string>();
|
||||||
|
var extensions = obj[nameof(RazorConfiguration.Extensions)].ToObject<RazorExtension[]>(serializer);
|
||||||
|
|
||||||
|
return RazorConfiguration.Create(RazorLanguageVersion.Parse(languageVersion), configurationName, extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var configuration = (RazorConfiguration)value;
|
||||||
|
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WritePropertyName(nameof(RazorConfiguration.ConfigurationName));
|
||||||
|
writer.WriteValue(configuration.ConfigurationName);
|
||||||
|
|
||||||
|
writer.WritePropertyName(nameof(RazorConfiguration.LanguageVersion));
|
||||||
|
writer.WriteValue(configuration.LanguageVersion.ToString());
|
||||||
|
|
||||||
|
writer.WritePropertyName(nameof(RazorConfiguration.Extensions));
|
||||||
|
serializer.Serialize(writer, configuration.Extensions);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
{
|
{
|
||||||
internal class RazorDiagnosticJsonConverter : JsonConverter
|
internal class RazorDiagnosticJsonConverter : JsonConverter
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
internal class RazorExtensionJsonConverter : JsonConverter
|
||||||
|
{
|
||||||
|
public static readonly RazorExtensionJsonConverter Instance = new RazorExtensionJsonConverter();
|
||||||
|
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(RazorExtension).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.TokenType != JsonToken.StartObject)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = JObject.Load(reader);
|
||||||
|
var extensionName = obj[nameof(RazorExtension.ExtensionName)].Value<string>();
|
||||||
|
|
||||||
|
return new SerializedRazorExtension(extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var extension = (RazorExtension)value;
|
||||||
|
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WritePropertyName(nameof(RazorExtension.ExtensionName));
|
||||||
|
writer.WriteValue(extension.ExtensionName);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// 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;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
internal class SerializedRazorExtension : RazorExtension
|
||||||
|
{
|
||||||
|
public SerializedRazorExtension(string extensionName)
|
||||||
|
{
|
||||||
|
if (extensionName == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(extensionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtensionName = extensionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ExtensionName { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
{
|
{
|
||||||
internal class TagHelperDescriptorJsonConverter : JsonConverter
|
internal class TagHelperDescriptorJsonConverter : JsonConverter
|
||||||
{
|
{
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Razor;
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
|
@ -31,28 +32,62 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
HostProject_For_1_0 = new HostProject("/TestPath/SomePath/Test.csproj", FallbackRazorConfiguration.MVC_1_0);
|
HostProject_For_1_0 = new HostProject("/TestPath/SomePath/Test.csproj", FallbackRazorConfiguration.MVC_1_0);
|
||||||
HostProject_For_1_1 = new HostProject("/TestPath/SomePath/Test.csproj", FallbackRazorConfiguration.MVC_1_1);
|
HostProject_For_1_1 = new HostProject("/TestPath/SomePath/Test.csproj", FallbackRazorConfiguration.MVC_1_1);
|
||||||
HostProject_For_2_0 = new HostProject("/TestPath/SomePath/Test.csproj", FallbackRazorConfiguration.MVC_2_0);
|
HostProject_For_2_0 = new HostProject("/TestPath/SomePath/Test.csproj", FallbackRazorConfiguration.MVC_2_0);
|
||||||
|
|
||||||
|
HostProject_For_2_1 = new HostProject(
|
||||||
|
"/TestPath/SomePath/Test.csproj",
|
||||||
|
new ProjectSystemRazorConfiguration(RazorLanguageVersion.Version_2_1, "MVC-2.1", Array.Empty<RazorExtension>()));
|
||||||
|
HostProject_For_UnknownConfiguration = new HostProject(
|
||||||
|
"/TestPath/SomePath/Test.csproj",
|
||||||
|
new ProjectSystemRazorConfiguration(RazorLanguageVersion.Version_2_1, "Blazor-0.1", Array.Empty<RazorExtension>()));
|
||||||
|
|
||||||
|
|
||||||
|
CustomFactories = new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[]
|
||||||
|
{
|
||||||
|
new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>(
|
||||||
|
() => new LegacyProjectEngineFactory_1_0(),
|
||||||
|
typeof(LegacyProjectEngineFactory_1_0).GetCustomAttribute<ExportCustomProjectEngineFactoryAttribute>()),
|
||||||
|
new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>(
|
||||||
|
() => new LegacyProjectEngineFactory_1_1(),
|
||||||
|
typeof(LegacyProjectEngineFactory_1_1).GetCustomAttribute<ExportCustomProjectEngineFactoryAttribute>()),
|
||||||
|
new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>(
|
||||||
|
() => new LegacyProjectEngineFactory_2_0(),
|
||||||
|
typeof(LegacyProjectEngineFactory_2_0).GetCustomAttribute<ExportCustomProjectEngineFactoryAttribute>()),
|
||||||
|
new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>(
|
||||||
|
() => new LegacyProjectEngineFactory_2_1(),
|
||||||
|
typeof(LegacyProjectEngineFactory_2_1).GetCustomAttribute<ExportCustomProjectEngineFactoryAttribute>()),
|
||||||
|
};
|
||||||
|
|
||||||
|
FallbackFactory = new FallbackProjectEngineFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] CustomFactories { get; }
|
||||||
|
|
||||||
|
private IFallbackProjectEngineFactory FallbackFactory { get; }
|
||||||
|
|
||||||
private HostProject HostProject_For_1_0 { get; }
|
private HostProject HostProject_For_1_0 { get; }
|
||||||
|
|
||||||
private HostProject HostProject_For_1_1 { get; }
|
private HostProject HostProject_For_1_1 { get; }
|
||||||
|
|
||||||
private HostProject HostProject_For_2_0 { get; }
|
private HostProject HostProject_For_2_0 { get; }
|
||||||
|
|
||||||
|
private HostProject HostProject_For_2_1 { get; }
|
||||||
|
|
||||||
|
private HostProject HostProject_For_UnknownConfiguration { get; }
|
||||||
|
|
||||||
// We don't actually look at the project, we rely on the ProjectStateManager
|
// We don't actually look at the project, we rely on the ProjectStateManager
|
||||||
private Project WorkspaceProject { get; }
|
private Project WorkspaceProject { get; }
|
||||||
|
|
||||||
private Workspace Workspace { get; }
|
private Workspace Workspace { get; }
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Create_CreatesTemplateEngine_ForLatest()
|
public void Create_CreatesDesignTimeTemplateEngine_ForVersion2_1()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var projectManager = new TestProjectSnapshotManager(Workspace);
|
var projectManager = new TestProjectSnapshotManager(Workspace);
|
||||||
projectManager.HostProjectAdded(HostProject_For_2_0);
|
projectManager.HostProjectAdded(HostProject_For_2_1);
|
||||||
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
|
var factoryService = new DefaultProjectEngineFactoryService(projectManager, FallbackFactory, CustomFactories);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
||||||
|
|
@ -62,6 +97,30 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperDescriptorProvider>());
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Create_CreatesDesignTimeTemplateEngine_ForVersion2_0()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var projectManager = new TestProjectSnapshotManager(Workspace);
|
||||||
|
projectManager.HostProjectAdded(HostProject_For_2_0);
|
||||||
|
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
|
var factoryService = new DefaultProjectEngineFactoryService(projectManager, FallbackFactory, CustomFactories);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
||||||
|
{
|
||||||
|
b.Features.Add(new MyCoolNewFeature());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperDescriptorProvider>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +133,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
projectManager.HostProjectAdded(HostProject_For_1_1);
|
projectManager.HostProjectAdded(HostProject_For_1_1);
|
||||||
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
|
var factoryService = new DefaultProjectEngineFactoryService(projectManager, FallbackFactory, CustomFactories);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
||||||
|
|
@ -84,6 +143,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<Mvc1_X.ViewComponentTagHelperDescriptorProvider>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<Mvc1_X.MvcViewDocumentClassifierPass>());
|
Assert.Single(engine.Engine.Features.OfType<Mvc1_X.MvcViewDocumentClassifierPass>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<Mvc1_X.ViewComponentTagHelperPass>());
|
Assert.Single(engine.Engine.Features.OfType<Mvc1_X.ViewComponentTagHelperPass>());
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +156,7 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
projectManager.HostProjectAdded(HostProject_For_1_0);
|
projectManager.HostProjectAdded(HostProject_For_1_0);
|
||||||
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
|
var factoryService = new DefaultProjectEngineFactoryService(projectManager, FallbackFactory, CustomFactories);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
||||||
|
|
@ -106,17 +166,18 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<Mvc1_X.MvcViewDocumentClassifierPass>());
|
Assert.Empty(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperDescriptorProvider>());
|
||||||
Assert.Empty(engine.Engine.Features.OfType<Mvc1_X.ViewComponentTagHelperPass>());
|
Assert.Empty(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
||||||
|
Assert.Empty(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Create_UnknownProjectPath_UsesLatest()
|
public void Create_UnknownProject_UsesVersion2_0()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var projectManager = new TestProjectSnapshotManager(Workspace);
|
var projectManager = new TestProjectSnapshotManager(Workspace);
|
||||||
|
|
||||||
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
|
var factoryService = new DefaultProjectEngineFactoryService(projectManager, FallbackFactory, CustomFactories);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var engine = factoryService.Create("/TestPath/DifferentPath/", b =>
|
var engine = factoryService.Create("/TestPath/DifferentPath/", b =>
|
||||||
|
|
@ -126,30 +187,33 @@ namespace Microsoft.VisualStudio.Editor.Razor
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
||||||
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperDescriptorProvider>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Create_MvcReferenceNotFound_UsesLatest()
|
public void Create_ForUnknownConfiguration_UsesFallbackFactory()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var projectManager = new TestProjectSnapshotManager(Workspace);
|
var projectManager = new TestProjectSnapshotManager(Workspace);
|
||||||
projectManager.HostProjectAdded(HostProject_For_2_0);
|
projectManager.HostProjectAdded(HostProject_For_UnknownConfiguration);
|
||||||
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
projectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
var factoryService = new DefaultProjectEngineFactoryService(projectManager);
|
var factoryService = new DefaultProjectEngineFactoryService(projectManager, FallbackFactory, CustomFactories);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var engine = factoryService.Create("/TestPath/DifferentPath/", b =>
|
var engine = factoryService.Create("/TestPath/SomePath/", b =>
|
||||||
{
|
{
|
||||||
b.Features.Add(new MyCoolNewFeature());
|
b.Features.Add(new MyCoolNewFeature());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
Assert.Single(engine.Engine.Features.OfType<MyCoolNewFeature>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
Assert.Empty(engine.Engine.Features.OfType<DefaultTagHelperDescriptorProvider>());
|
||||||
Assert.Single(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
Assert.Empty(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperDescriptorProvider>());
|
||||||
|
Assert.Empty(engine.Engine.Features.OfType<MvcLatest.MvcViewDocumentClassifierPass>());
|
||||||
|
Assert.Empty(engine.Engine.Features.OfType<MvcLatest.ViewComponentTagHelperPass>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyCoolNewFeature : IRazorEngineFeature
|
private class MyCoolNewFeature : IRazorEngineFeature
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common.csproj" />
|
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.csproj" />
|
||||||
<ProjectReference Include="..\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj" />
|
<ProjectReference Include="..\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Microsoft.VisualStudio.LanguageServices.Razor.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Microsoft.VisualStudio.LanguageServices.Razor.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor.Runtime\Microsoft.AspNetCore.Razor.Runtime.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor.Runtime\Microsoft.AspNetCore.Razor.Runtime.csproj" />
|
||||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor\Microsoft.AspNetCore.Razor.csproj" />
|
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Razor\Microsoft.AspNetCore.Razor.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
// 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;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Microsoft.VisualStudio.Editor.Razor;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor
|
||||||
|
{
|
||||||
|
public class OOPTagHelperResolverTest
|
||||||
|
{
|
||||||
|
public OOPTagHelperResolverTest()
|
||||||
|
{
|
||||||
|
HostProject_For_2_0 = new HostProject("Test.csproj", FallbackRazorConfiguration.MVC_2_0);
|
||||||
|
HostProject_For_NonSerializableConfiguration = new HostProject(
|
||||||
|
"Test.csproj",
|
||||||
|
new ProjectSystemRazorConfiguration(RazorLanguageVersion.Version_2_1, "Blazor-0.1", Array.Empty<RazorExtension>()));
|
||||||
|
|
||||||
|
CustomFactories = new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[]
|
||||||
|
{
|
||||||
|
new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>(
|
||||||
|
() => new LegacyProjectEngineFactory_2_0(),
|
||||||
|
typeof(LegacyProjectEngineFactory_2_0).GetCustomAttribute<ExportCustomProjectEngineFactoryAttribute>()),
|
||||||
|
|
||||||
|
// We don't really use this factory, we just use it to ensure that the call is going to go out of process.
|
||||||
|
new Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>(
|
||||||
|
() => new LegacyProjectEngineFactory_2_1(),
|
||||||
|
new ExportCustomProjectEngineFactoryAttribute("Blazor-0.1") { SupportsSerialization = false, }),
|
||||||
|
};
|
||||||
|
|
||||||
|
FallbackFactory = new FallbackProjectEngineFactory();
|
||||||
|
|
||||||
|
Workspace = new AdhocWorkspace();
|
||||||
|
|
||||||
|
var info = ProjectInfo.Create(ProjectId.CreateNewId("Test"), VersionStamp.Default, "Test", "Test", LanguageNames.CSharp, filePath: "Test.csproj");
|
||||||
|
WorkspaceProject = Workspace.CurrentSolution.AddProject(info).GetProject(info.Id);
|
||||||
|
|
||||||
|
ErrorReporter = new DefaultErrorReporter();
|
||||||
|
ProjectManager = new TestProjectSnapshotManager(Workspace);
|
||||||
|
EngineFactory = new DefaultProjectEngineFactoryService(ProjectManager, FallbackFactory, CustomFactories);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ErrorReporter ErrorReporter { get; }
|
||||||
|
|
||||||
|
private RazorProjectEngineFactoryService EngineFactory { get; }
|
||||||
|
|
||||||
|
private Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] CustomFactories { get; }
|
||||||
|
|
||||||
|
private IFallbackProjectEngineFactory FallbackFactory { get; }
|
||||||
|
|
||||||
|
private HostProject HostProject_For_2_0 { get; }
|
||||||
|
|
||||||
|
private HostProject HostProject_For_NonSerializableConfiguration { get; }
|
||||||
|
|
||||||
|
private ProjectSnapshotManagerBase ProjectManager { get; }
|
||||||
|
|
||||||
|
private Project WorkspaceProject { get; }
|
||||||
|
|
||||||
|
private Workspace Workspace { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetTagHelpersAsync_WithNonInitializedProject_Noops()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
ProjectManager.HostProjectAdded(HostProject_For_2_0);
|
||||||
|
|
||||||
|
var project = ProjectManager.GetProjectWithFilePath("Test.csproj");
|
||||||
|
|
||||||
|
var resolver = new TestTagHelperResolver(EngineFactory, ErrorReporter, Workspace);
|
||||||
|
|
||||||
|
var result = await resolver.GetTagHelpersAsync(project);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(TagHelperResolutionResult.Empty, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetTagHelpersAsync_WithSerializableCustomFactory_GoesOutOfProcess()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
ProjectManager.HostProjectAdded(HostProject_For_2_0);
|
||||||
|
ProjectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
|
var project = ProjectManager.GetProjectWithFilePath("Test.csproj");
|
||||||
|
|
||||||
|
var resolver = new TestTagHelperResolver(EngineFactory, ErrorReporter, Workspace)
|
||||||
|
{
|
||||||
|
OnResolveOutOfProcess = (f, p) =>
|
||||||
|
{
|
||||||
|
Assert.Same(CustomFactories[0].Value, f);
|
||||||
|
Assert.Same(project, p);
|
||||||
|
|
||||||
|
return Task.FromResult(TagHelperResolutionResult.Empty);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await resolver.GetTagHelpersAsync(project);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(TagHelperResolutionResult.Empty, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetTagHelpersAsync_WithNonSerializableCustomFactory_StaysInProcess()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
ProjectManager.HostProjectAdded(HostProject_For_NonSerializableConfiguration);
|
||||||
|
ProjectManager.WorkspaceProjectAdded(WorkspaceProject);
|
||||||
|
|
||||||
|
var project = ProjectManager.GetProjectWithFilePath("Test.csproj");
|
||||||
|
|
||||||
|
var resolver = new TestTagHelperResolver(EngineFactory, ErrorReporter, Workspace)
|
||||||
|
{
|
||||||
|
OnResolveInProcess = (p) =>
|
||||||
|
{
|
||||||
|
Assert.Same(project, p);
|
||||||
|
|
||||||
|
return Task.FromResult(TagHelperResolutionResult.Empty);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await resolver.GetTagHelpersAsync(project);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(TagHelperResolutionResult.Empty, result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestTagHelperResolver : OOPTagHelperResolver
|
||||||
|
{
|
||||||
|
public TestTagHelperResolver(RazorProjectEngineFactoryService engineFactory, ErrorReporter errorReporter, Workspace workspace)
|
||||||
|
: base(engineFactory, errorReporter, workspace)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<IProjectEngineFactory, ProjectSnapshot, Task<TagHelperResolutionResult>> OnResolveOutOfProcess { get; set; }
|
||||||
|
|
||||||
|
public Func<ProjectSnapshot, Task<TagHelperResolutionResult>> OnResolveInProcess { get; set; }
|
||||||
|
|
||||||
|
protected override Task<TagHelperResolutionResult> ResolveTagHelpersOutOfProcessAsync(IProjectEngineFactory factory, ProjectSnapshot project)
|
||||||
|
{
|
||||||
|
Assert.NotNull(OnResolveOutOfProcess);
|
||||||
|
return OnResolveOutOfProcess(factory, project);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<TagHelperResolutionResult> ResolveTagHelpersInProcessAsync(ProjectSnapshot project)
|
||||||
|
{
|
||||||
|
Assert.NotNull(OnResolveInProcess);
|
||||||
|
return OnResolveInProcess(project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private class TestProjectSnapshotManager : DefaultProjectSnapshotManager
|
||||||
|
{
|
||||||
|
public TestProjectSnapshotManager(Workspace workspace)
|
||||||
|
: base(
|
||||||
|
Mock.Of<ForegroundDispatcher>(),
|
||||||
|
Mock.Of<ErrorReporter>(),
|
||||||
|
Mock.Of<ProjectSnapshotWorker>(),
|
||||||
|
Enumerable.Empty<ProjectSnapshotChangeTrigger>(),
|
||||||
|
workspace)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void NotifyBackgroundWorker(ProjectSnapshotUpdateContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
// 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;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
public class ProjectSnapshotHandleSerializationTest
|
||||||
|
{
|
||||||
|
public ProjectSnapshotHandleSerializationTest()
|
||||||
|
{
|
||||||
|
var converters = new JsonConverterCollection();
|
||||||
|
converters.RegisterRazorConverters();
|
||||||
|
Converters = converters.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonConverter[] Converters { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProjectSnapshotHandleJsonConverter_Serialization_CanKindaRoundTrip()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var snapshot = new ProjectSnapshotHandle(
|
||||||
|
"Test.csproj",
|
||||||
|
new ProjectSystemRazorConfiguration(
|
||||||
|
RazorLanguageVersion.Version_1_1,
|
||||||
|
"Test",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new ProjectSystemRazorExtension("Test-Extension1"),
|
||||||
|
new ProjectSystemRazorExtension("Test-Extension2"),
|
||||||
|
}),
|
||||||
|
ProjectId.CreateFromSerialized(Guid.NewGuid(), "Test"));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var json = JsonConvert.SerializeObject(snapshot, Converters);
|
||||||
|
var obj = JsonConvert.DeserializeObject<ProjectSnapshotHandle>(json, Converters);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(snapshot.FilePath, obj.FilePath);
|
||||||
|
Assert.Equal(snapshot.Configuration.ConfigurationName, obj.Configuration.ConfigurationName);
|
||||||
|
Assert.Collection(
|
||||||
|
snapshot.Configuration.Extensions,
|
||||||
|
e => Assert.Equal("Test-Extension1", e.ExtensionName),
|
||||||
|
e => Assert.Equal("Test-Extension2", e.ExtensionName));
|
||||||
|
Assert.Equal(snapshot.Configuration.LanguageVersion, obj.Configuration.LanguageVersion);
|
||||||
|
Assert.Equal(snapshot.WorkspaceProjectId.Id, obj.WorkspaceProjectId.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ProjectSnapshotHandleJsonConverter_SerializationWithNulls_CanKindaRoundTrip()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var snapshot = new ProjectSnapshotHandle("Test.csproj", null, null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var json = JsonConvert.SerializeObject(snapshot, Converters);
|
||||||
|
var obj = JsonConvert.DeserializeObject<ProjectSnapshotHandle>(json, Converters);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(snapshot.FilePath, obj.FilePath);
|
||||||
|
Assert.Null(obj.Configuration);
|
||||||
|
Assert.Null(obj.WorkspaceProjectId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
public class RazorConfigurationSerializationTest
|
||||||
|
{
|
||||||
|
public RazorConfigurationSerializationTest()
|
||||||
|
{
|
||||||
|
var converters = new JsonConverterCollection();
|
||||||
|
converters.RegisterRazorConverters();
|
||||||
|
Converters = converters.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonConverter[] Converters { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RazorConfigurationJsonConverter_Serialization_CanRoundTrip()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var configuration = new ProjectSystemRazorConfiguration(
|
||||||
|
RazorLanguageVersion.Version_1_1,
|
||||||
|
"Test",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new ProjectSystemRazorExtension("Test-Extension1"),
|
||||||
|
new ProjectSystemRazorExtension("Test-Extension2"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var json = JsonConvert.SerializeObject(configuration, Converters);
|
||||||
|
var obj = JsonConvert.DeserializeObject<RazorConfiguration>(json, Converters);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(configuration.ConfigurationName, obj.ConfigurationName);
|
||||||
|
Assert.Collection(
|
||||||
|
configuration.Extensions,
|
||||||
|
e => Assert.Equal("Test-Extension1", e.ExtensionName),
|
||||||
|
e => Assert.Equal("Test-Extension2", e.ExtensionName));
|
||||||
|
Assert.Equal(configuration.LanguageVersion, obj.LanguageVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
|
using Microsoft.CodeAnalysis.Razor;
|
||||||
|
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.VisualStudio.LanguageServices.Razor.Serialization
|
||||||
|
{
|
||||||
|
public class RazorExtensionSerializationTest
|
||||||
|
{
|
||||||
|
public RazorExtensionSerializationTest()
|
||||||
|
{
|
||||||
|
var converters = new JsonConverterCollection();
|
||||||
|
converters.RegisterRazorConverters();
|
||||||
|
Converters = converters.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonConverter[] Converters { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RazorExensionJsonConverter_Serialization_CanRoundTrip()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var extension = new ProjectSystemRazorExtension("Test");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var json = JsonConvert.SerializeObject(extension, Converters);
|
||||||
|
var obj = JsonConvert.DeserializeObject<RazorExtension>(json, Converters);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(extension.ExtensionName, obj.ExtensionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Razor.Language;
|
using Microsoft.AspNetCore.Razor.Language;
|
||||||
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
using Microsoft.AspNetCore.Razor.Language.Legacy;
|
||||||
|
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -177,7 +177,8 @@ namespace Microsoft.VisualStudio.RazorExtension.RazorInfo
|
||||||
.Select(reference => reference.Display)
|
.Select(reference => reference.Display)
|
||||||
.Select(filter => Path.GetFileNameWithoutExtension(filter));
|
.Select(filter => Path.GetFileNameWithoutExtension(filter));
|
||||||
var projectFilters = project.AllProjectReferences.Select(filter => solution.GetProject(filter.ProjectId).AssemblyName);
|
var projectFilters = project.AllProjectReferences.Select(filter => solution.GetProject(filter.ProjectId).AssemblyName);
|
||||||
var resolutionResult = await _tagHelperResolver.GetTagHelpersAsync(project, CancellationToken.None);
|
|
||||||
|
var resolutionResult = await _tagHelperResolver.GetTagHelpersAsync(projectViewModel.Snapshot.Project);
|
||||||
|
|
||||||
var files = GetCshtmlDocuments(project);
|
var files = GetCshtmlDocuments(project);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue