-
Notifications
You must be signed in to change notification settings - Fork 593
/
Global.asax.cs
174 lines (149 loc) · 7.98 KB
/
Global.asax.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
using System;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using SampleWeb.Helpers;
using StackExchange.Profiling;
using StackExchange.Profiling.EntityFramework6;
using StackExchange.Profiling.Mvc;
using StackExchange.Profiling.Storage;
namespace SampleWeb
{
public class MvcApplication : HttpApplication
{
/// <summary>
/// Gets the connection string.
/// </summary>
public static string ConnectionString
{
get { return "Data Source = " + HttpContext.Current.Server.MapPath("~/App_Data/TestMiniProfiler.sqlite"); }
}
/// <summary>
/// register the routes.
/// </summary>
/// <param name="routes">The routes.</param>
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
/// <summary>
/// The application start event.
/// </summary>
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
InitProfilerSettings();
// this is only done for testing purposes so we don't check in the db to source control
// parameter table is only used in this project for sample queries
// yes, it is ugly, and do not do this unless you know for sure that the second Store in the MultiStorageProvider is of this type
((SqliteMiniProfilerStorage)((MultiStorageProvider)MiniProfiler.Settings.Storage).Stores[1]).RecreateDatabase("create table RouteHits(RouteName,HitCount,unique(RouteName))");
var entityFrameworkDataPath = HttpContext.Current.Server.MapPath("~/App_Data/SampleWeb.EFCodeFirst.EFContext.sdf");
if (File.Exists(entityFrameworkDataPath))
{
File.Delete(entityFrameworkDataPath);
}
// Setup profiler for Controllers via a Global ActionFilter
GlobalFilters.Filters.Add(new ProfilingActionFilter());
// initialize automatic view profiling
var copy = ViewEngines.Engines.ToList();
ViewEngines.Engines.Clear();
foreach (var item in copy)
{
ViewEngines.Engines.Add(new ProfilingViewEngine(item));
}
MiniProfilerEF6.Initialize();
}
/// <summary>
/// The application begin request event.
/// </summary>
protected void Application_BeginRequest()
{
MiniProfiler profiler = null;
// might want to decide here (or maybe inside the action) whether you want
// to profile this request - for example, using an "IsSystemAdmin" flag against
// the user, or similar; this could also all be done in action filters, but this
// is simple and practical; just return null for most users. For our test, we'll
// profile only for local requests (seems reasonable)
if (Request.IsLocal)
{
profiler = MiniProfiler.Start();
}
using (profiler.Step("Application_BeginRequest"))
{
// you can start profiling your code immediately
}
}
/// <summary>
/// The application end request.
/// </summary>
protected void Application_EndRequest()
{
MiniProfiler.Stop();
}
/// <summary>
/// Gets or sets a value indicating whether disable profiling results.
/// </summary>
public static bool DisableProfilingResults { get; set; }
/// <summary>
/// Customize aspects of the MiniProfiler.
/// </summary>
private void InitProfilerSettings()
{
// a powerful feature of the MiniProfiler is the ability to share links to results with other developers.
// by default, however, long-term result caching is done in HttpRuntime.Cache, which is very volatile.
//
// let's rig up serialization of our profiler results to a database, so they survive app restarts.
// Setting up a MultiStorage provider. This will store results in the HttpRuntimeCache (normally the default) and in SqlLite as well.
MultiStorageProvider multiStorage = new MultiStorageProvider(
new HttpRuntimeCacheStorage(new TimeSpan(1, 0, 0)),
new SqliteMiniProfilerStorage(ConnectionString));
MiniProfiler.Settings.Storage = multiStorage;
// different RDBMS have different ways of declaring sql parameters - SQLite can understand inline sql parameters just fine
// by default, sql parameters won't be displayed
MiniProfiler.Settings.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter();
// these settings are optional and all have defaults, any matching setting specified in .RenderIncludes() will
// override the application-wide defaults specified here, for example if you had both:
// MiniProfiler.Settings.PopupRenderPosition = RenderPosition.Right;
// and in the page:
// @MiniProfiler.RenderIncludes(position: RenderPosition.Left)
// then the position would be on the left that that page, and on the right (the app default) for anywhere that doesn't
// specified position in the .RenderIncludes() call.
MiniProfiler.Settings.PopupRenderPosition = RenderPosition.Right; // defaults to left
MiniProfiler.Settings.PopupMaxTracesToShow = 10; // defaults to 15
MiniProfiler.Settings.RouteBasePath = "~/profiler"; // e.g. /profiler/mini-profiler-includes.js
// optional settings to control the stack trace output in the details pane
// the exclude methods are not thread safe, so be sure to only call these once per appdomain
MiniProfiler.Settings.ExcludeType("SessionFactory"); // Ignore any class with the name of SessionFactory
MiniProfiler.Settings.ExcludeAssembly("NHibernate"); // Ignore any assembly named NHibernate
MiniProfiler.Settings.ExcludeMethod("Flush"); // Ignore any method with the name of Flush
// MiniProfiler.Settings.ShowControls = true;
MiniProfiler.Settings.StackMaxLength = 256; // default is 120 characters
// because profiler results can contain sensitive data (e.g. sql queries with parameter values displayed), we
// can define a function that will authorize clients to see the json or full page results.
// we use it on http://stackoverflow.com to check that the request cookies belong to a valid developer.
MiniProfiler.Settings.Results_Authorize = request =>
{
// you may implement this if you need to restrict visibility of profiling on a per request basis
// for example, for this specific path, we'll only allow profiling if a query parameter is set
if ("/Home/ResultsAuthorization".Equals(request.Url.LocalPath, StringComparison.OrdinalIgnoreCase))
{
return (request.Url.Query).ToLower().Contains("isauthorized");
}
// all other paths can check our global switch
return !DisableProfilingResults;
};
// the list of all sessions in the store is restricted by default, you must return true to alllow it
MiniProfiler.Settings.Results_List_Authorize = request =>
{
// you may implement this if you need to restrict visibility of profiling lists on a per request basis
return true; // all requests are kosher
};
}
}
}