diff --git a/MvcMiniProfiler.EntityFramework/MvcMiniProfiler.EntityFramework.csproj b/MvcMiniProfiler.EntityFramework/MvcMiniProfiler.EntityFramework.csproj index cc1e981..b954236 100644 --- a/MvcMiniProfiler.EntityFramework/MvcMiniProfiler.EntityFramework.csproj +++ b/MvcMiniProfiler.EntityFramework/MvcMiniProfiler.EntityFramework.csproj @@ -1,4 +1,4 @@ - + Debug @@ -10,10 +10,10 @@ Properties MvcMiniProfiler.EntityFramework MvcMiniProfiler.EntityFramework - v4.0 512 + v4.0 true full false @@ -23,6 +23,7 @@ 4 + v4.0 pdbonly true bin\Release\ diff --git a/MvcMiniProfiler.Tests/Data/IDbProfilerTest.cs b/MvcMiniProfiler.Tests/Data/IDbProfilerTest.cs index 9624cdd..7f0b783 100644 --- a/MvcMiniProfiler.Tests/Data/IDbProfilerTest.cs +++ b/MvcMiniProfiler.Tests/Data/IDbProfilerTest.cs @@ -140,6 +140,7 @@ public void Errors() } } +#if !CSHARP30 [Test] public void DataAdapter() { @@ -165,6 +166,6 @@ public void DataAdapter() Assert.That(mp.ExecutedScalars == 0); Assert.That(mp.ExecutedNonQueries == 0); } - +#endif } } diff --git a/MvcMiniProfiler.Tests/MvcMiniProfiler.Tests.csproj b/MvcMiniProfiler.Tests/MvcMiniProfiler.Tests.csproj index 05fcd8b..4b91f2e 100644 --- a/MvcMiniProfiler.Tests/MvcMiniProfiler.Tests.csproj +++ b/MvcMiniProfiler.Tests/MvcMiniProfiler.Tests.csproj @@ -1,4 +1,4 @@ - + Debug @@ -11,11 +11,11 @@ Properties MvcMiniProfiler.Tests MvcMiniProfiler.Tests - v4.0 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + v4.0 true full false @@ -25,6 +25,7 @@ 4 + v4.0 pdbonly true bin\Release\ @@ -38,6 +39,41 @@ Properties\MiniProfiler.Tests.snk + + v3.5 + true + bin\NET35-Debug\ + DEBUG;TRACE;CSHARP30 + full + AnyCPU + bin\Debug\MvcMiniProfiler.Tests.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + + + v3.5 + bin\NET35-Release\ + TRACE;CSHARP30 + true + pdbonly + AnyCPU + bin\Release\MvcMiniProfiler.Tests.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + diff --git a/MvcMiniProfiler.Tests/Storage/SqlServerStorageTest.cs b/MvcMiniProfiler.Tests/Storage/SqlServerStorageTest.cs index 2682c5f..4fb28c0 100644 --- a/MvcMiniProfiler.Tests/Storage/SqlServerStorageTest.cs +++ b/MvcMiniProfiler.Tests/Storage/SqlServerStorageTest.cs @@ -9,6 +9,7 @@ using System.Data.SqlServerCe; using MvcMiniProfiler.Helpers.Dapper; using MvcMiniProfiler.Data; +using MvcMiniProfiler.Helpers; namespace MvcMiniProfiler.Tests.Storage { @@ -18,7 +19,7 @@ public class SqlServerStorageTest : BaseTest [TestFixtureSetUp] public void TestFixtureSetUp() { - var sqlToExecute = SqlServerStorage.TableCreationScript.Replace("nvarchar(max)", "ntext").Split(';').Where(s => !string.IsNullOrWhiteSpace(s)); + var sqlToExecute = SqlServerStorage.TableCreationScript.Replace("nvarchar(max)", "ntext").Split(';').Where(s => !ExtensionMethods.IsNullOrWhiteSpace(s)); var connStr = CreateSqlCeDatabase(sqlToExecute: sqlToExecute); MiniProfiler.Settings.Storage = new SqlCeStorage(connStr); diff --git a/MvcMiniProfiler.Wcf/MvcMiniProfiler.Wcf.csproj b/MvcMiniProfiler.Wcf/MvcMiniProfiler.Wcf.csproj index 35db2a4..5f88f26 100644 --- a/MvcMiniProfiler.Wcf/MvcMiniProfiler.Wcf.csproj +++ b/MvcMiniProfiler.Wcf/MvcMiniProfiler.Wcf.csproj @@ -36,6 +36,37 @@ miniprofiler.snk + + true + bin\NET35-Debug\ + DEBUG;TRACE + full + AnyCPU + bin\Debug\MvcMiniProfiler.Wcf.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + false + + + bin\NET35-Release\ + TRACE + true + pdbonly + AnyCPU + bin\Release\MvcMiniProfiler.Wcf.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + false + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + diff --git a/MvcMiniProfiler.sln b/MvcMiniProfiler.sln index f4faa98..70755cb 100644 --- a/MvcMiniProfiler.sln +++ b/MvcMiniProfiler.sln @@ -38,35 +38,57 @@ Global EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + NET35-Debug|Any CPU = NET35-Debug|Any CPU + NET35-Release|Any CPU = NET35-Release|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {386222BD-6B6E-480F-A342-8DE1AB516E2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {386222BD-6B6E-480F-A342-8DE1AB516E2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {386222BD-6B6E-480F-A342-8DE1AB516E2C}.NET35-Debug|Any CPU.ActiveCfg = NET35-Debug|Any CPU + {386222BD-6B6E-480F-A342-8DE1AB516E2C}.NET35-Debug|Any CPU.Build.0 = NET35-Debug|Any CPU + {386222BD-6B6E-480F-A342-8DE1AB516E2C}.NET35-Release|Any CPU.ActiveCfg = NET35-Release|Any CPU + {386222BD-6B6E-480F-A342-8DE1AB516E2C}.NET35-Release|Any CPU.Build.0 = NET35-Release|Any CPU {386222BD-6B6E-480F-A342-8DE1AB516E2C}.Release|Any CPU.ActiveCfg = Release|Any CPU {386222BD-6B6E-480F-A342-8DE1AB516E2C}.Release|Any CPU.Build.0 = Release|Any CPU {50A89C9B-7335-4626-B552-272CE56DC72E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {50A89C9B-7335-4626-B552-272CE56DC72E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50A89C9B-7335-4626-B552-272CE56DC72E}.NET35-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50A89C9B-7335-4626-B552-272CE56DC72E}.NET35-Release|Any CPU.ActiveCfg = Release|Any CPU {50A89C9B-7335-4626-B552-272CE56DC72E}.Release|Any CPU.ActiveCfg = Release|Any CPU {50A89C9B-7335-4626-B552-272CE56DC72E}.Release|Any CPU.Build.0 = Release|Any CPU {5D54F88D-4C79-4EAB-B7B7-C8DE78F5DDA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5D54F88D-4C79-4EAB-B7B7-C8DE78F5DDA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D54F88D-4C79-4EAB-B7B7-C8DE78F5DDA7}.NET35-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D54F88D-4C79-4EAB-B7B7-C8DE78F5DDA7}.NET35-Release|Any CPU.ActiveCfg = Release|Any CPU {5D54F88D-4C79-4EAB-B7B7-C8DE78F5DDA7}.Release|Any CPU.ActiveCfg = Release|Any CPU {5D54F88D-4C79-4EAB-B7B7-C8DE78F5DDA7}.Release|Any CPU.Build.0 = Release|Any CPU {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.NET35-Debug|Any CPU.ActiveCfg = NET35-Debug|Any CPU + {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.NET35-Debug|Any CPU.Build.0 = NET35-Debug|Any CPU + {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.NET35-Release|Any CPU.ActiveCfg = NET35-Release|Any CPU + {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.NET35-Release|Any CPU.Build.0 = NET35-Release|Any CPU {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4CA8022-257B-4893-97D8-76E05EBBAAB0}.Release|Any CPU.Build.0 = Release|Any CPU {7F18DC76-61A2-4E7D-BA5A-FE159E789362}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7F18DC76-61A2-4E7D-BA5A-FE159E789362}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F18DC76-61A2-4E7D-BA5A-FE159E789362}.NET35-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F18DC76-61A2-4E7D-BA5A-FE159E789362}.NET35-Release|Any CPU.ActiveCfg = Release|Any CPU {7F18DC76-61A2-4E7D-BA5A-FE159E789362}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F18DC76-61A2-4E7D-BA5A-FE159E789362}.Release|Any CPU.Build.0 = Release|Any CPU {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.NET35-Debug|Any CPU.ActiveCfg = NET35-Debug|Any CPU + {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.NET35-Debug|Any CPU.Build.0 = NET35-Debug|Any CPU + {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.NET35-Release|Any CPU.ActiveCfg = NET35-Release|Any CPU + {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.NET35-Release|Any CPU.Build.0 = NET35-Release|Any CPU {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C471B0E5-0AE4-48E0-A938-02AEDA030C5E}.Release|Any CPU.Build.0 = Release|Any CPU {2DD1E352-3FFE-49F8-ADAB-65F3FECE75E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2DD1E352-3FFE-49F8-ADAB-65F3FECE75E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DD1E352-3FFE-49F8-ADAB-65F3FECE75E6}.NET35-Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DD1E352-3FFE-49F8-ADAB-65F3FECE75E6}.NET35-Release|Any CPU.ActiveCfg = Release|Any CPU {2DD1E352-3FFE-49F8-ADAB-65F3FECE75E6}.Release|Any CPU.ActiveCfg = Release|Any CPU {2DD1E352-3FFE-49F8-ADAB-65F3FECE75E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection diff --git a/MvcMiniProfiler/DotNet35Support.cs b/MvcMiniProfiler/DotNet35Support.cs new file mode 100644 index 0000000..3941778 --- /dev/null +++ b/MvcMiniProfiler/DotNet35Support.cs @@ -0,0 +1,271 @@ +using System; + +using System.Collections; + +using System.Collections.Generic; + +using System.Threading; +using System.Linq; + +#if !CSHARP30 +using System.Collections.Concurrent; +#endif + +namespace MvcMiniProfiler +{ + internal interface IConcurrentDictionary : IDictionary + { + bool TryRemove(TKey key, out TValue value); + } + +#if CSHARP30 + internal static class EnumHelper + { + public static bool TryParse(string value, out T e) + { + e = default(T); + + try + { + e = (T)Enum.Parse(typeof(T), value); + return true; + } + catch (Exception) + { + return false; + } + } + } + + internal static class GuidHelper + { + public static bool TryParse(string value, out Guid id) + { + id = Guid.Empty; + + try + { + id = new Guid(value); + return true; + } + catch (Exception) + { + return false; + } + } + } + + internal static class Tuple + { + public static Tuple Create(T1 item1, T2 item2) + { + return new Tuple(item1, item2); + } + } + + internal class Tuple + { + public Tuple(T1 item1, T2 item2) + { + Item1 = item1; + Item2 = item2; + } + + public T1 Item1 { get; private set; } + public T2 Item2 { get; private set; } + + public override int GetHashCode() + { + return Item1.GetHashCode() ^ Item2.GetHashCode(); + } + + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + + var other = obj as Tuple; + if (other == null) + { + return false; + } + + var comparer1 = EqualityComparer.Default; + var comparer2 = EqualityComparer.Default; + return comparer1.Equals(Item1, other.Item1)&& comparer2.Equals(Item2, other.Item2); + } + + public override string ToString() + { + throw new NotImplementedException(); + } + } + + /// + /// This is a dictionary that only implements the methods required by the . Concurrency is very simply implemented via a . + /// + /// The type of the key. + /// The type of the value. + internal class MiniConcurrentDictionary : IConcurrentDictionary + { + private Dictionary _dict = new Dictionary(); + private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + + public TValue this[TKey key] + { + get + { + _lock.EnterReadLock(); + try + { + return _dict[key]; + } + finally + { + _lock.ExitReadLock(); + } + } + set + { + _lock.EnterWriteLock(); + try + { + _dict[key] = value; + } + finally + { + _lock.ExitWriteLock(); + } + } + } + + public ICollection Values + { + get + { + _lock.EnterReadLock(); + try + { + return _dict.Values.ToList(); + } + finally + { + _lock.ExitReadLock(); + } + } + } + + public bool TryGetValue(TKey key, out TValue value) + { + var result = false; + _lock.EnterReadLock(); + try + { + result = _dict.TryGetValue(key, out value); + } + finally + { + _lock.ExitReadLock(); + } + + return result; + } + + public bool TryRemove(TKey key, out TValue value) + { + var result = false; + _lock.EnterWriteLock(); + try + { + if (_dict.TryGetValue(key, out value)) + { + result = _dict.Remove(key); + } + } + finally + { + _lock.ExitWriteLock(); + } + + return result; + } + + #region Not Implemented + + public IEnumerator> GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(KeyValuePair item) + { + throw new NotImplementedException(); + } + + public void Clear() + { + throw new NotImplementedException(); + } + + public bool Contains(KeyValuePair item) + { + throw new NotImplementedException(); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + public bool Remove(KeyValuePair item) + { + throw new NotImplementedException(); + } + + public int Count + { + get { throw new NotImplementedException(); } + } + public bool IsReadOnly + { + get { throw new NotImplementedException(); } + } + public bool ContainsKey(TKey key) + { + throw new NotImplementedException(); + } + + public void Add(TKey key, TValue value) + { + throw new NotImplementedException(); + } + + public bool Remove(TKey key) + { + throw new NotImplementedException(); + } + + public ICollection Keys + { + get { throw new NotImplementedException(); } + } + + #endregion + } +#else + internal class MiniConcurrentDictionary : ConcurrentDictionary, IConcurrentDictionary + { + bool IConcurrentDictionary.TryRemove(TKey key, out TValue value) + { + return base.TryRemove(key, out value); + } + } +#endif +} \ No newline at end of file diff --git a/MvcMiniProfiler/Helpers/ExtensionMethods.cs b/MvcMiniProfiler/Helpers/ExtensionMethods.cs index 0f60078..a27e047 100644 --- a/MvcMiniProfiler/Helpers/ExtensionMethods.cs +++ b/MvcMiniProfiler/Helpers/ExtensionMethods.cs @@ -17,7 +17,25 @@ internal static class ExtensionMethods /// internal static bool IsNullOrWhiteSpace(this string s) { +#if CSHARP30 + var result = false; + if (String.IsNullOrEmpty(s)) + { + result = true; + } + else if (s.Trim() == String.Empty) + { + result = true; + } + else + { + result = false; + } + + return result; +#else return string.IsNullOrWhiteSpace(s); +#endif } /// @@ -25,7 +43,7 @@ internal static bool IsNullOrWhiteSpace(this string s) /// internal static bool HasValue(this string s) { - return !string.IsNullOrWhiteSpace(s); + return !ExtensionMethods.IsNullOrWhiteSpace(s); } internal static string Truncate(this string s, int maxLength) diff --git a/MvcMiniProfiler/Helpers/SqlMapper.cs b/MvcMiniProfiler/Helpers/SqlMapper.cs index aebe4fa..23b3ba5 100644 --- a/MvcMiniProfiler/Helpers/SqlMapper.cs +++ b/MvcMiniProfiler/Helpers/SqlMapper.cs @@ -433,7 +433,16 @@ public bool Equals(Identity other) } #if CSHARP30 - /// + /// + /// Execute SQL + /// + /// Number of rows affected + public static int Execute(this IDbConnection cnn, string sql) + { + return Execute(cnn, sql, null, null, null, null); + } + + /// /// Execute parameterized SQL /// /// Number of rows affected @@ -441,7 +450,29 @@ public static int Execute(this IDbConnection cnn, string sql, object param) { return Execute(cnn, sql, param, null, null, null); } - /// + + /// + /// Executes a query, returning the data typed as per T + /// + public static IEnumerable Query(this IDbConnection cnn, string sql) + { + return Query(cnn, sql, null, null, true, null, null); + } + + /// + /// Executes a query, returning the data typed as per T + /// + public static IEnumerable Query(this IDbConnection cnn, string sql) + { + return Query(cnn, sql, null, null, true, null, null); + } + + public static IEnumerable Query(this IDbConnection cnn, string sql, object param) + { + return Query(cnn, sql, param, null, true, null, null); + } + + /// /// Executes a query, returning the data typed as per T /// /// the dynamic param may seem a bit odd, but this works around a major usability issue in vs, if it is Object vs completion gets annoying. Eg type new get new object @@ -452,7 +483,6 @@ public static IEnumerable Query(this IDbConnection cnn, string sql, object { return Query(cnn, sql, param, null, true, null, null); } - #endif /// /// Execute parameterized SQL diff --git a/MvcMiniProfiler/Helpers/StackTraceSnippet.cs b/MvcMiniProfiler/Helpers/StackTraceSnippet.cs index 1ca8fa7..d092068 100644 --- a/MvcMiniProfiler/Helpers/StackTraceSnippet.cs +++ b/MvcMiniProfiler/Helpers/StackTraceSnippet.cs @@ -43,7 +43,7 @@ public static string Get() } } - var result = string.Join(" ", methods); + var result = string.Join(" ", methods.ToArray()); if (result.Length > MiniProfiler.Settings.StackMaxLength) { diff --git a/MvcMiniProfiler/MiniProfiler.cs b/MvcMiniProfiler/MiniProfiler.cs index 1287094..d4dae7f 100644 --- a/MvcMiniProfiler/MiniProfiler.cs +++ b/MvcMiniProfiler/MiniProfiler.cs @@ -320,7 +320,25 @@ public static IDisposable StepStatic(string name, ProfileLevel level = ProfileLe return MiniProfilerExtensions.Step(Current, name, level); } - /// +#if CSHARP30 + /// + /// Returns the css and javascript includes needed to display the MiniProfiler results UI. + /// + /// Which side of the page the profiler popup button should be displayed on (defaults to left) + /// Whether to show trivial timings by default (defaults to false) + /// Whether to show time the time with children column by default (defaults to false) + /// The maximum number of trace popups to show before removing the oldest (defaults to 15) + /// xhtml rendering mode, ensure script tag is closed ... etc + /// when true, shows buttons to minimize and clear MiniProfiler results + /// Script and link elements normally; an empty string when there is no active profiling session. + public static string RenderIncludes(RenderPosition? position = null, bool? showTrivial = null, bool? showTimeWithChildren = null, int? maxTracesToShow = null, bool xhtml = false, bool? showControls = null) + { + var result = UI.MiniProfilerHandler.RenderIncludes(Current, position, showTrivial, showTimeWithChildren, maxTracesToShow, xhtml, showControls); + + return result.ToString(); + } +#else + /// /// Returns the css and javascript includes needed to display the MiniProfiler results UI. /// /// Which side of the page the profiler popup button should be displayed on (defaults to left) @@ -334,8 +352,9 @@ public static IHtmlString RenderIncludes(RenderPosition? position = null, bool? { return UI.MiniProfilerHandler.RenderIncludes(Current, position, showTrivial, showTimeWithChildren, maxTracesToShow, xhtml, showControls); } +#endif - /// + /// /// Gets the currently running MiniProfiler for the current HttpContext; null if no MiniProfiler was ed. /// public static MiniProfiler Current @@ -372,7 +391,7 @@ public static string ToJson(MiniProfiler profiler) /// public static MiniProfiler FromJson(string json) { - if (string.IsNullOrWhiteSpace(json)) return null; + if (ExtensionMethods.IsNullOrWhiteSpace(json)) return null; var result = new JavaScriptSerializer().Deserialize(json); return result; @@ -486,10 +505,38 @@ public static void AddProfilerResults(this MiniProfiler profiler, MiniProfiler e profiler.Head.AddChild(externalProfiler.Root); } +#if CSHARP30 /// /// Returns an html-encoded string with a text-representation of ; returns "" when profiler is null. /// /// The current profiling session or null. + public static string Render(this MiniProfiler profiler) + { + if (profiler == null) return string.Empty; + + var text = new StringBuilder() + .Append(HttpUtility.HtmlEncode(Environment.MachineName)).Append(" at ").Append(DateTime.UtcNow).AppendLine(); + + Stack timings = new Stack(); + timings.Push(profiler.Root); + while (timings.Count > 0) + { + var timing = timings.Pop(); + string name = HttpUtility.HtmlEncode(timing.Name); + text.AppendFormat("{2} {0} = {1:###,##0.##}ms", name, timing.DurationMilliseconds, new string('>', timing.Depth)).AppendLine(); + if (timing.HasChildren) + { + IList children = timing.Children; + for (int i = children.Count - 1; i >= 0; i--) timings.Push(children[i]); + } + } + return text.ToString(); + } +#else + /// + /// Returns an html-encoded string with a text-representation of ; returns "" when profiler is null. + /// + /// The current profiling session or null. public static IHtmlString Render(this MiniProfiler profiler) { if (profiler == null) return new HtmlString(""); @@ -512,6 +559,6 @@ public static IHtmlString Render(this MiniProfiler profiler) } return new HtmlString(text.ToString()); } - - } +#endif + } } \ No newline at end of file diff --git a/MvcMiniProfiler/MvcMiniProfiler.csproj b/MvcMiniProfiler/MvcMiniProfiler.csproj index eac5ab0..9564b5d 100644 --- a/MvcMiniProfiler/MvcMiniProfiler.csproj +++ b/MvcMiniProfiler/MvcMiniProfiler.csproj @@ -10,11 +10,11 @@ Properties MvcMiniProfiler MvcMiniProfiler - v4.0 512 - + v4.0 + true full false @@ -25,6 +25,8 @@ bin\Debug\MvcMiniProfiler.XML + v4.0 + pdbonly true bin\Release\ @@ -42,8 +44,44 @@ miniprofiler.snk + + v3.5 + + true + bin\NET35-Debug\ + TRACE;DEBUG;CSHARP30 + bin\Debug\MvcMiniProfiler.XML + full + AnyCPU + bin\Debug\MvcMiniProfiler.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + + + v3.5 + + bin\NET35-Release\ + TRACE;CSHARP30 + bin\Release\MvcMiniProfiler.xml + true + pdbonly + AnyCPU + bin\Release\MvcMiniProfiler.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + - @@ -52,11 +90,22 @@ - - ..\..\StackOverflow\StackOverflow\lib\System.Web.Mvc.dll - + + + + + + + + + + + + + + IProfilerProvider.cs @@ -64,6 +113,7 @@ + Code diff --git a/MvcMiniProfiler/SqlFormatters/SqlServerFormatter.cs b/MvcMiniProfiler/SqlFormatters/SqlServerFormatter.cs index f5c6f49..36f2a9e 100644 --- a/MvcMiniProfiler/SqlFormatters/SqlServerFormatter.cs +++ b/MvcMiniProfiler/SqlFormatters/SqlServerFormatter.cs @@ -72,7 +72,7 @@ public string FormatSql(SqlTiming timing) DbType parsed; string resolvedType = null; - if (!Enum.TryParse(p.DbType, out parsed)) + if (!EnumHelper.TryParse(p.DbType, out parsed)) { resolvedType = p.DbType; } diff --git a/MvcMiniProfiler/SqlProfiler.cs b/MvcMiniProfiler/SqlProfiler.cs index b0c3429..38b1107 100644 --- a/MvcMiniProfiler/SqlProfiler.cs +++ b/MvcMiniProfiler/SqlProfiler.cs @@ -3,21 +3,29 @@ using System.Data.Common; using MvcMiniProfiler.Data; using System.Linq; + +#if CSHARP30 +using Tuple = MvcMiniProfiler.Tuple; +#else using System.Collections.Concurrent; +#endif namespace MvcMiniProfiler { - - // TODO: refactor this out into MiniProfiler + // TODO: refactor this out into MiniProfiler /// /// Contains helper code to time sql statements. /// public class SqlProfiler { - ConcurrentDictionary, SqlTiming> _inProgress = new ConcurrentDictionary, SqlTiming>(); - ConcurrentDictionary _inProgressReaders = new ConcurrentDictionary(); - - /// +#if CSHARP30 + IConcurrentDictionary, SqlTiming> _inProgress = new MiniConcurrentDictionary, SqlTiming>(); + IConcurrentDictionary _inProgressReaders = new MiniConcurrentDictionary(); +#else + IConcurrentDictionary, SqlTiming> _inProgress = new MiniConcurrentDictionary, SqlTiming>(); + IConcurrentDictionary _inProgressReaders = new MiniConcurrentDictionary(); +#endif + /// /// The profiling session this SqlProfiler is part of. /// public MiniProfiler Profiler { get; private set; } diff --git a/MvcMiniProfiler/SqlTiming.cs b/MvcMiniProfiler/SqlTiming.cs index cf7e4b6..d1facf7 100644 --- a/MvcMiniProfiler/SqlTiming.cs +++ b/MvcMiniProfiler/SqlTiming.cs @@ -212,7 +212,7 @@ private List GetCommandParameters(DbCommand command) foreach (DbParameter dbParameter in command.Parameters) { - if (!string.IsNullOrWhiteSpace(dbParameter.ParameterName)) + if (!ExtensionMethods.IsNullOrWhiteSpace(dbParameter.ParameterName)) { var formattedParameterValue = GetFormattedParameterValue(dbParameter); result.Add(new SqlTimingParameter diff --git a/MvcMiniProfiler/Storage/SqlServerStorage.cs b/MvcMiniProfiler/Storage/SqlServerStorage.cs index a2d7a1b..ba91aad 100644 --- a/MvcMiniProfiler/Storage/SqlServerStorage.cs +++ b/MvcMiniProfiler/Storage/SqlServerStorage.cs @@ -265,7 +265,7 @@ protected virtual void SaveSqlTimingParameters(DbConnection conn, MiniProfiler p { typeof(SqlTimingParameter), "select * from MiniProfilerSqlTimingParameters where MiniProfilerId = @id" } }; - private static readonly string LoadSqlBatch = string.Join("\n", LoadSqlStatements.Select(pair => pair.Value)); + private static readonly string LoadSqlBatch = string.Join("\n", LoadSqlStatements.Select(pair => pair.Value).ToArray()); /// /// Loads the MiniProfiler identifed by 'id' from the database. @@ -297,7 +297,7 @@ private MiniProfiler LoadInBatch(DbConnection conn, object idParameter) { MiniProfiler result; - using (var multi = conn.QueryMultiple(LoadSqlBatch, idParameter)) + using (var multi = conn.QueryMultiple(LoadSqlBatch, idParameter, null, null, null)) { result = multi.Read().SingleOrDefault(); diff --git a/MvcMiniProfiler/UI/MiniProfilerHandler.cs b/MvcMiniProfiler/UI/MiniProfilerHandler.cs index 183f866..0d9a85b 100644 --- a/MvcMiniProfiler/UI/MiniProfilerHandler.cs +++ b/MvcMiniProfiler/UI/MiniProfilerHandler.cs @@ -178,11 +178,11 @@ private static string Results(HttpContext context) { // when we're rendering as a button/popup in the corner, we'll pass ?popup=1 // if it's absent, we're rendering results as a full page for sharing - var isPopup = !string.IsNullOrWhiteSpace(context.Request.QueryString["popup"]); + var isPopup = !ExtensionMethods.IsNullOrWhiteSpace(context.Request.QueryString["popup"]); // this guid is the MiniProfiler.Id property Guid id; - if (!Guid.TryParse(context.Request.QueryString["id"], out id)) + if (!GuidHelper.TryParse(context.Request.QueryString["id"], out id)) return isPopup ? NotFound(context) : NotFound(context, "text/plain", "No Guid id specified on the query string"); MiniProfiler.Settings.EnsureStorageStrategy(); @@ -259,6 +259,27 @@ private static string NotFound(HttpContext context, string contentType = "text/p return message; } - } + +#if CSHARP30 + internal class HtmlString + { + public HtmlString() + : this(String.Empty) + { + } + + public HtmlString(string value) + { + _value = value; + } + + private string _value; + + public override string ToString() + { + return _value; + } + } +#endif } diff --git a/MvcMiniProfiler/WebRequestProfilerProvider.cs b/MvcMiniProfiler/WebRequestProfilerProvider.cs index 483d67f..1daee53 100644 --- a/MvcMiniProfiler/WebRequestProfilerProvider.cs +++ b/MvcMiniProfiler/WebRequestProfilerProvider.cs @@ -1,9 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Web; +using System.Web; +using System.Web.Mvc; + +#if CSHARP30 using System.Web.Routing; +#endif + using MvcMiniProfiler.Helpers; namespace MvcMiniProfiler @@ -105,9 +106,18 @@ public override void Stop(bool discardResults) private static void EnsureName(MiniProfiler profiler, HttpRequest request) { // also set the profiler name to Controller/Action or /url - if (string.IsNullOrWhiteSpace(profiler.Name)) - { - var rc = request.RequestContext; + if (ExtensionMethods.IsNullOrWhiteSpace(profiler.Name)) + { +#if CSHARP30 + RequestContext rc = null; + var handler = HttpContext.Current.Handler as MvcHandler; + if (handler != null) + { + rc = handler.RequestContext; + } +#else + var rc = request.RequestContext; +#endif RouteValueDictionary values; if (rc != null && rc.RouteData != null && (values = rc.RouteData.Values).Count > 0) @@ -119,7 +129,7 @@ private static void EnsureName(MiniProfiler profiler, HttpRequest request) profiler.Name = controller.ToString() + "/" + action.ToString(); } - if (string.IsNullOrWhiteSpace(profiler.Name)) + if (ExtensionMethods.IsNullOrWhiteSpace(profiler.Name)) { profiler.Name = request.Url.AbsolutePath ?? ""; if (profiler.Name.Length > 50) diff --git a/Sample.Mvc/Sample.Mvc.csproj b/Sample.Mvc/Sample.Mvc.csproj index b4388ee..95a9bd2 100644 --- a/Sample.Mvc/Sample.Mvc.csproj +++ b/Sample.Mvc/Sample.Mvc.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/Sample.Wcf/Sample.Wcf.csproj b/Sample.Wcf/Sample.Wcf.csproj index e2c5cc1..46da249 100644 --- a/Sample.Wcf/Sample.Wcf.csproj +++ b/Sample.Wcf/Sample.Wcf.csproj @@ -1,4 +1,4 @@ - + Debug diff --git a/Sample.WebForms/Sample.WebForms.csproj b/Sample.WebForms/Sample.WebForms.csproj index f277dc8..7b5de34 100644 --- a/Sample.WebForms/Sample.WebForms.csproj +++ b/Sample.WebForms/Sample.WebForms.csproj @@ -1,4 +1,4 @@ - + Debug