blob: eee63aa130c03b3ccc1ff1daf84038e1922fa638 (
plain)
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
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Mvc.Properties;
using System.Xml;
namespace System.Web.Mvc
{
// Processes files with this format:
//
// <typeCache lastModified=... mvcVersionId=...>
// <assembly name=...>
// <module versionId=...>
// <type>...</type>
// </module>
// </assembly>
// </typeCache>
//
// This is used to store caches of files between AppDomain resets, leading to improved cold boot time
// and more efficient use of memory.
internal sealed class TypeCacheSerializer
{
private static readonly Guid _mvcVersionId = typeof(TypeCacheSerializer).Module.ModuleVersionId;
// used for unit testing
private DateTime CurrentDate
{
get { return CurrentDateOverride ?? DateTime.Now; }
}
internal DateTime? CurrentDateOverride { get; set; }
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This is an instance method for consistency with the SerializeTypes() method.")]
public List<Type> DeserializeTypes(TextReader input)
{
XmlDocument doc = new XmlDocument();
doc.Load(input);
XmlElement rootElement = doc.DocumentElement;
Guid readMvcVersionId = new Guid(rootElement.Attributes["mvcVersionId"].Value);
if (readMvcVersionId != _mvcVersionId)
{
// The cache is outdated because the cache file was produced by a different version
// of MVC.
return null;
}
List<Type> deserializedTypes = new List<Type>();
foreach (XmlNode assemblyNode in rootElement.ChildNodes)
{
string assemblyName = assemblyNode.Attributes["name"].Value;
Assembly assembly = Assembly.Load(assemblyName);
foreach (XmlNode moduleNode in assemblyNode.ChildNodes)
{
Guid moduleVersionId = new Guid(moduleNode.Attributes["versionId"].Value);
foreach (XmlNode typeNode in moduleNode.ChildNodes)
{
string typeName = typeNode.InnerText;
Type type = assembly.GetType(typeName);
if (type == null || type.Module.ModuleVersionId != moduleVersionId)
{
// The cache is outdated because we couldn't find a previously recorded
// type or the type's containing module was modified.
return null;
}
else
{
deserializedTypes.Add(type);
}
}
}
}
return deserializedTypes;
}
public void SerializeTypes(IEnumerable<Type> types, TextWriter output)
{
var groupedByAssembly = from type in types
group type by type.Module
into groupedByModule
group groupedByModule by groupedByModule.Key.Assembly;
XmlDocument doc = new XmlDocument();
doc.AppendChild(doc.CreateComment(MvcResources.TypeCache_DoNotModify));
XmlElement typeCacheElement = doc.CreateElement("typeCache");
doc.AppendChild(typeCacheElement);
typeCacheElement.SetAttribute("lastModified", CurrentDate.ToString());
typeCacheElement.SetAttribute("mvcVersionId", _mvcVersionId.ToString());
foreach (var assemblyGroup in groupedByAssembly)
{
XmlElement assemblyElement = doc.CreateElement("assembly");
typeCacheElement.AppendChild(assemblyElement);
assemblyElement.SetAttribute("name", assemblyGroup.Key.FullName);
foreach (var moduleGroup in assemblyGroup)
{
XmlElement moduleElement = doc.CreateElement("module");
assemblyElement.AppendChild(moduleElement);
moduleElement.SetAttribute("versionId", moduleGroup.Key.ModuleVersionId.ToString());
foreach (Type type in moduleGroup)
{
XmlElement typeElement = doc.CreateElement("type");
moduleElement.AppendChild(typeElement);
typeElement.AppendChild(doc.CreateTextNode(type.FullName));
}
}
}
doc.Save(output);
}
}
}
|