-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Module.cs
163 lines (139 loc) · 6.22 KB
/
Module.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.FileProviders.Embedded;
namespace OrchardCore.Modules
{
using Manifest;
public class Module
{
public const string WebRootPath = "wwwroot";
public const string WebRoot = WebRootPath + "/";
private readonly string _baseNamespace;
private readonly DateTimeOffset _lastModified;
private readonly IDictionary<string, IFileInfo> _fileInfos = new Dictionary<string, IFileInfo>();
// TODO: MWP: trace back to usage, etc...
// TODO: MWP: perhaps we filter up front so we are not discovering all this during ctor...
// TODO: MWP: 'that' being the Module Context, etc...
/// <summary>
/// Constructs an instance of the Module.
/// </summary>
/// <param name="assyName">The assembly name to use when loading itself.</param>
/// <param name="isApplication">Whether the Module may be considered to be the "Application".</param>
public Module(string assyName, bool isApplication = false)
{
if (!String.IsNullOrWhiteSpace(assyName))
{
Assembly = Assembly.Load(new AssemblyName(assyName));
Assets = Assembly.GetCustomAttributes<ModuleAssetAttribute>()
.Select(a => new Asset(a.Asset)).ToArray();
AssetPaths = Assets.Select(a => a.ModuleAssetPath).ToArray();
// TODO: MWP: so we are 'aware' multiple instances are popping up, then...
var moduleInfos = Assembly.GetCustomAttributes<ModuleAttribute>();
ModuleInfo =
moduleInfos.Where(f => f is not ModuleMarkerAttribute).FirstOrDefault() ??
moduleInfos.Where(f => f is ModuleMarkerAttribute).FirstOrDefault() ??
// This is better use the default parameterless ctor and assign the property
new ModuleAttribute() { Name = assyName };
var features = Assembly.GetCustomAttributes<Manifest.FeatureAttribute>()
.Where(f => f is not ModuleAttribute).ToList();
if (isApplication)
{
ModuleInfo.Name = Application.ModuleName;
ModuleInfo.Description = Application.ModuleDescription;
ModuleInfo.Priority = Application.ModulePriority;
ModuleInfo.Category = Application.ModuleCategory;
ModuleInfo.DefaultTenantOnly = true;
// Adds the application primary feature.
features.Insert(0, new Manifest.FeatureAttribute(
assyName
, Application.ModuleName
, Application.ModuleCategory
, Application.ModulePriority
, Application.ModuleDescription
, null
, true
, default
, default
));
// Adds the application default feature.
features.Insert(1, new Manifest.FeatureAttribute(
Application.DefaultFeatureId
, Application.DefaultFeatureName
, Application.ModuleCategory
, Application.ModulePriority
, Application.DefaultFeatureDescription
, null
, true
, default
, default
));
}
ModuleInfo.Features.AddRange(features);
// The 'ModuleInfo.Id' allows a module project to change its 'AssemblyName'
// without to update the code. If not provided, the assembly name is used.
var logicalName = ModuleInfo.Id ?? assyName;
Name = ModuleInfo.Id = logicalName;
SubPath = Application.ModulesRoot + Name;
Root = SubPath + '/';
}
else
{
Name = Root = SubPath = String.Empty;
Assets = Enumerable.Empty<Asset>();
AssetPaths = Enumerable.Empty<string>();
ModuleInfo = new ModuleAttribute();
}
_baseNamespace = Name + '.';
_lastModified = DateTimeOffset.UtcNow;
if (!String.IsNullOrEmpty(Assembly?.Location))
{
try
{
_lastModified = File.GetLastWriteTimeUtc(Assembly.Location);
}
catch (PathTooLongException)
{
}
catch (UnauthorizedAccessException)
{
}
}
}
public string Name { get; }
public string Root { get; }
public string SubPath { get; }
public Assembly Assembly { get; }
public IEnumerable<Asset> Assets { get; }
public IEnumerable<string> AssetPaths { get; }
public ModuleAttribute ModuleInfo { get; }
public IFileInfo GetFileInfo(string subpath)
{
if (!_fileInfos.TryGetValue(subpath, out var fileInfo))
{
if (!AssetPaths.Contains(Root + subpath))
{
return new NotFoundFileInfo(subpath);
}
lock (_fileInfos)
{
if (!_fileInfos.TryGetValue(subpath, out fileInfo))
{
var resourcePath = _baseNamespace + subpath.Replace('/', '>');
var fileName = Path.GetFileName(subpath);
if (Assembly.GetManifestResourceInfo(resourcePath) == null)
{
return new NotFoundFileInfo(fileName);
}
_fileInfos[subpath] = fileInfo = new EmbeddedResourceFileInfo(
Assembly, resourcePath, fileName, _lastModified);
}
}
}
return fileInfo;
}
}
}