Skip to content

Commit

Permalink
Merge pull request #36 from jaytem/LocalObjectCache
Browse files Browse the repository at this point in the history
Local object cache viewer
  • Loading branch information
bjuris authored Mar 14, 2019
2 parents e979ff0 + 3f3c41c commit 5ec4e4a
Show file tree
Hide file tree
Showing 8 changed files with 292 additions and 4 deletions.
125 changes: 125 additions & 0 deletions DeveloperTools/Controllers/LocalObjectCacheController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web.Mvc;
using System.Web.Routing;
using DeveloperTools.Core;
using DeveloperTools.Models;
using EPiServer.Core;
using EPiServer.Framework.Cache;

namespace DeveloperTools.Controllers
{
public class LocalObjectCacheController : DeveloperToolsController
{
private readonly ISynchronizedObjectInstanceCache _cache;

public LocalObjectCacheController(ISynchronizedObjectInstanceCache cache)
{
_cache = cache;
}

public ActionResult Index(string FilteredBy, bool os = false)
{
return View(PrepareViewModel(FilteredBy, os));
}

[HttpParamAction]
public ActionResult RemoveLocalCache(string[] cacheKeys, bool os)
{
if(cacheKeys != null)
{
foreach (string key in cacheKeys)
{
_cache.RemoveLocal(key);
}
}

return RedirectToAction("Index", new RouteValueDictionary(new { os }));
}

[HttpParamAction]
public ActionResult RemoveLocalRemoteCache(string[] cacheKeys, bool os)
{
if(cacheKeys != null)
{
foreach (string key in cacheKeys)
{
_cache.RemoveLocal(key);
_cache.RemoveRemote(key);
}
}

return RedirectToAction("Index", new RouteValueDictionary(new { os }));
}

[HttpParamAction]
public ActionResult ViewObjectSize()
{
return RedirectToAction("Index", new RouteValueDictionary(new { os = true }));
}

private LocalObjectCache PrepareViewModel(string FilteredBy, bool viewObjectSize)
{
var model = new LocalObjectCache();

var cachedEntries = HttpContext.Cache.Cast<DictionaryEntry>().Take(10_000);

switch (FilteredBy)
{
case "pages":
model.CachedItems = ConvertToListItem(cachedEntries.Where(item => item.Value is PageData), viewObjectSize);
break;
case "content":
model.CachedItems = ConvertToListItem(cachedEntries.Where(item => item.Value is IContent), viewObjectSize);
break;
default:
model.CachedItems = ConvertToListItem(cachedEntries, viewObjectSize);
break;
}

model.FilteredBy = FilteredBy;
model.Choices = new[]
{
new SelectListItem { Text = "All Cached Objects", Value = "all" },
new SelectListItem { Text = "Any Content", Value = "content" },
new SelectListItem { Text = "Pages Only", Value = "pages" }
};

model.ViewObjectSize = viewObjectSize;
return model;
}

private IEnumerable<LocalObjectCacheItem> ConvertToListItem(IEnumerable<DictionaryEntry> cachedEntries, bool viewObjectSize) =>
cachedEntries.Select(e => new LocalObjectCacheItem
{
Key = e.Key.ToString(),
Value = e.Value,
Size = viewObjectSize ? GetObjectSize(e.Value) : 0
}).ToList();

private static long GetObjectSize(object obj)
{
if(obj == null)
return 0;

try
{
using (Stream s = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(s, obj);

return s.Length;
}
}
catch (Exception)
{
return -1;
}
}
}
}
7 changes: 6 additions & 1 deletion DeveloperTools/Core/DeveloperMenuProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class DeveloperMenuProvider : IMenuProvider
const string ModuleDependenciesTitle = "Module Dependencies";
const string ModuleDependenciesPath = "global/DeveloperTools/ModuleDependencies";

const string LocalObjectCacheTitle = "Local Object Cache";
const string LocalObjectCachePath = "global/DeveloperTools/LocalObjectCache";

public IEnumerable<MenuItem> GetMenuItems()
{
// Create the top menu section
Expand All @@ -69,6 +72,7 @@ public IEnumerable<MenuItem> GetMenuItems()
var routes = CreateUrlMenuItem(RoutesTitle, RoutesPath, Paths.ToResource(ModuleName, "Routes"));
var viewLocations = CreateUrlMenuItem(ViewLocationsTitle, ViewLocationsPath, Paths.ToResource(ModuleName, "ViewEngineLocations"));
var moduleDependencies = CreateUrlMenuItem(ModuleDependenciesTitle, ModuleDependenciesPath, Paths.ToResource(ModuleName, "ModuleDependencies"));
var localobjectcache = CreateUrlMenuItem(LocalObjectCacheTitle, LocalObjectCachePath, Paths.ToResource(ModuleName, "LocalObjectCache"));

return new MenuItem[]
{
Expand All @@ -84,7 +88,8 @@ public IEnumerable<MenuItem> GetMenuItems()
remoteEventViewer,
routes,
viewLocations,
moduleDependencies
moduleDependencies,
localobjectcache
};
}

Expand Down
21 changes: 21 additions & 0 deletions DeveloperTools/Core/HttpParamActionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Reflection;
using System.Web.Mvc;

namespace DeveloperTools.Core
{
public class HttpParamActionAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if(actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;

if(!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;

var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
}
4 changes: 4 additions & 0 deletions DeveloperTools/DeveloperTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\ContentTypeAnalyzerController.cs" />
<Compile Include="Controllers\LocalObjectCacheController.cs" />
<Compile Include="Controllers\RoutesController.cs" />
<Compile Include="Controllers\RemoteEventController.cs" />
<Compile Include="Controllers\MemoryDumpController.cs" />
Expand All @@ -219,9 +220,11 @@
<Compile Include="Controllers\ViewEngineLocationsController.cs" />
<Compile Include="Core\DeveloperMenuProvider.cs" />
<Compile Include="Core\EnumerableExtensions.cs" />
<Compile Include="Core\HttpParamActionAttribute.cs" />
<Compile Include="Models\AssembliesModel.cs" />
<Compile Include="Models\ContentTypeAnalyzerModel.cs" />
<Compile Include="Models\ExtractedModuleInfo.cs" />
<Compile Include="Models\LocalObjectCache.cs" />
<Compile Include="Models\ModuleDependency.cs" />
<Compile Include="Models\ModuleDependencyViewModel.cs" />
<Compile Include="Models\ModuleInfo.cs" />
Expand All @@ -242,6 +245,7 @@
<None Include="modules\_protected\EPiServer.DeveloperTools\Views\ContentTypeAnalyzer\Index.aspx">
<SubType>ASPXCodeBehind</SubType>
</None>
<None Include="modules\_protected\EPiServer.DeveloperTools\Views\LocalObjectCache\Index.aspx" />
<None Include="modules\_protected\EPiServer.DeveloperTools\Views\Routes\Index.aspx" />
<None Include="modules\_protected\EPiServer.DeveloperTools\Views\RemoteEvent\Index.aspx">
<SubType>ASPXCodeBehind</SubType>
Expand Down
Binary file modified DeveloperTools/EPiServer.DeveloperTools.zip
Binary file not shown.
25 changes: 25 additions & 0 deletions DeveloperTools/Models/LocalObjectCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Web.Mvc;

namespace DeveloperTools.Models
{
public class LocalObjectCache
{
public IEnumerable<LocalObjectCacheItem> CachedItems { get; set; }

public string FilteredBy { get; set; }

public IEnumerable<SelectListItem> Choices { get; set; }

public bool ViewObjectSize { get; set; }
}

public class LocalObjectCacheItem
{
public string Key { get; set; }

public object Value { get; set; }

public long Size { get; set; }
}
}
6 changes: 3 additions & 3 deletions DeveloperTools/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("15a30f61-0a54-4a91-b98f-5b30eb22b6f5")]
[assembly: AssemblyVersion("3.3.3.0")]
[assembly: AssemblyFileVersion("3.3.3.0")]
[assembly: AssemblyInformationalVersion("3.3.3")]
[assembly: AssemblyVersion("3.4.0.0")]
[assembly: AssemblyFileVersion("3.4.0.0")]
[assembly: AssemblyInformationalVersion("3.4.0")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<DeveloperTools.Models.LocalObjectCache>" MasterPageFile="../Shared/DeveloperTools.Master" %>

<asp:Content ID="Styles" runat="server" ContentPlaceHolderID="HeaderStyles">
<style type="text/css">
.table-column-width {
width: 30%;
}
.stripe tbody tr:nth-child(even) {
background-color: #f0f2f2;
}
</style>
</asp:Content>

<asp:Content ID="Content" runat="server" ContentPlaceHolderID="MainRegion">
<link rel="stylesheet" type="text/css" href="//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.0/css/jquery.dataTables.css" />
<script type="text/javascript" language="javascript" src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.0/jquery.dataTables.min.js" type="text/javascript"></script>

<div class="epi-contentContainer epi-padding">
<div class="epi-contentArea">
<h1>Local Object Cache</h1>
<p class="EP-systemInfo">This tool shows all of the current items in the local object cache, and allows the deletion of one or more cached items.</p>
</div>

<div class="epi-contentArea epi-formArea">
<%using (Html.BeginForm("Index", "LocalObjectCache", FormMethod.Post))
{ %>
<%= Html.AntiForgeryToken() %>

<table class="table">
<tr>
<td>Filter By</td>
<td><%= Html.DropDownListFor(m => m.FilteredBy, Model.Choices) %></td>
<td>
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Refresh" type="submit" name="filter" id="filter" value="Filter" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
</td>
</tr>
</table>
<% } %>

<% using (Html.BeginForm("Action", "LocalObjectCache", FormMethod.Post))
{ %>
<div class="epi-contentArea">
<p class="EP-systemInfo">Total count of cached items: <%= Model.CachedItems.Count() %></p>
</div>
<div class="epi-buttonDefault">
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Delete" type="submit" name="RemoveLocalCache" id="RemoveLocalCache" value="Remove Local Cache Items" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Delete" type="submit" name="removeLocalRemoteCache" id="removeLocalRemoteCache" value="Remove Local and Remote Cache Items" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-ViewMode" type="submit" name="ViewObjectSize" id="ViewObjectSize" value="View Object Size" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
</div>

<table class="table table-condensed table-bordered table-condensed stripe">
<thead>
<tr>
<th><input type="checkbox" id="clearAll" name="clearAll" onClick="toggle(this)" value="true" /></th>
<th class="table-column-width">Key</th>
<th class="table-column-width">Type</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<% foreach (var item in Model.CachedItems)
{ %>
<tr>
<td class="center"><input type="checkbox" id="<%= item.Key %>" name="cacheKeys" value="<%= item.Key %>" /></td>
<td><%= item.Key %></td>
<td><%= item.Value.GetType() %></td>
<td><%= item.Size %></td>
</tr>
<% } %>
</tbody>
</table>

<div class="epi-buttonDefault">
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Delete" type="submit" name="RemoveLocalCache" id="RemoveLocalCacheBottom" value="Remove Local Cache Items" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-Delete" type="submit" name="removeLocalRemoteCache" id="removeLocalRemoteCacheBottom" value="Remove Local and Remote Cache Items" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
<span class="epi-cmsButton">
<input class="epi-cmsButton-text epi-cmsButton-tools epi-cmsButton-ViewMode" type="submit" name="ViewObjectSize" id="ViewObjectSize" value="View Object Size" onmouseover="EPi.ToolButton.MouseDownHandler(this)" onmouseout="EPi.ToolButton.ResetMouseDownHandler(this)" />
</span>
</div>

<input type="hidden" id="os" name="os" value="<%= Model.ViewObjectSize %>"/>
<% } %>
</div>
</div>

<script language="JavaScript">
function toggle(source) {
checkboxes = document.getElementsByName('cacheKeys');
for (var i = 0, n = checkboxes.length; i < n; i++) {
checkboxes[i].checked = source.checked;
}
}
</script>
</asp:Content>

0 comments on commit 5ec4e4a

Please sign in to comment.