Skip to content

Commit

Permalink
Big update:
Browse files Browse the repository at this point in the history
- Added embedded js and png files for easy deployment
- Refactored direct output into Responders architecture
- Added ShouldSetupInInit option to IGlimpsePlugin, and implemented setup tasks in the plugins
- Added isolation between plugins
  • Loading branch information
nikmd23 committed Mar 29, 2011
1 parent 0cc3930 commit d2a1e7d
Show file tree
Hide file tree
Showing 29 changed files with 506 additions and 180 deletions.
7 changes: 7 additions & 0 deletions source/Glimpse.Net/Configuration/GlimpseConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ public bool On
}
}

[ConfigurationProperty("pluginPath", DefaultValue = @"\", IsRequired = false)]
public string PluginPath
{
set { this["pluginPath"] = value; }
get { return this["pluginPath"].ToString(); }
}

[ConfigurationProperty("saveRequestCount", DefaultValue = "0", IsRequired = false)]
public int SaveRequestCount
{
Expand Down
4 changes: 3 additions & 1 deletion source/Glimpse.Net/DictionaryStringObjectPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Web;
using Glimpse.Protocol;

Expand All @@ -24,6 +25,7 @@ protected IDictionary<string, string> Process(IDictionary<string, object> dictio
}

public abstract object GetData(HttpApplication application);
public abstract void SetupInit();
public abstract string Name { get; }
}
}
8 changes: 8 additions & 0 deletions source/Glimpse.Net/Extentions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,20 @@ public static bool IsGlimpseRequest(this HttpApplication application)

var result = (path.StartsWith("/Glimpse/Config") ||
path.StartsWith("/Glimpse/History") ||
path.StartsWith("/Glimpse/glimpseClient.js") ||
path.StartsWith("/Glimpse/glimpseSprite.png") ||
path.StartsWith("/Glimpse/Clients"));

application.Context.Items["__validPath"] = result;
return result;
}

public static string GetClientName(this HttpApplication application)
{
var cookie = application.Request.Cookies[GlimpseConstants.CookieClientNameKey];
return cookie != null ? cookie.Value : "";
}

public static GlimpseMode GetGlimpseMode(this HttpApplication application)
{
var cookies = application.Request.Cookies;
Expand Down
16 changes: 15 additions & 1 deletion source/Glimpse.Net/Glimpse.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.configuration" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
Expand All @@ -51,6 +52,14 @@
<Compile Include="Extentions.cs" />
<Compile Include="GlimpseRequestMetadata.cs" />
<Compile Include="GlimpseTraceListener.cs" />
<Compile Include="Responder\Clients.cs" />
<Compile Include="Responder\Config.cs" />
<Compile Include="Responder\GlimpseResponderAttribute.cs" />
<Compile Include="Responder\History.cs" />
<Compile Include="Responder\Javascript.cs" />
<Compile Include="Responder\GlimpseResponders.cs" />
<Compile Include="Responder\Sprite.cs" />
<Compile Include="Responder\GlimpseResponder.cs" />
<Compile Include="Plugin\Asp\Environment.cs" />
<Compile Include="Plugin\Asp\Trace.cs" />
<Compile Include="Plugin\Configuration\Config.cs" />
Expand All @@ -76,7 +85,12 @@
<Name>Glimpse.Protocol</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="glimpseClient.js" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="glimpseSprite.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
199 changes: 39 additions & 160 deletions source/Glimpse.Net/Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using Glimpse.Net.Configuration;
using Glimpse.Net.Mvc;
using Glimpse.Net.Responder;
using Glimpse.Protocol;

namespace Glimpse.Net
Expand All @@ -19,33 +16,28 @@ public class Module : IHttpModule
{
private static GlimpseConfiguration Configuration { get; set; }
private static CompositionContainer Container { get; set; }
[ImportMany] private IList<IGlimpseConverter> JsConverters { get; set; }
private static JavaScriptSerializer JsSerializer { get; set; }
private static GlimpseResponders Responders { get; set; }
[ImportMany] private IList<Lazy<IGlimpsePlugin, IGlimpsePluginRequirements>> Plugins { get; set; }
[Import] private IGlimpseSanitizer Sanitizer { get; set; }

public Module()
{
Configuration = ConfigurationManager.GetSection("glimpse") as GlimpseConfiguration ?? new GlimpseConfiguration();
JsConverters = new List<IGlimpseConverter>();
JsSerializer = new JavaScriptSerializer();
Responders = new GlimpseResponders();
Plugins = new List<Lazy<IGlimpsePlugin, IGlimpsePluginRequirements>>();
}

public void Init(HttpApplication context)
{
if (Configuration.On == false) return; //Do nothing if Glimpse is off, events are not wired up

//TODO: MEF Plugin point to do something once as setup
GlobalFilters.Filters.Add(new GlimpseFilterAttribute(), int.MinValue);

var traceListeners = Trace.Listeners;
if (!traceListeners.OfType<GlimpseTraceListener>().Any())
traceListeners.Add(new GlimpseTraceListener()); //Add trace listener if it isn't already configured
//TODO: END MEF Plugin point to do something once as setup

ComposePlugins(); //Have MEF satisfy our needs

//Allow plugin's registered for Intialization to setup
foreach (var plugin in Plugins.Where(plugin => plugin.Metadata.ShouldSetupInInit))
{
plugin.Value.SetupInit();
}

context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
context.PostRequestHandlerExecute += PostRequestHandlerExecute;
Expand All @@ -57,9 +49,10 @@ private static void BeginRequest(object sender, EventArgs e)
HttpApplication httpApplication;
if (!sender.IsValidRequest(out httpApplication, Configuration, false, false)) return;

if (httpApplication.IsGlimpseRequest())
{
GlimpseResponse(httpApplication);
var responder = Responders.GetResponderFor(httpApplication);
if (responder != null)
{
responder.Respond(httpApplication, Configuration);
return;
}

Expand All @@ -82,47 +75,32 @@ private void EndRequest(object sender, EventArgs e)
ProcessData(httpApplication, false); //Run all plugins that DO NOT need access to Session
}

private void PreSendRequestHeaders(object sender, EventArgs e)
private static void PreSendRequestHeaders(object sender, EventArgs e)
{
HttpApplication httpApplication;
if (!sender.IsValidRequest(out httpApplication, Configuration, true)) return;

IDictionary<string, object> data;
if (!httpApplication.TryGetData(out data)) return;

var json = JsSerializer.Serialize(data); //serialize data to Json
json = Sanitizer.Sanitize(json);
var json = Responders.StandardResponse(httpApplication);

Persist(json, httpApplication);

//if ajax request, render glimpse data to headers
if (httpApplication.IsAjax())
{
httpApplication.Response.AddHeader(GlimpseConstants.HttpHeader, json);
}
else
{
var html = string.Format(@"<script type='text/javascript' id='glimpseData'>var glimpse = {0};</script>", json);
httpApplication.Response.Write(html);
}
}

private void ComposePlugins()
{
var aggregateCatalog = new AggregateCatalog();
//var typeCatlog = new TypeCatalog(typeof (Plugin.Asp.Environment));
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var directoryCatalog = new DirectoryCatalog(@"\");
var configuredDirectoryCatalog = new DirectoryCatalog(Configuration.PluginPath);

//aggregateCatalog.Catalogs.Add(typeCatlog);
aggregateCatalog.Catalogs.Add(assemblyCatalog);
aggregateCatalog.Catalogs.Add(directoryCatalog);
aggregateCatalog.Catalogs.Add(configuredDirectoryCatalog);

Container = new CompositionContainer(aggregateCatalog);
Container.ComposeParts(this);//TODO, is this needed? can I use typeof?
Container.ComposeParts(this, Responders);

//wireup converters into serializer
JsSerializer.RegisterConverters(JsConverters);
Responders.RegisterConverters();
}

public void Dispose()
Expand All @@ -141,141 +119,42 @@ private static void Persist(string json, HttpApplication ctx)
//clientName, longtime, url,
queue = store[GlimpseConstants.JsonQueue] as Queue<GlimpseRequestMetadata>;

if (queue == null) store[GlimpseConstants.JsonQueue] = queue = new Queue<GlimpseRequestMetadata>(Configuration.SaveRequestCount);
if (queue == null)
store[GlimpseConstants.JsonQueue] =
queue = new Queue<GlimpseRequestMetadata>(Configuration.SaveRequestCount);

if (queue.Count == Configuration.SaveRequestCount) queue.Dequeue();

var browser = ctx.Request.Browser;
queue.Enqueue(new GlimpseRequestMetadata{
Browser = string.Format("{0} {1}", browser.Browser, browser.Version),
ClientName = GetClientName(ctx),
Json = json,
RequestTime = DateTime.Now.ToLongTimeString(),
RequestId = Guid.NewGuid(),
IsAjax = new HttpRequestWrapper(ctx.Request).IsAjaxRequest().ToString()
});
}

private static string GetClientName(HttpApplication ctx)
{
var cookie = ctx.Request.Cookies[GlimpseConstants.CookieClientNameKey];
return cookie != null ? cookie.Value : "";
queue.Enqueue(new GlimpseRequestMetadata
{
Browser = string.Format("{0} {1}", browser.Browser, browser.Version),
ClientName = ctx.GetClientName(),
Json = json,
RequestTime = DateTime.Now.ToLongTimeString(),
RequestId = Guid.NewGuid(),
IsAjax = ctx.IsAjax().ToString()
});
}

private void ProcessData(HttpApplication httpApplication, bool sessionRequired)
{
IDictionary<string, object > data;
IDictionary<string, object> data;
if (!httpApplication.TryGetData(out data)) return;

foreach (var plugin in Plugins)
{
if (plugin.Metadata.SessionRequired == sessionRequired)
{
var p = plugin.Value;
var pluginData = p.GetData(httpApplication);
if (pluginData != null) data.Add(p.Name, pluginData);
}
}
//TODO: do I need to reassign to the store?
}

private static void GlimpseResponse(HttpApplication httpApplication)
{
//TODO: CLEAN ME!
var path = httpApplication.Request.Path;
var response = httpApplication.Response;

//render config page
if (path.StartsWith("/Glimpse/Config"))
foreach (var plugin in Plugins.Where(p=>p.Metadata.SessionRequired == sessionRequired))
{
var mode = httpApplication.GetGlimpseMode();

response.Write(string.Format("<html><head><title>Glimpse Config</title><script>function toggleCookie(){{var mode = document.getElementById('glimpseMode'); if (mode.innerHTML==='On'){{mode.innerHTML='Off';document.cookie='glimpseMode=Off; path=/;'}}else{{mode.innerHTML='On';document.cookie='glimpseMode=On; path=/;'}}}}</script><head><body><h1>Glimpse Config Settings:</h1><ul><li>On = {0}</li><li>Allowed IP's = <ol>", Configuration.On));
foreach (IpAddress ipAddress in Configuration.IpAddresses)
var p = plugin.Value;
try
{
response.Write(string.Format("<li>{0}</li>", ipAddress.Address));
}
response.Write("</ol></li><li>Allowed ContentType's = <ol>");
foreach (ContentType contentType in Configuration.ContentTypes)
{
response.Write(string.Format("<li>{0}</li>", contentType.Content));
}
response.Write(string.Format("</ol></li></ul><h1>Your Settings:</h1><ol><li>IP = {0}</li><li>GlimpseMode = <input type='checkbox' id='gChk' onclick='toggleCookie();'{2}/> <label for='gChk' id='glimpseMode'>{1}</lable></li></ol></body></html>", httpApplication.Request.ServerVariables["REMOTE_ADDR"], mode, mode==GlimpseMode.On ? " checked" : ""));

httpApplication.CompleteRequest();
return;
}

//render history json
if (path.StartsWith("/Glimpse/History"))
{
if (!httpApplication.IsValidRequest(Configuration, false, checkPath:false))
{
var data = JsSerializer.Serialize(new { Error = true, Message = "You are not configured to access history." });
JsonResponse(httpApplication, data);
return;
}

var queue = httpApplication.Application[GlimpseConstants.JsonQueue] as Queue<GlimpseRequestMetadata>;
if (queue != null)
{
var clientName = httpApplication.Request.QueryString[GlimpseConstants.ClientName];
string data;

if (string.IsNullOrEmpty(clientName))
data = JsSerializer.Serialize(queue);
else
{
var filteredQueue = from request in queue where request.ClientName.Equals(clientName) select request;
data = JsSerializer.Serialize(filteredQueue);
}

JsonResponse(httpApplication, data);
return;
}
else
{
var data = JsSerializer.Serialize(new { Error = true, Message = "No history avalible." });
JsonResponse(httpApplication, data);
return;
}
}

if (path.StartsWith("/Glimpse/Clients"))
{
if (!httpApplication.IsValidRequest(Configuration, false, checkPath:false))
{
var data = JsSerializer.Serialize(new { Error = true, Message = "You are not configured to access history." });
JsonResponse(httpApplication, data);
return;
}

var queue = httpApplication.Application[GlimpseConstants.JsonQueue] as Queue<GlimpseRequestMetadata>;
if (queue != null)
{
var filteredQueue = from request in queue
group request by request.ClientName
into clients select new {Client = clients.Key, RequestCount = clients.Count()};

var data = JsSerializer.Serialize(filteredQueue);
JsonResponse(httpApplication, data);
return;
var pluginData = p.GetData(httpApplication);
data.Add(p.Name, pluginData);
}
else
catch(Exception ex)
{
var data = JsSerializer.Serialize(new { Error = true, Message = "No history avalible." });
JsonResponse(httpApplication, data);
return;
data.Add(p.Name, ex.Message);
}
}
}

private static void JsonResponse(HttpApplication httpApplication, string data)
{
var response = httpApplication.Response;
response.Write(data);
response.AddHeader("Content-Type", "application/json");
httpApplication.CompleteRequest();
}
}
}
8 changes: 7 additions & 1 deletion source/Glimpse.Net/NameValueCollectionPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web;
using Glimpse.Protocol;
Expand All @@ -8,6 +9,11 @@ namespace Glimpse.Net
public abstract class NameValueCollectionPlugin : IGlimpsePlugin
{
public abstract object GetData(HttpApplication application);
public void SetupInit()
{
throw new NotImplementedException();
}

public abstract string Name { get; }

protected IDictionary<string, string> Process(NameValueCollection collection, HttpApplication application)
Expand Down
Loading

0 comments on commit d2a1e7d

Please sign in to comment.