-
Notifications
You must be signed in to change notification settings - Fork 12
/
AspNetCoreMvcExtensions.cs
132 lines (109 loc) · 6.35 KB
/
AspNetCoreMvcExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewComponents;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.DependencyInjection;
namespace MissingDIExtensions
{
public static class AspNetCoreMvcExtensions
{
public static void AddCustomControllerActivation(this IServiceCollection services, Func<Type, object> activator)
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (activator == null) throw new ArgumentNullException(nameof(activator));
services.AddSingleton<IControllerActivator>(new DelegatingControllerActivator(
context => activator(context.ActionDescriptor.ControllerTypeInfo.AsType())));
}
public static void AddCustomViewComponentActivation(this IServiceCollection services, Func<Type, object> activator)
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (activator == null) throw new ArgumentNullException(nameof(activator));
services.AddSingleton<IViewComponentActivator>(new DelegatingViewComponentActivator(activator));
}
public static void AddCustomTagHelperActivation(this IServiceCollection services, Func<Type, object> activator,
Predicate<Type> applicationTypeSelector = null)
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (activator == null) throw new ArgumentNullException(nameof(activator));
// There are tag helpers OOTB in MVC. Letting the application container try to create them will fail
// because of the dependencies these tag helpers have. This means that OOTB tag helpers need to remain
// created by the framework's DefaultTagHelperActivator, hence the selector predicate.
applicationTypeSelector =
applicationTypeSelector ?? (type => !type.GetTypeInfo().Namespace.StartsWith("Microsoft"));
services.AddSingleton<ITagHelperActivator>(provider =>
new DelegatingTagHelperActivator(
customCreatorSelector: applicationTypeSelector,
customTagHelperCreator: activator,
defaultTagHelperActivator:
new DefaultTagHelperActivator(provider.GetRequiredService<ITypeActivatorCache>())));
}
public static Type[] GetControllerTypes(this IApplicationBuilder builder)
{
var manager = builder.ApplicationServices.GetRequiredService<ApplicationPartManager>();
var feature = new ControllerFeature();
manager.PopulateFeature(feature);
return feature.Controllers.Select(t => t.AsType()).ToArray();
}
public static Type[] GetViewComponentTypes(this IApplicationBuilder builder)
{
var manager = builder.ApplicationServices.GetRequiredService<ApplicationPartManager>();
var feature = new ViewComponentFeature();
manager.PopulateFeature(feature);
return feature.ViewComponents.Select(t => t.AsType()).ToArray();
}
}
public sealed class DelegatingControllerActivator : IControllerActivator
{
private readonly Func<ControllerContext, object> controllerCreator;
private readonly Action<ControllerContext, object> controllerReleaser;
public DelegatingControllerActivator(Func<ControllerContext, object> controllerCreator,
Action<ControllerContext, object> controllerReleaser = null)
{
this.controllerCreator = controllerCreator ?? throw new ArgumentNullException(nameof(controllerCreator));
this.controllerReleaser = controllerReleaser ?? ((_, __) => { });
}
public object Create(ControllerContext context) => this.controllerCreator(context);
public void Release(ControllerContext context, object controller) => this.controllerReleaser(context, controller);
}
public sealed class DelegatingViewComponentActivator : IViewComponentActivator
{
private readonly Func<Type, object> viewComponentCreator;
private readonly Action<object> viewComponentReleaser;
public DelegatingViewComponentActivator(Func<Type, object> viewComponentCreator,
Action<object> viewComponentReleaser = null)
{
this.viewComponentCreator = viewComponentCreator ?? throw new ArgumentNullException(nameof(viewComponentCreator));
this.viewComponentReleaser = viewComponentReleaser ?? (_ => { });
}
public object Create(ViewComponentContext context) =>
this.viewComponentCreator(context.ViewComponentDescriptor.TypeInfo.AsType());
public void Release(ViewComponentContext context, object viewComponent) =>
this.viewComponentReleaser(viewComponent);
}
internal sealed class DelegatingTagHelperActivator : ITagHelperActivator
{
private readonly Predicate<Type> customCreatorSelector;
private readonly Func<Type, object> customTagHelperCreator;
private readonly ITagHelperActivator defaultTagHelperActivator;
public DelegatingTagHelperActivator(Predicate<Type> customCreatorSelector, Func<Type, object> customTagHelperCreator,
ITagHelperActivator defaultTagHelperActivator)
{
this.customCreatorSelector = customCreatorSelector ?? throw new ArgumentNullException(nameof(customCreatorSelector));
this.customTagHelperCreator = customTagHelperCreator ?? throw new ArgumentNullException(nameof(customTagHelperCreator));
this.defaultTagHelperActivator = defaultTagHelperActivator ?? throw new ArgumentNullException(nameof(defaultTagHelperActivator));
}
public TTagHelper Create<TTagHelper>(ViewContext context) where TTagHelper : ITagHelper =>
this.customCreatorSelector(typeof(TTagHelper))
? (TTagHelper)this.customTagHelperCreator(typeof(TTagHelper))
: defaultTagHelperActivator.Create<TTagHelper>(context);
}
}