Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit acb9682

Browse files
committed
[Fixes #4087] Add AddViewComponentsAsServices() and ServiceBasedViewComponentActivator
1 parent aa6a547 commit acb9682

File tree

7 files changed

+112
-32
lines changed

7 files changed

+112
-32
lines changed

src/Microsoft.AspNetCore.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Linq;
56
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.AspNetCore.Mvc.ViewComponents;
8+
using Microsoft.Extensions.DependencyInjection.Extensions;
69

710
namespace Microsoft.Extensions.DependencyInjection
811
{
@@ -33,5 +36,20 @@ public static IMvcBuilder AddViewOptions(
3336
builder.Services.Configure(setupAction);
3437
return builder;
3538
}
39+
40+
public static IMvcBuilder AddViewComponentsAsServices(this IMvcBuilder builder)
41+
{
42+
var feature = new ViewComponentsFeature();
43+
builder.Manager.PopulateFeature(feature);
44+
45+
foreach (var viewComponent in feature.ViewComponents.Select(vc => vc.AsType()))
46+
{
47+
builder.Services.TryAddTransient(viewComponent, viewComponent);
48+
}
49+
50+
builder.Services.Replace(ServiceDescriptor.Transient<IViewComponentActivator, ServiceBasedViewComponentActivator>());
51+
52+
return builder;
53+
}
3654
}
3755
}

src/Microsoft.AspNetCore.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcCoreBuilderExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
using System;
55
using System.Buffers;
6+
using System.Linq;
67
using Microsoft.AspNetCore.Mvc;
8+
using Microsoft.AspNetCore.Mvc.ApplicationParts;
79
using Microsoft.AspNetCore.Mvc.Controllers;
810
using Microsoft.AspNetCore.Mvc.Formatters;
911
using Microsoft.AspNetCore.Mvc.Rendering;
@@ -26,10 +28,19 @@ public static IMvcCoreBuilder AddViews(this IMvcCoreBuilder builder)
2628
}
2729

2830
builder.AddDataAnnotations();
31+
AddViewApplicationPartsProviders(builder.Manager);
2932
AddViewServices(builder.Services);
3033
return builder;
3134
}
3235

36+
private static void AddViewApplicationPartsProviders(ApplicationPartManager manager)
37+
{
38+
if (!manager.Providers.OfType<ViewComponentsFeatureProvider>().Any())
39+
{
40+
manager.Providers.Add(new ViewComponentsFeatureProvider());
41+
}
42+
}
43+
3344
public static IMvcCoreBuilder AddViews(
3445
this IMvcCoreBuilder builder,
3546
Action<MvcViewOptions> setupAction)

src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewComponents/DefaultViewComponentDescriptorProvider.cs

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Linq;
77
using System.Reflection;
88
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Mvc.ApplicationParts;
910
using Microsoft.AspNetCore.Mvc.Infrastructure;
1011
using Microsoft.AspNetCore.Mvc.ViewFeatures;
1112

@@ -18,64 +19,47 @@ public class DefaultViewComponentDescriptorProvider : IViewComponentDescriptorPr
1819
{
1920
private const string AsyncMethodName = "InvokeAsync";
2021
private const string SyncMethodName = "Invoke";
21-
private readonly IAssemblyProvider _assemblyProvider;
22+
private readonly ApplicationPartManager _manager;
2223

2324
/// <summary>
2425
/// Creates a new <see cref="DefaultViewComponentDescriptorProvider"/>.
2526
/// </summary>
26-
/// <param name="assemblyProvider">The <see cref="IAssemblyProvider"/>.</param>
27-
public DefaultViewComponentDescriptorProvider(IAssemblyProvider assemblyProvider)
27+
/// <param name="manager">The <see cref="ApplicationPartManager"/>.</param>
28+
public DefaultViewComponentDescriptorProvider(ApplicationPartManager manager)
2829
{
29-
_assemblyProvider = assemblyProvider;
30+
if (manager == null)
31+
{
32+
throw new ArgumentNullException(nameof(manager));
33+
}
34+
35+
_manager = manager;
3036
}
3137

3238
/// <inheritdoc />
3339
public virtual IEnumerable<ViewComponentDescriptor> GetViewComponents()
3440
{
35-
var types = GetCandidateTypes();
36-
37-
return types
38-
.Where(IsViewComponentType)
39-
.Select(CreateDescriptor);
41+
return GetCandidateTypes().Select(CreateDescriptor);
4042
}
4143

4244
/// <summary>
43-
/// Gets the candidate <see cref="TypeInfo"/> instances. The results of this will be provided to
44-
/// <see cref="IsViewComponentType"/> for filtering.
45+
/// Gets the candidate <see cref="TypeInfo"/> instances provided by the <see cref="ApplicationPartManager"/>.
4546
/// </summary>
4647
/// <returns>A list of <see cref="TypeInfo"/> instances.</returns>
4748
protected virtual IEnumerable<TypeInfo> GetCandidateTypes()
4849
{
49-
var assemblies = _assemblyProvider.CandidateAssemblies;
50-
return assemblies.SelectMany(a => a.ExportedTypes).Select(t => t.GetTypeInfo());
51-
}
52-
53-
/// <summary>
54-
/// Determines whether or not the given <see cref="TypeInfo"/> is a view component class.
55-
/// </summary>
56-
/// <param name="typeInfo">The <see cref="TypeInfo"/>.</param>
57-
/// <returns>
58-
/// <c>true</c> if <paramref name="typeInfo"/>represents a view component class, otherwise <c>false</c>.
59-
/// </returns>
60-
protected virtual bool IsViewComponentType(TypeInfo typeInfo)
61-
{
62-
if (typeInfo == null)
63-
{
64-
throw new ArgumentNullException(nameof(typeInfo));
65-
}
66-
67-
return ViewComponentConventions.IsComponent(typeInfo);
50+
var feature = new ViewComponentsFeature();
51+
_manager.PopulateFeature(feature);
52+
return feature.ViewComponents;
6853
}
6954

7055
private static ViewComponentDescriptor CreateDescriptor(TypeInfo typeInfo)
7156
{
72-
var type = typeInfo.AsType();
7357
var candidate = new ViewComponentDescriptor
7458
{
7559
FullName = ViewComponentConventions.GetComponentFullName(typeInfo),
7660
ShortName = ViewComponentConventions.GetComponentName(typeInfo),
7761
TypeInfo = typeInfo,
78-
MethodInfo = FindMethod(type)
62+
MethodInfo = FindMethod(typeInfo.AsType())
7963
};
8064

8165
return candidate;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.Extensions.DependencyInjection;
6+
7+
namespace Microsoft.AspNetCore.Mvc.ViewComponents
8+
{
9+
public class ServiceBasedViewComponentActivator : IViewComponentActivator
10+
{
11+
public object Create(ViewComponentContext context)
12+
{
13+
if (context == null)
14+
{
15+
throw new ArgumentNullException(nameof(context));
16+
}
17+
18+
var controllerType = context.ViewComponentDescriptor.TypeInfo.AsType();
19+
20+
return context.ViewContext.HttpContext.RequestServices.GetRequiredService(controllerType);
21+
}
22+
23+
public virtual void Release(ViewComponentContext context, object viewComponent)
24+
{
25+
}
26+
}
27+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using System.Threading.Tasks;
6+
7+
namespace Microsoft.AspNetCore.Mvc.ViewComponents
8+
{
9+
public class ViewComponentsFeature
10+
{
11+
public IList<TypeInfo> ViewComponents { get; } = new List<TypeInfo>();
12+
}
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Mvc.ApplicationParts;
6+
7+
namespace Microsoft.AspNetCore.Mvc.ViewComponents
8+
{
9+
public class ViewComponentsFeatureProvider : IApplicationFeatureProvider<ViewComponentsFeature>
10+
{
11+
public void GetFeature(IEnumerable<ApplicationPart> parts, ViewComponentsFeature feature)
12+
{
13+
foreach (var type in parts.OfType<IExportTypes>().SelectMany(p => p.Types))
14+
{
15+
if (ViewComponentConventions.IsComponent(type) && ! feature.ViewComponents.Contains(type))
16+
{
17+
feature.ViewComponents.Add(type);
18+
}
19+
}
20+
}
21+
}
22+
}

test/Microsoft.AspNetCore.Mvc.FunctionalTests/MvcTestFixture.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
using Microsoft.AspNetCore.Mvc.ApplicationParts;
1111
using Microsoft.AspNetCore.Mvc.Controllers;
1212
using Microsoft.AspNetCore.Mvc.Infrastructure;
13+
14+
using Microsoft.AspNetCore.Mvc.ViewComponents;
1315
using Microsoft.AspNetCore.TestHost;
1416
using Microsoft.AspNetCore.Testing;
1517
using Microsoft.Extensions.DependencyInjection;
@@ -72,7 +74,10 @@ protected virtual void InitializeServices(IServiceCollection services)
7274

7375
var manager = new ApplicationPartManager();
7476
manager.ApplicationParts.Add(new AssemblyPart(startupAssembly));
77+
7578
manager.FeatureProviders.Add(new ControllerFeatureProvider());
79+
manager.FeatureProviders.Add(new ViewComponentsFeatureProvider());
80+
7681
services.AddSingleton(manager);
7782
}
7883

0 commit comments

Comments
 (0)