-
Notifications
You must be signed in to change notification settings - Fork 42
/
Vpp.cs
253 lines (213 loc) · 9.1 KB
/
Vpp.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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
using System.Linq;
using System.Text.RegularExpressions;
namespace EmbeddedResourceVirtualPathProvider
{
public class Vpp : VirtualPathProvider, IEnumerable
{
readonly Dictionary<string, Dictionary<string, List<EmbeddedResource>>> resources = new Dictionary<string, Dictionary<string, List<EmbeddedResource>>>();
Regex pathPattern = new Regex(@"^(?<directory>.*?)?\.(?<filename>[^.]*([\.-](?<version>[0-9]{1,5}\.[0-9]{1,5}\.[0-9]{1,5})(\.min)?)?\.[^.]*)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public Vpp(params Assembly[] assemblies)
{
UseResource = er => true;
UseLocalIfAvailable = resource => true;
CacheControl = er => null;
GetPath = resourcePath => DefaultPathFunction(resourcePath);
Array.ForEach(assemblies, a => Add(a));
}
public Func<EmbeddedResource, bool> UseResource { get; set; }
public Func<EmbeddedResource, bool> UseLocalIfAvailable { get; set; }
public Func<EmbeddedResource, EmbeddedResourceCacheControl> CacheControl { get; set; }
public Func<string, EmbeddedResourcePath> GetPath { get; set; }
public Dictionary<string, Dictionary<string, List<EmbeddedResource>>> Resources { get { return resources; } }
private EmbeddedResourcePath DefaultPathFunction(string resourcePath)
{
Match match = pathPattern.Match(resourcePath);
if (match.Success)
{
return new EmbeddedResourcePath()
{
Directory = match.Groups["directory"].Value,
Filename = match.Groups["filename"].Value
};
}
return null;
}
public void Add(Assembly assembly, string projectSourcePath = null)
{
var assemblyName = assembly.GetName().Name;
foreach (var resourcePath in assembly.GetManifestResourceNames().Where(r => r.StartsWith(assemblyName)))
{
EmbeddedResourcePath path = GetPath(resourcePath.Substring(assemblyName.Length + 1));
if (path != null)
{
Dictionary<string, List<EmbeddedResource>> directoryResources;
string directoryName = path.Directory.ToUpperInvariant();
string filename = path.Filename.ToUpperInvariant();
if (!resources.TryGetValue(directoryName, out directoryResources))
{
directoryResources = new Dictionary<string, List<EmbeddedResource>>();
resources.Add(directoryName, directoryResources);
}
if (!directoryResources.ContainsKey(filename))
{
directoryResources[filename] = new List<EmbeddedResource>();
}
directoryResources[filename].Insert(0, new EmbeddedResource(assembly, resourcePath, projectSourcePath));
}
}
}
public override bool FileExists(string virtualPath)
{
return (base.FileExists(virtualPath) || GetResourceFromVirtualPath(virtualPath) != null);
}
public override VirtualDirectory GetDirectory(string virtualDir)
{
string key = virtualDir.Replace('/', '.').TrimStart('~', '.').TrimEnd('.').ToUpperInvariant();
Dictionary<string, List<EmbeddedResource>> directoryResources;
if (resources.TryGetValue(key, out directoryResources))
{
return new EmbeddedResourceVirtualDirectory(virtualDir, directoryResources, CacheControl);
}
return base.GetDirectory(virtualDir);
}
public override bool DirectoryExists(string virtualDir)
{
string key = virtualDir.Replace('/', '.').TrimStart('~', '.').TrimEnd('.').ToUpperInvariant();
if (resources.ContainsKey(key))
{
return true;
}
return base.DirectoryExists(virtualDir);
}
public override VirtualFile GetFile(string virtualPath)
{
//if (base.FileExists(virtualPath)) return base.GetFile(virtualPath);
var resource = GetResourceFromVirtualPath(virtualPath);
if (resource != null)
return new EmbeddedResourceVirtualFile(virtualPath, resource, CacheControl(resource));
return base.GetFile(virtualPath);
}
public override string CombineVirtualPaths(string basePath, string relativePath)
{
var combineVirtualPaths = base.CombineVirtualPaths(basePath, relativePath);
return combineVirtualPaths;
}
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
{
var fileHash = base.GetFileHash(virtualPath, virtualPathDependencies);
return fileHash;
}
public override string GetCacheKey(string virtualPath)
{
var resource = GetResourceFromVirtualPath(virtualPath);
if (resource != null)
{
return (virtualPath + resource.AssemblyName + resource.AssemblyLastModified.Ticks).GetHashCode().ToString();
}
return base.GetCacheKey(virtualPath);
}
public bool IsInt(string c)
{
int outChar;
return int.TryParse(c, out outChar);
}
public EmbeddedResource GetResourceFromVirtualPath(string virtualPath)
{
var path = VirtualPathUtility.ToAppRelative(virtualPath).TrimStart('~', '/');
var index = path.LastIndexOf("/");
if (index != -1)
{
var folder = path.Substring(0, index); //embedded resources with "-"in their folder names are stored as "_".
var folderItems = folder.Split('/');
List<string> result = new List<string>();
foreach (var item in folderItems)
{
var resultFolder = item;
resultFolder = resultFolder.Replace("-", "_"); //replace - with underscore
var outputFolder = "";
var outs = "";
for (var i = 0; i < resultFolder.Length; i++)
{
if (i == 0 && IsInt(resultFolder[i].ToString())) //if the first character is a int, then prefix
outs += "_";
outs += resultFolder[i];
//if any character follows a dot with a int, prefix with an underscore
if (resultFolder[i] == '.')
{
//get the next one
if (IsInt(resultFolder.Substring(i + 1, 1)))
outs += "_";
}
}
resultFolder = outs;
result.Add(resultFolder);
}
folder = string.Join(".", result);
path = folder + path.Substring(index);
}
Match pathMatch = pathPattern.Match(path.Replace('/', '.').ToUpperInvariant());
if (pathMatch.Success)
{
string directory = pathMatch.Groups["directory"].Value;
string filename = pathMatch.Groups["filename"].Value;
if (resources.ContainsKey(directory))
{
var directoryResources = resources[directory];
if (directoryResources.ContainsKey(filename))
{
var resource = directoryResources[filename].FirstOrDefault(UseResource);
if (resource != null && !ShouldUsePrevious(virtualPath, resource))
{
return resource;
}
}
}
}
return null;
}
public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
{
var resource = GetResourceFromVirtualPath(virtualPath);
if (resource != null)
{
return resource.GetCacheDependency(utcStart);
}
var embeddedResourceDependencies = virtualPathDependencies.OfType<string>()
.Select(x => new { path = x, resource = GetResourceFromVirtualPath(x) })
.Where(x => x.resource != null)
.ToList();
if (embeddedResourceDependencies.Any())
{
virtualPathDependencies = virtualPathDependencies.OfType<string>()
.Except(embeddedResourceDependencies.Select(v => v.path))
.Concat(embeddedResourceDependencies.Select(v => $"/bin/{v.resource.AssemblyName}").Distinct());
}
if (DirectoryExists(virtualPath) || FileExists(virtualPath))
{
return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
return null;
}
private bool ShouldUsePrevious(string virtualPath, EmbeddedResource resource)
{
return base.FileExists(virtualPath) && UseLocalIfAvailable(resource);
}
//public override string GetCacheKey(string virtualPath)
//{
// var resource = GetResourceFromVirtualPath(virtualPath);
// if (resource != null) return virtualPath + "blah";
// return base.GetCacheKey(virtualPath);
//}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException("Only got this so that we can use object collection initializer syntax");
}
}
}