Skip to content

Commit 6e2604d

Browse files
Added view locations module
1 parent fe4c57a commit 6e2604d

File tree

8 files changed

+255
-162
lines changed

8 files changed

+255
-162
lines changed

DeveloperTools/Controllers/ViewEngineLocationsController.cs

Lines changed: 0 additions & 52 deletions
This file was deleted.

DeveloperTools/EPiServer.DeveloperTools.Views/Views/AppEnvironment/Index.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<th align="left">Name</th>
1515
<th align="left">AssemblyVersion</th>
1616
<th align="left">FileVersion</th>
17-
<th>Location</th>
17+
<th>AreaName</th>
1818
</tr>
1919
</thead>
2020
<tbody>
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
@model EPiServer.DeveloperTools.Features.ViewLocations.ViewEngineLocationsModel
2+
3+
<div class="epi-contentArea">
4+
<h1 class="EP-prefix">View Engine AreaNames</h1>
5+
<p>Show a list of all view areaNames where Mvc would look for templates.</p>
6+
</div>
7+
<div class="epi-formArea">
8+
<h2 class="EP-prefix">Area Views AreaNames</h2>
9+
<table cellpadding="0" cellspacing="0" border="0" class="display" id="theViewLocations">
10+
<thead>
11+
<tr>
12+
<th align="left">View AreaName</th>
13+
<th align="left">Engine</th>
14+
</tr>
15+
</thead>
16+
<tbody>
17+
@foreach (var l in Model.AreaViewLocationFormats)
18+
{
19+
<tr>
20+
<td>@l.Location</td>
21+
<td>@l.EngineName</td>
22+
</tr>
23+
}
24+
</tbody>
25+
</table>
26+
<br/>
27+
<h2 class="EP-prefix">Area Page Views AreaNames</h2>
28+
<table cellpadding="0" cellspacing="0" border="0" class="display" id="theViewLocations">
29+
<thead>
30+
<tr>
31+
<th align="left">View AreaName</th>
32+
<th align="left">Engine</th>
33+
</tr>
34+
</thead>
35+
<tbody>
36+
@foreach (var l in Model.AreaPageViewLocationFormats)
37+
{
38+
<tr>
39+
<td>@l.Location</td>
40+
<td>@l.EngineName</td>
41+
</tr>
42+
}
43+
</tbody>
44+
</table>
45+
<br/>
46+
<h2 class="EP-prefix">View AreaNames</h2>
47+
<table cellpadding="0" cellspacing="0" border="0" class="display" id="theViewLocations">
48+
<thead>
49+
<tr>
50+
<th align="left">View AreaName</th>
51+
<th align="left">Engine</th>
52+
</tr>
53+
</thead>
54+
<tbody>
55+
@foreach (var l in Model.ViewLocations)
56+
{
57+
<tr>
58+
<td>@l.Location</td>
59+
<td>@l.EngineName</td>
60+
</tr>
61+
}
62+
</tbody>
63+
</table>
64+
<br />
65+
<h2 class="EP-prefix">View AreaNames</h2>
66+
<table cellpadding="0" cellspacing="0" border="0" class="display" id="theViewLocations">
67+
<thead>
68+
<tr>
69+
<th align="left">Page Views AreaName</th>
70+
<th align="left">Engine</th>
71+
</tr>
72+
</thead>
73+
<tbody>
74+
@foreach (var l in Model.PageViewLocationFormats)
75+
{
76+
<tr>
77+
<td>@l.Location</td>
78+
<td>@l.EngineName</td>
79+
</tr>
80+
}
81+
</tbody>
82+
</table>
83+
<br />
84+
<h2 class="EP-prefix">Cached View Locations</h2>
85+
<table cellpadding="0" cellspacing="0" border="0" class="display" id="theViewLocations">
86+
<thead>
87+
<tr>
88+
<th align="left">Area Name</th>
89+
<th align="left">Controller Name</th>
90+
<th align="left">Page Name</th>
91+
<th align="left">View Name</th>
92+
</tr>
93+
</thead>
94+
<tbody>
95+
@foreach (var l in Model.ExpandedLocations)
96+
{
97+
<tr>
98+
<td>@l.AreaName</td>
99+
<td>@l.ControllerName</td>
100+
<td>@l.PageName</td>
101+
<td>@l.ViewName</td>
102+
</tr>
103+
}
104+
</tbody>
105+
</table>
106+
</div>
107+
108+
@section AdditionalScripts {
109+
<script>
110+
$(document).ready(function () {
111+
$('#theViewAreaNames').dataTable(
112+
{
113+
"aaSorting": [[0, "desc"]],
114+
"bPaginate": false,
115+
"bLengthChange": false,
116+
"bFilter": true,
117+
"bSort": true,
118+
"bInfo": false,
119+
"bAutoWidth": true
120+
});
121+
122+
$('#thePartialViewAreaNames').dataTable(
123+
{
124+
"aaSorting": [[0, "desc"]],
125+
"bPaginate": false,
126+
"bLengthChange": false,
127+
"bFilter": true,
128+
"bSort": true,
129+
"bInfo": false,
130+
"bAutoWidth": true
131+
});
132+
});
133+
</script>
134+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Collections.Generic;
2+
3+
namespace EPiServer.DeveloperTools.Features.ViewLocations;
4+
5+
public class ViewEngineLocationsModel
6+
{
7+
public List<ViewEngineLocationItemModel> AreaViewLocationFormats { get; } = new();
8+
public List<ViewEngineLocationItemModel> AreaPageViewLocationFormats { get; } = new();
9+
public List<ViewEngineLocationItemModel> PageViewLocationFormats { get; } = new();
10+
public List<ViewEngineLocationItemModel> ViewLocations { get; } = new();
11+
public List<ExpandedLocationItemModel> ExpandedLocations { get; } = new();
12+
}
13+
14+
public class ViewEngineLocationItemModel
15+
{
16+
public ViewEngineLocationItemModel(string location, string engineName)
17+
{
18+
Location = location;
19+
EngineName = engineName;
20+
}
21+
22+
public string EngineName { get; }
23+
public string Location { get; }
24+
}
25+
26+
public class ExpandedLocationItemModel
27+
{
28+
public ExpandedLocationItemModel(string areaName, string controllerName, string pageName, string viewName)
29+
{
30+
AreaName = areaName;
31+
ControllerName = controllerName;
32+
PageName = pageName;
33+
ViewName = viewName;
34+
}
35+
36+
public string AreaName { get; }
37+
public string ControllerName { get; }
38+
public string PageName { get; }
39+
public string ViewName { get; }
40+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using EPiServer.DeveloperTools.Features.Common;
6+
using Microsoft.AspNetCore.DataProtection.KeyManagement;
7+
using Microsoft.AspNetCore.Mvc;
8+
using Microsoft.AspNetCore.Mvc.Razor;
9+
using Microsoft.AspNetCore.Mvc.ViewEngines;
10+
using Microsoft.Extensions.Caching.Memory;
11+
using Microsoft.Extensions.Options;
12+
using Newtonsoft.Json.Linq;
13+
14+
namespace EPiServer.DeveloperTools.Features.ViewLocations;
15+
16+
public class ViewLocationsController : DeveloperToolsController
17+
{
18+
private readonly IOptions<RazorViewEngineOptions> _razorOptions;
19+
private readonly ICompositeViewEngine _viewEngine;
20+
21+
public ViewLocationsController(IOptions<RazorViewEngineOptions> razorOptions, ICompositeViewEngine viewEngine)
22+
{
23+
_razorOptions = razorOptions;
24+
_viewEngine = viewEngine;
25+
}
26+
27+
public ActionResult Index()
28+
{
29+
var options = _razorOptions.Value;
30+
var model = new ViewEngineLocationsModel();
31+
32+
model.AreaViewLocationFormats.AddRange(options.AreaViewLocationFormats.Select(f => new ViewEngineLocationItemModel(f, "engineName")));
33+
model.AreaPageViewLocationFormats.AddRange(options.AreaPageViewLocationFormats.Select(f => new ViewEngineLocationItemModel(f, "engineName")));
34+
model.ViewLocations.AddRange(options.ViewLocationFormats.Select(f => new ViewEngineLocationItemModel(f, "engineName")));
35+
model.PageViewLocationFormats.AddRange(options.PageViewLocationFormats.Select(f => new ViewEngineLocationItemModel(f, "engineName")));
36+
37+
foreach (var engine in _viewEngine.ViewEngines)
38+
{
39+
var cacheFieldInfo = engine.GetType().GetProperty("ViewLookupCache", BindingFlags.NonPublic | BindingFlags.Instance);
40+
if (cacheFieldInfo != null)
41+
{
42+
if (cacheFieldInfo.GetValue(engine) is IMemoryCache cache)
43+
{
44+
var entriesFieldInfo = cache.GetType().GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance);
45+
if (entriesFieldInfo != null)
46+
{
47+
if (entriesFieldInfo.GetValue(cache) is IDictionary entries)
48+
{
49+
foreach (var entry in entries.Keys)
50+
{
51+
model.ExpandedLocations.Add(
52+
new ExpandedLocationItemModel(
53+
GetProperty(entry, "AreaName"),
54+
GetProperty(entry, "ControllerName"),
55+
GetProperty(entry, "PageName"),
56+
GetProperty(entry, "ViewName")));
57+
}
58+
}
59+
}
60+
}
61+
}
62+
}
63+
64+
return View(model);
65+
}
66+
67+
private static string GetProperty(object entry, string propertyName)
68+
{
69+
var viewNameFieldInfo = entry.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
70+
if (viewNameFieldInfo != null)
71+
{
72+
var propertyValue = viewNameFieldInfo.GetValue(entry) as string;
73+
return !string.IsNullOrEmpty(propertyValue) ? propertyValue : string.Empty;
74+
}
75+
76+
return string.Empty;
77+
}
78+
}

DeveloperTools/Infrastructure/MenuProvider.cs renamed to DeveloperTools/MenuProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using EPiServer.Shell.Modules;
66
using EPiServer.Shell.Navigation;
77

8-
namespace EPiServer.DeveloperTools.Infrastructure;
8+
namespace EPiServer.DeveloperTools;
99

1010
[MenuProvider]
1111
public class MenuProvider : IMenuProvider
@@ -35,7 +35,7 @@ public IEnumerable<MenuItem> GetMenuItems()
3535
//CreateUrlMenuItem("Memory Dump", "MemoryDump", 90),
3636
CreateUrlMenuItem("Remote Events", "RemoteEvent", 100),
3737
CreateUrlMenuItem("Routes", "Routes", 110),
38-
//CreateUrlMenuItem("View Locations", "ViewLocations", 120),
38+
CreateUrlMenuItem("View Locations", "ViewLocations", 120),
3939
//CreateUrlMenuItem("Module Dependencies", "ModuleDependencies", 130),
4040
//CreateUrlMenuItem("Local Object Cache", "LocalObjectCache", 140)
4141
};

DeveloperTools/Models/ViewEngineLocationsModel.cs

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)