forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathApplicationPartRegistry.cs
More file actions
145 lines (123 loc) · 5.91 KB
/
Copy pathApplicationPartRegistry.cs
File metadata and controls
145 lines (123 loc) · 5.91 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
// 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.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Web.WebPages.Resources;
namespace System.Web.WebPages.ApplicationParts
{
internal class ApplicationPartRegistry
{
// Page types that we could serve
private static readonly Type _webPageType = typeof(WebPageRenderingBase);
private readonly DictionaryBasedVirtualPathFactory _virtualPathFactory;
private readonly ConcurrentDictionary<string, bool> _registeredVirtualPaths;
private readonly ConcurrentDictionary<IResourceAssembly, ApplicationPart> _applicationParts;
public ApplicationPartRegistry(DictionaryBasedVirtualPathFactory pathFactory)
{
_applicationParts = new ConcurrentDictionary<IResourceAssembly, ApplicationPart>();
_registeredVirtualPaths = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
_virtualPathFactory = pathFactory;
}
public IEnumerable<ApplicationPart> RegisteredParts
{
get { return _applicationParts.Values; }
}
public ApplicationPart this[string name]
{
get { return _applicationParts.Values.FirstOrDefault(appPart => appPart.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); }
}
public ApplicationPart this[IResourceAssembly assembly]
{
get
{
ApplicationPart part;
if (!_applicationParts.TryGetValue(assembly, out part))
{
part = null;
}
return part;
}
}
// Register an assembly as an application module, which makes its compiled web pages
// and embedded resources available
public void Register(ApplicationPart applicationPart)
{
Register(applicationPart, registerPageAction: null); // Use default action which creates a new page
}
// Register an assembly as an application module, which makes its compiled web pages
// and embedded resources available
internal void Register(ApplicationPart applicationPart, Func<object> registerPageAction)
{
// Throw if this assembly has been registered
if (_applicationParts.ContainsKey(applicationPart.Assembly))
{
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture,
WebPageResources.ApplicationPart_ModuleAlreadyRegistered, applicationPart.Assembly));
}
// Throw if the virtual path is already in use
if (_registeredVirtualPaths.ContainsKey(applicationPart.RootVirtualPath))
{
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentCulture,
WebPageResources.ApplicationPart_ModuleAlreadyRegisteredForVirtualPath, applicationPart.RootVirtualPath));
}
// REVIEW: Should we register the app-part after we scan the assembly for webpages?
// Add the part to the list
if (_applicationParts.TryAdd(applicationPart.Assembly, applicationPart))
{
// We don't really care about the value
_registeredVirtualPaths.TryAdd(applicationPart.RootVirtualPath, true);
// Get all of the web page types
var webPageTypes = from type in applicationPart.Assembly.GetTypes()
where type.IsSubclassOf(_webPageType)
select type;
// Register each of page with the plan9
foreach (Type webPageType in webPageTypes)
{
RegisterWebPage(applicationPart, webPageType, registerPageAction);
}
}
}
private void RegisterWebPage(ApplicationPart module, Type webPageType, Func<object> registerPageAction)
{
var virtualPathAttribute = webPageType.GetCustomAttributes(typeof(PageVirtualPathAttribute), false)
.Cast<PageVirtualPathAttribute>()
.SingleOrDefault();
// Ignore it if it doesn't have a PageVirtualPathAttribute
if (virtualPathAttribute == null)
{
return;
}
// Get the path of the page relative to the module root
string virtualPath = GetRootRelativeVirtualPath(module.RootVirtualPath, virtualPathAttribute.VirtualPath);
// Create a factory for the page type
Func<object> pageFactory = registerPageAction ?? NewTypeInstance(webPageType);
// Register a page factory for it
_virtualPathFactory.RegisterPath(virtualPath, pageFactory);
}
private static Func<object> NewTypeInstance(Type type)
{
return Expression.Lambda<Func<object>>(Expression.New(type)).Compile();
}
internal static string GetRootRelativeVirtualPath(string rootVirtualPath, string pageVirtualPath)
{
string virtualPath = pageVirtualPath;
// Trim the ~/ prefix, since we want it to be relative to the module base path
if (virtualPath.StartsWith("~/", StringComparison.Ordinal))
{
virtualPath = virtualPath.Substring(2);
}
if (!rootVirtualPath.EndsWith("/", StringComparison.OrdinalIgnoreCase))
{
rootVirtualPath += "/";
}
// Combine it with the root
virtualPath = VirtualPathUtility.Combine(rootVirtualPath, virtualPath);
return virtualPath;
}
}
}