Skip to content
This repository has been archived by the owner on Feb 23, 2021. It is now read-only.

Commit

Permalink
Added design time support for ViewComponent TagHelpers
Browse files Browse the repository at this point in the history
  • Loading branch information
ajaybhargavb committed Sep 24, 2016
1 parent f3240cc commit bf3a26f
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,26 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Razor.Compilation.TagHelpers;
using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Razor.Design.Internal
{
public class AssemblyTagHelperDescriptorResolver
{
private readonly TagHelperDescriptorFactory _descriptorFactory = new TagHelperDescriptorFactory(designTime: true);
private const string TypeFullName = "Microsoft.AspNetCore.Mvc.DesignTimeMvcServiceCollectionProvider";
private const string MvcAssemblyName = "Microsoft.AspNetCore.Mvc";
private const string MethodName = "PopulateServiceCollection";

private readonly TagHelperDescriptorFactory _tagHelperDescriptorFactory;
private readonly TagHelperTypeResolver _tagHelperTypeResolver;

private bool _isInitialized;
private Action<IServiceCollection, string> _populateMethodDelegate;

public AssemblyTagHelperDescriptorResolver()
: this(new TagHelperTypeResolver())
{
Expand All @@ -22,6 +32,7 @@ public AssemblyTagHelperDescriptorResolver()
public AssemblyTagHelperDescriptorResolver(TagHelperTypeResolver tagHelperTypeResolver)
{
_tagHelperTypeResolver = tagHelperTypeResolver;
_tagHelperDescriptorFactory = new TagHelperDescriptorFactory(designTime: true);
}

public static int DefaultProtocolVersion { get; } = 1;
Expand All @@ -35,19 +46,7 @@ public IEnumerable<TagHelperDescriptor> Resolve(string assemblyName, ErrorSink e
throw new ArgumentNullException(nameof(assemblyName));
}

if (ProtocolVersion == 1)
{
var tagHelperTypes = GetTagHelperTypes(assemblyName, errorSink);
var tagHelperDescriptors = new List<TagHelperDescriptor>();
foreach (var tagHelperType in tagHelperTypes)
{
var descriptors = _descriptorFactory.CreateDescriptors(assemblyName, tagHelperType, errorSink);
tagHelperDescriptors.AddRange(descriptors);
}

return tagHelperDescriptors;
}
else
if (ProtocolVersion != 1)
{
// Unknown protocol
throw new InvalidOperationException(
Expand All @@ -56,6 +55,39 @@ public IEnumerable<TagHelperDescriptor> Resolve(string assemblyName, ErrorSink e
DesignResources.InvalidProtocolValue,
typeof(TagHelperDescriptor).FullName, ProtocolVersion));
}

EnsureMvcInitialized();

ITagHelperDescriptorResolver resolver;
if (_populateMethodDelegate != null)
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ITagHelperTypeResolver>(_tagHelperTypeResolver);
serviceCollection.AddSingleton<ITagHelperDescriptorFactory>(_tagHelperDescriptorFactory);

// Populate the service collection
_populateMethodDelegate(serviceCollection, assemblyName);

var services = serviceCollection.BuildServiceProvider();
resolver = services.GetRequiredService<ITagHelperDescriptorResolver>();
}
else
{
// MVC assembly does not exist. Manually create the resolver.
resolver = new TagHelperDescriptorResolver(_tagHelperTypeResolver, _tagHelperDescriptorFactory);
}

var directiveDescriptors = new[]
{
new TagHelperDirectiveDescriptor
{
DirectiveText = $"*, {assemblyName}"
}
};
var context = new TagHelperDescriptorResolutionContext(directiveDescriptors, errorSink);
var descriptors = resolver.Resolve(context);

return descriptors;
}

/// <summary>
Expand All @@ -65,5 +97,34 @@ protected virtual IEnumerable<Type> GetTagHelperTypes(string assemblyName, Error
{
return _tagHelperTypeResolver.Resolve(assemblyName, SourceLocation.Zero, errorSink);
}

private void EnsureMvcInitialized()
{
if (_isInitialized)
{
return;
}

_isInitialized = true;

var providerClass = Type.GetType($"{TypeFullName}, {MvcAssemblyName}");

// Get the method from the type
var populateMethod = providerClass?.GetMethods(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(methodInfo =>
{
if (string.Equals(MethodName, methodInfo.Name, StringComparison.Ordinal))
{
var methodParams = methodInfo.GetParameters();
return methodParams.Length == 2
&& methodParams[0].ParameterType.Equals(typeof(IServiceCollection))
&& methodParams[1].ParameterType.Equals(typeof(string));
}
return false;
});

_populateMethodDelegate = (Action<IServiceCollection, string>) populateMethod
?.CreateDelegate(typeof(Action<IServiceCollection, string>));
}
}
}
7 changes: 6 additions & 1 deletion src/Microsoft.AspNetCore.Razor.Design/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"dependencies": {
"Microsoft.AspNetCore.Razor.Runtime": "1.1.0-*",
"Microsoft.Extensions.CommandLineUtils": "1.1.0-*",
"Microsoft.Extensions.DependencyInjection": "1.1.0-*",
"Newtonsoft.Json": "9.0.1"
},
"frameworks": {
Expand All @@ -49,6 +50,10 @@
}
}
},
"net451": {}
"net451": {
"frameworkAssemblies": {
"System.Runtime": ""
}
}
}
}

0 comments on commit bf3a26f

Please sign in to comment.