From 746d3d54c25932de039e27feb8f56bc689a33430 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Tue, 18 Aug 2015 12:46:09 +0200 Subject: [PATCH 01/33] Fixes 5614 : ContentPickerField and LayoutPart throws argument null exception. --- .../Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs index b08c95247..9d037c02e 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs @@ -17,7 +17,7 @@ namespace Orchard.ContentPicker.Fields { public IEnumerable ContentItems { get { - return _contentItems.Value; + return _contentItems.Value ?? new ContentItem[0]; } } From 9980633ac3228c97939cb99100499567b6d2b544 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Thu, 20 Aug 2015 23:57:38 +0200 Subject: [PATCH 02/33] Use Enumerable.Empty --- .../Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs index 9d037c02e..8b7c15194 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Fields/ContentPickerField.cs @@ -17,7 +17,7 @@ namespace Orchard.ContentPicker.Fields { public IEnumerable ContentItems { get { - return _contentItems.Value ?? new ContentItem[0]; + return _contentItems.Value ?? Enumerable.Empty(); } } From cfc1dc23791c60427382f70696417a74785c5273 Mon Sep 17 00:00:00 2001 From: Gustavo Tandeciarz Date: Fri, 21 Aug 2015 20:08:41 -0400 Subject: [PATCH 03/33] Enables gulp watch of Assets.json Will restart the watch task when Assets.json is changed. --- src/Gulpfile.js | 54 ++++++++++++++++++++++++++++++++++-------------- src/Package.json | 4 +++- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Gulpfile.js b/src/Gulpfile.js index 05b62a89e..69a24ed64 100644 --- a/src/Gulpfile.js +++ b/src/Gulpfile.js @@ -13,7 +13,8 @@ var glob = require("glob"), uglify = require("gulp-uglify"), rename = require("gulp-rename"), concat = require("gulp-concat"), - header = require("gulp-header"); + header = require("gulp-header"), + fs = require("fs"); /* ** GULP TASKS @@ -37,32 +38,53 @@ gulp.task("rebuild", function () { return merge(assetGroupTasks); }); -// Continuous watch (each asset group is built whenever one of its inputs changes). + +// Set "Watchers" as sub-processes in order to restart the task when Assets.json changes. gulp.task("watch", function () { - var pathWin32 = require("path"); - getAssetGroups().forEach(function (assetGroup) { - var watchPaths = assetGroup.inputPaths.concat(assetGroup.watchPaths); - gulp.watch(watchPaths, function (event) { - var isConcat = path.basename(assetGroup.outputFileName, path.extname(assetGroup.outputFileName)) !== "@"; - if (isConcat) - console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group with output '" + assetGroup.outputPath + "'."); - else - console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group."); - var doRebuild = true; - var task = createAssetGroupTask(assetGroup, doRebuild); + var watchers; + function restart() { + if (watchers) { + watchers.forEach(function (w) { + w.remove(); + w.end(); + }); + } + watchers = []; + // Continuous watch (each asset group is built whenever one of its inputs changes). + getAssetGroups().forEach(function (assetGroup) { + var watchPaths = assetGroup.inputPaths.concat(assetGroup.watchPaths); + var watcher = gulp.watch(watchPaths, function (event) { + var isConcat = path.basename(assetGroup.outputFileName, path.extname(assetGroup.outputFileName)) !== "@"; + if (isConcat) + console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group with output '" + assetGroup.outputPath + "'."); + else + console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group."); + var doRebuild = true; + var task = createAssetGroupTask(assetGroup, doRebuild); + }); + watchers.push(watcher); }); + } + var p; + if (p) { p.exit(); } + p = gulp.watch("Orchard.Web/{Core,Modules,Themes}/*/Assets.json", function (event) { + console.log("Asset file '" + event.path + "' was " + event.type + ", resetting asset watchers."); + restart(); }); + restart(); }); + /* ** ASSET GROUPS */ - function getAssetGroups() { - var assetManifestPaths = glob.sync("Orchard.Web/{Core,Modules,Themes}/*/Assets.json"); + var assetManifestPaths = glob.sync("Orchard.Web/{Core,Modules,Themes}/*/Assets.json", {}); var assetGroups = []; assetManifestPaths.forEach(function (assetManifestPath) { - var assetManifest = require("./" + assetManifestPath); + var file = './' + assetManifestPath; + var json = fs.readFileSync(file, 'utf8'); + assetManifest = eval(json); assetManifest.forEach(function (assetGroup) { resolveAssetGroupPaths(assetGroup, assetManifestPath); assetGroups.push(assetGroup); diff --git a/src/Package.json b/src/Package.json index 96a154825..a46100b18 100644 --- a/src/Package.json +++ b/src/Package.json @@ -15,7 +15,9 @@ "gulp-uglify": "^1.2.0", "gulp-rename": "^1.2.2", "gulp-concat": "^2.5.2", - "gulp-header": "^1.2.2" + "gulp-header": "^1.2.2", + "gulp-util": "^3.0.6", + "fs": "^0.0.2" }, "dependencies": { } } From bbcdd67b95ca0247df064516e06be9caed72e3fe Mon Sep 17 00:00:00 2001 From: Gustavo Tandeciarz Date: Fri, 21 Aug 2015 20:15:51 -0400 Subject: [PATCH 04/33] Cleanup gulp-util was previously used during development and is no longer required. --- src/Package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Package.json b/src/Package.json index a46100b18..f096237f7 100644 --- a/src/Package.json +++ b/src/Package.json @@ -16,7 +16,6 @@ "gulp-rename": "^1.2.2", "gulp-concat": "^2.5.2", "gulp-header": "^1.2.2", - "gulp-util": "^3.0.6", "fs": "^0.0.2" }, "dependencies": { } From 4831b72bd174904f8854826774eb2ed64a9e5c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Wed, 26 Aug 2015 15:18:40 -0700 Subject: [PATCH 05/33] Improving DateTimeRelative shape The implementation was not relative for span further than a week. --- src/Orchard.Web/Core/Shapes/DateTimeShapes.cs | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs b/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs index f63f4bedc..12099ede3 100644 --- a/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs +++ b/src/Orchard.Web/Core/Shapes/DateTimeShapes.cs @@ -1,5 +1,4 @@ -using System; -using System.Globalization; +using System; using System.Web; using System.Web.Mvc; using Orchard.DisplayManagement; @@ -32,8 +31,20 @@ namespace Orchard.Core.Shapes { DateTimeUtc = DateTimeUtc != System.DateTime.MinValue ? DateTimeUtc : dateTimeUtc; // Both capitalizations retained for compatibility. var time = _clock.UtcNow - DateTimeUtc; - if (time.TotalDays > 7 || time.TotalDays < -7) - return Display.DateTime(DateTimeUtc: DateTimeUtc, CustomFormat: null); + if (time.TotalYears() > 1) + return T.Plural("1 year ago", "{0} years ago", time.TotalYears()); + if (time.TotalYears() < -1) + return T.Plural("in 1 year", "in {0} years", -time.TotalYears()); + + if (time.TotalMonths() > 1) + return T.Plural("1 month ago", "{0} months ago", time.TotalMonths()); + if (time.TotalMonths() < -1) + return T.Plural("in 1 month", "in {0} months", -time.TotalMonths()); + + if (time.TotalWeeks() > 1) + return T.Plural("1 week ago", "{0} weeks ago", time.TotalWeeks()); + if (time.TotalWeeks() < -1) + return T.Plural("in 1 week", "in {0} weeks", -time.TotalWeeks()); if (time.TotalHours > 24) return T.Plural("1 day ago", "{0} days ago", time.Days); @@ -71,4 +82,18 @@ namespace Orchard.Core.Shapes { return new MvcHtmlString(_dateLocalizationServices.ConvertToLocalizedString(DateTimeUtc, CustomFormat.Text)); } } -} \ No newline at end of file + + public static class TimespanExtensions { + public static int TotalWeeks(this TimeSpan time) { + return (int)time.TotalDays / 7; + } + + public static int TotalMonths(this TimeSpan time) { + return (int)time.TotalDays / 31; + } + + public static int TotalYears(this TimeSpan time) { + return (int)time.TotalDays / 365; + } + } +} From f5772334e163c470029593db8da34d2ec41511b3 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Thu, 3 Sep 2015 10:05:02 +0200 Subject: [PATCH 06/33] Fixes #5735 : ContentType name encoding in Lists --- .../Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml index 10a69f805..2bc7f83ec 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml @@ -5,13 +5,13 @@ }

- @Html.ActionLink(T("{0} Properties", (string)Model.ContainerDisplayName).ToString(), "Edit", new { Area = "Contents", Id = (int)Model.ContainerId, ReturnUrl = Html.ViewContext.HttpContext.Request.RawUrl }) + @Html.ActionLink(T("{0} Properties", Html.Raw((string)Model.ContainerDisplayName)).Text, "Edit", new { Area = "Contents", Id = (int)Model.ContainerId, ReturnUrl = Html.ViewContext.HttpContext.Request.RawUrl })

@if (itemContentTypes.Any()) { foreach (var contentType in itemContentTypes) { - @Html.ActionLink(T("New {0}", contentType.DisplayName).ToString(), "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" }) + @Html.ActionLink(T("New {0}", Html.Raw(contentType.DisplayName)).Text, "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" }) } } else { From 97bb52bbddc92d52d7eb198da45a055e24da35a6 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Fri, 4 Sep 2015 15:05:25 +0200 Subject: [PATCH 07/33] Add LinkExtensions Allows using IHtmlString as linkText --- src/Orchard/Mvc/Html/LinkExtensions.cs | 144 +++++++++++++++++++++++++ src/Orchard/Orchard.Framework.csproj | 1 + 2 files changed, 145 insertions(+) create mode 100644 src/Orchard/Mvc/Html/LinkExtensions.cs diff --git a/src/Orchard/Mvc/Html/LinkExtensions.cs b/src/Orchard/Mvc/Html/LinkExtensions.cs new file mode 100644 index 000000000..34db0c758 --- /dev/null +++ b/src/Orchard/Mvc/Html/LinkExtensions.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using System.Web.WebPages; + +namespace Orchard.Mvc.Html { + public static class LinkExtensions { + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName) { + return ActionLink(htmlHelper, linkText, actionName, null /* controllerName */, new RouteValueDictionary(), new RouteValueDictionary()); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, object routeValues) { + return ActionLink(htmlHelper, linkText, actionName, null /* controllerName */, ObjectToDictionary(routeValues), new RouteValueDictionary()); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, object routeValues, object htmlAttributes) { + return ActionLink(htmlHelper, linkText, actionName, null /* controllerName */, ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, RouteValueDictionary routeValues) { + return ActionLink(htmlHelper, linkText, actionName, null /* controllerName */, routeValues, new RouteValueDictionary()); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + return ActionLink(htmlHelper, linkText, actionName, null /* controllerName */, routeValues, htmlAttributes); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, string controllerName) { + return ActionLink(htmlHelper, linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary()); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, string controllerName, object routeValues, object htmlAttributes) { + return ActionLink(htmlHelper, linkText, actionName, controllerName, ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + if (String.IsNullOrEmpty(linkText.ToString())) { + throw new ArgumentException("Argument must be a non empty string", "linkText"); + } + return MvcHtmlString.Create(GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null /* routeName */, actionName, controllerName, routeValues, htmlAttributes)); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes) { + return ActionLink(htmlHelper, linkText, actionName, controllerName, protocol, hostName, fragment, ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + + public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, IHtmlString linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + if (String.IsNullOrEmpty(linkText.ToString())) { + throw new ArgumentException("Argument must be a non empty string", "linkText"); + } + return MvcHtmlString.Create(GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null /* routeName */, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, object routeValues) { + return RouteLink(htmlHelper, linkText, ObjectToDictionary(routeValues)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, RouteValueDictionary routeValues) { + return RouteLink(htmlHelper, linkText, routeValues, new RouteValueDictionary()); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName) { + return RouteLink(htmlHelper, linkText, routeName, (object)null /* routeValues */); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName, object routeValues) { + return RouteLink(htmlHelper, linkText, routeName, ObjectToDictionary(routeValues)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName, RouteValueDictionary routeValues) { + return RouteLink(htmlHelper, linkText, routeName, routeValues, new RouteValueDictionary()); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, object routeValues, object htmlAttributes) { + return RouteLink(htmlHelper, linkText, ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + return RouteLink(htmlHelper, linkText, null /* routeName */, routeValues, htmlAttributes); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName, object routeValues, object htmlAttributes) { + return RouteLink(htmlHelper, linkText, routeName, ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + if (String.IsNullOrEmpty(linkText.ToString())) { + throw new ArgumentException("Argument must be a non empty string", "linkText"); + } + return MvcHtmlString.Create(GenerateRouteLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, routeName, routeValues, htmlAttributes)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes) { + return RouteLink(htmlHelper, linkText, routeName, protocol, hostName, fragment, ObjectToDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + } + + public static MvcHtmlString RouteLink(this HtmlHelper htmlHelper, IHtmlString linkText, string routeName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + if (String.IsNullOrEmpty(linkText.ToString())) { + throw new ArgumentException("Argument must be a non empty string", "linkText"); + } + return MvcHtmlString.Create(GenerateRouteLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, routeName, protocol, hostName, fragment, routeValues, htmlAttributes)); + } + + public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, IHtmlString linkText, string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + return GenerateLink(requestContext, routeCollection, linkText, routeName, actionName, controllerName, null /* protocol */, null /* hostName */, null /* fragment */, routeValues, htmlAttributes); + } + + public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, IHtmlString linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, true /* includeImplicitMvcValues */); + } + + public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, IHtmlString linkText, string routeName, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + return GenerateRouteLink(requestContext, routeCollection, linkText, routeName, null /* protocol */, null /* hostName */, null /* fragment */, routeValues, htmlAttributes); + } + + public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, IHtmlString linkText, string routeName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary htmlAttributes) { + return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, null /* actionName */, null /* controllerName */, protocol, hostName, fragment, routeValues, htmlAttributes, false /* includeImplicitMvcValues */); + } + private static string GenerateLinkInternal(RequestContext requestContext, RouteCollection routeCollection, IHtmlString linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary htmlAttributes, bool includeImplicitMvcValues) { + string url = UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, routeCollection, requestContext, includeImplicitMvcValues); + TagBuilder tagBuilder = new TagBuilder("a") { + InnerHtml = linkText.ToString() + }; + tagBuilder.MergeAttributes(htmlAttributes); + tagBuilder.MergeAttribute("href", url); + return tagBuilder.ToString(TagRenderMode.Normal); + } + + private static RouteValueDictionary ObjectToDictionary(object value) { + RouteValueDictionary dictionary = new RouteValueDictionary(); + + if (value != null) { + foreach (var prop in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { + dictionary.Add(prop.Name, prop.GetValue(value)); + } + } + + return dictionary; + } + } +} diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index ee62487ba..eba605d31 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -150,6 +150,7 @@ + From 3efc38dc65cfd3d0814c97a52e41bbd853a6113b Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Fri, 4 Sep 2015 14:06:08 +0100 Subject: [PATCH 08/33] Refactored distributed locks to support existing installations. --- .../Services/SetupService.cs | 5 ++ .../Orchard.Setup/Services/SetupService.cs | 5 ++ .../Data/Migration/AutomaticDataMigrations.cs | 22 ++++++++- src/Orchard/Orchard.Framework.csproj | 2 +- .../Locking/Migrations/FrameworkMigrations.cs | 22 --------- .../Services/DistributedLockSchemaBuilder.cs | 47 +++++++++++++++++++ 6 files changed, 79 insertions(+), 24 deletions(-) delete mode 100644 src/Orchard/Tasks/Locking/Migrations/FrameworkMigrations.cs create mode 100644 src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.ImportExport/Services/SetupService.cs index c125a21c9..ffb149108 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Services/SetupService.cs @@ -20,6 +20,7 @@ using Orchard.Logging; using Orchard.Recipes.Services; using Orchard.Security; using Orchard.Settings; +using Orchard.Tasks.Locking.Services; using Orchard.Utility.Extensions; namespace Orchard.ImportExport.Services @@ -101,6 +102,10 @@ namespace Orchard.ImportExport.Services schemaBuilder.AlterTable("Orchard_Framework_DataMigrationRecord", table => table.AddUniqueConstraint("UC_DMR_DataMigrationClass_Version", "DataMigrationClass", "Version")); + // Create the distributed lock record schema. + var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder); + distributedLockSchemaBuilder.CreateSchema(); + var dataMigrationManager = environment.Resolve(); dataMigrationManager.Update("Settings"); diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index 16b3e465b..dfff5b008 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -23,6 +23,7 @@ using Orchard.Recipes.Models; using Orchard.Recipes.Services; using Orchard.Security; using Orchard.Settings; +using Orchard.Tasks.Locking.Services; using Orchard.Utility.Extensions; namespace Orchard.Setup.Services { @@ -154,6 +155,10 @@ namespace Orchard.Setup.Services { schemaBuilder.AlterTable("Orchard_Framework_DataMigrationRecord", table => table.AddUniqueConstraint("UC_DMR_DataMigrationClass_Version", "DataMigrationClass", "Version")); + // Create the distributed lock record schema. + var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder); + distributedLockSchemaBuilder.CreateSchema(); + var dataMigrationManager = environment.Resolve(); dataMigrationManager.Update("Settings"); diff --git a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs index 7c0693540..887e0a941 100644 --- a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs +++ b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs @@ -1,6 +1,9 @@ using System; using System.Linq; +using Orchard.Data.Migration.Interpreters; +using Orchard.Data.Migration.Schema; using Orchard.Environment; +using Orchard.Environment.Configuration; using Orchard.Environment.Features; using Orchard.Logging; using Orchard.Tasks.Locking.Services; @@ -13,15 +16,21 @@ namespace Orchard.Data.Migration { private readonly IDataMigrationManager _dataMigrationManager; private readonly IFeatureManager _featureManager; private readonly IDistributedLockService _distributedLockService; + private readonly IDataMigrationInterpreter _dataMigrationInterpreter; + private readonly ShellSettings _shellSettings; public AutomaticDataMigrations( IDataMigrationManager dataMigrationManager, + IDataMigrationInterpreter dataMigrationInterpreter, IFeatureManager featureManager, - IDistributedLockService distributedLockService) { + IDistributedLockService distributedLockService, + ShellSettings shellSettings) { _dataMigrationManager = dataMigrationManager; _featureManager = featureManager; _distributedLockService = distributedLockService; + _shellSettings = shellSettings; + _dataMigrationInterpreter = dataMigrationInterpreter; Logger = NullLogger.Instance; } @@ -30,6 +39,7 @@ namespace Orchard.Data.Migration { public void Activated() { IDistributedLock @lock; + EnsureDistributedLockSchema(); if(_distributedLockService.TryAcquireLock(GetType().FullName, TimeSpan.FromMinutes(30), TimeSpan.FromMilliseconds(250), out @lock)) { using (@lock) { // Let's make sure that the basic set of features is enabled. If there are any that are not enabled, then let's enable them first. @@ -58,5 +68,15 @@ namespace Orchard.Data.Migration { public void Terminating() { // No-op. } + + /// + /// This ensures that the framework migrations have run for the distributed locking feature, as existing Orchard installations will not have the required tables when upgrading. + /// + private void EnsureDistributedLockSchema() { + // Ensure the distributed lock record schema exists. + var schemaBuilder = new SchemaBuilder(_dataMigrationInterpreter); + var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder); + distributedLockSchemaBuilder.EnsureSchema(); + } } } diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 6e2f60292..11adc4cf9 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -399,7 +399,7 @@ - + diff --git a/src/Orchard/Tasks/Locking/Migrations/FrameworkMigrations.cs b/src/Orchard/Tasks/Locking/Migrations/FrameworkMigrations.cs deleted file mode 100644 index 2a43a2e19..000000000 --- a/src/Orchard/Tasks/Locking/Migrations/FrameworkMigrations.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Orchard.Data.Migration; - -namespace Orchard.Tasks.Locking.Migrations { - public class FrameworkMigrations : DataMigrationImpl { - - public int Create() { - SchemaBuilder.CreateTable("DistributedLockRecord", table => table - .Column("Id", column => column.PrimaryKey().Identity()) - .Column("Name", column => column.NotNull().WithLength(512).Unique()) - .Column("MachineName", column => column.WithLength(256)) - .Column("CreatedUtc") - .Column("ValidUntilUtc", column => column.Nullable())); - - SchemaBuilder.AlterTable("DistributedLockRecord", table => { - table.CreateIndex("IDX_DistributedLockRecord_Name", "Name"); - }); - - return 1; - } - } -} \ No newline at end of file diff --git a/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs b/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs new file mode 100644 index 000000000..8a577d8a1 --- /dev/null +++ b/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs @@ -0,0 +1,47 @@ +using System; +using Orchard.Data.Migration.Schema; +using Orchard.Environment.Configuration; + +namespace Orchard.Tasks.Locking.Services { + public class DistributedLockSchemaBuilder { + private readonly ShellSettings _shellSettings; + private readonly SchemaBuilder _schemaBuilder; + private const string TableName = "Orchard_Framework_DistributedLockRecord"; + + public DistributedLockSchemaBuilder(ShellSettings shellSettings, SchemaBuilder schemaBuilder) { + _shellSettings = shellSettings; + _schemaBuilder = schemaBuilder; + } + + public void EnsureSchema() { + if (SchemaExists()) + return; + + CreateSchema(); + } + + public void CreateSchema() { + _schemaBuilder.CreateTable(TableName, table => table + .Column("Id", column => column.PrimaryKey().Identity()) + .Column("Name", column => column.NotNull().WithLength(512).Unique()) + .Column("MachineName", column => column.WithLength(256)) + .Column("CreatedUtc") + .Column("ValidUntilUtc", column => column.Nullable())); + + _schemaBuilder.AlterTable(TableName, table => { + table.CreateIndex("IDX_DistributedLockRecord_Name", "Name"); + }); + } + + public bool SchemaExists() { + try { + var tablePrefix = String.IsNullOrEmpty(_shellSettings.DataTablePrefix) ? "" : _shellSettings.DataTablePrefix + "_"; + _schemaBuilder.ExecuteSql(String.Format("select * from {0}{1}", tablePrefix, TableName)); + return true; + } + catch { + return false; + } + } + } +} \ No newline at end of file From 894e90f485bd7c024e19152154d75e51c8883c83 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Fri, 4 Sep 2015 15:08:30 +0200 Subject: [PATCH 09/33] Use new ActionLink extension method. --- .../Orchard.Lists/Views/Parts.Container.Manage.cshtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml b/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml index 2bc7f83ec..636dff05e 100644 --- a/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Lists/Views/Parts.Container.Manage.cshtml @@ -5,17 +5,17 @@ }

- @Html.ActionLink(T("{0} Properties", Html.Raw((string)Model.ContainerDisplayName)).Text, "Edit", new { Area = "Contents", Id = (int)Model.ContainerId, ReturnUrl = Html.ViewContext.HttpContext.Request.RawUrl }) + @Html.ActionLink(T("{0} Properties", (string)Model.ContainerDisplayName), "Edit", new { Area = "Contents", Id = (int)Model.ContainerId, ReturnUrl = Html.ViewContext.HttpContext.Request.RawUrl })

@if (itemContentTypes.Any()) { foreach (var contentType in itemContentTypes) { - @Html.ActionLink(T("New {0}", Html.Raw(contentType.DisplayName)).Text, "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" }) + @Html.ActionLink(T("New {0}", contentType.DisplayName), "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" }) } } else { - @Html.ActionLink(T("New Content").ToString(), "Create", "Admin", new { area = "Contents", containerId }, new { @class = "button primaryAction create-content" }) + @Html.ActionLink(T("New Content"), "Create", "Admin", new { area = "Contents", containerId }, new { @class = "button primaryAction create-content" }) } @T("Choose Items")
From 94db186b37fff9fc60a796bff6bc9648a0b7aec3 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Fri, 4 Sep 2015 14:43:30 +0100 Subject: [PATCH 10/33] Minor polishing. --- src/Orchard/Data/Migration/AutomaticDataMigrations.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs index 887e0a941..088903a06 100644 --- a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs +++ b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs @@ -38,8 +38,9 @@ namespace Orchard.Data.Migration { public ILogger Logger { get; set; } public void Activated() { + EnsureDistributedLockSchemaExists(); + IDistributedLock @lock; - EnsureDistributedLockSchema(); if(_distributedLockService.TryAcquireLock(GetType().FullName, TimeSpan.FromMinutes(30), TimeSpan.FromMilliseconds(250), out @lock)) { using (@lock) { // Let's make sure that the basic set of features is enabled. If there are any that are not enabled, then let's enable them first. @@ -72,7 +73,7 @@ namespace Orchard.Data.Migration { /// /// This ensures that the framework migrations have run for the distributed locking feature, as existing Orchard installations will not have the required tables when upgrading. /// - private void EnsureDistributedLockSchema() { + private void EnsureDistributedLockSchemaExists() { // Ensure the distributed lock record schema exists. var schemaBuilder = new SchemaBuilder(_dataMigrationInterpreter); var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder); From 9b91b1b2609439bb50dfc0321e72e5f39a95022f Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 4 Sep 2015 13:20:08 -0700 Subject: [PATCH 11/33] Removing unnecessary resolution --- src/Orchard/Mvc/MvcModule.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index 2da05b755..4125c4706 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -52,7 +52,6 @@ namespace Orchard.Mvc { var baseUrl = new Func(() => siteService.GetSiteSettings().BaseUrl); var httpContextBase = new HttpContextPlaceholder(baseUrl); - context.Resolve().CreateWorkContextScope(httpContextBase); return httpContextBase; } From 39fb266221046363943593dbe168598a2e2f16b9 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 4 Sep 2015 15:59:24 -0700 Subject: [PATCH 12/33] Skipping DateTime tests until the right solution is found c.f. #5702 --- src/Orchard.Tests/Localization/DateTimePartsTests.cs | 2 +- src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Orchard.Tests/Localization/DateTimePartsTests.cs b/src/Orchard.Tests/Localization/DateTimePartsTests.cs index 4532b0448..77340e45c 100644 --- a/src/Orchard.Tests/Localization/DateTimePartsTests.cs +++ b/src/Orchard.Tests/Localization/DateTimePartsTests.cs @@ -4,7 +4,7 @@ using Orchard.Localization.Models; namespace Orchard.Tests.Localization { - [TestFixture] + [TestFixture(Ignore = true, IgnoreReason = "Long running tests, stable code.")] public class DateTimePartsTests { [Test] diff --git a/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs b/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs index 8a4226c84..0e9534109 100644 --- a/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs +++ b/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -13,7 +12,7 @@ using Orchard.Localization.Services; namespace Orchard.Tests.Localization { - [TestFixture] + [TestFixture(Ignore = true, IgnoreReason = "Long running tests, stable code.")] public class DefaultDateFormatterTests { [SetUp] From 14482162fd4abec3e3ebc585871e993be54ce359 Mon Sep 17 00:00:00 2001 From: Daniel Stolt Date: Sun, 6 Sep 2015 00:31:15 +0200 Subject: [PATCH 13/33] Marked some tests as long-running. Fixes #5702. --- src/Orchard.Tests/Localization/DateTimePartsTests.cs | 2 +- src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Tests/Localization/DateTimePartsTests.cs b/src/Orchard.Tests/Localization/DateTimePartsTests.cs index 77340e45c..6a3ee09e4 100644 --- a/src/Orchard.Tests/Localization/DateTimePartsTests.cs +++ b/src/Orchard.Tests/Localization/DateTimePartsTests.cs @@ -4,7 +4,7 @@ using Orchard.Localization.Models; namespace Orchard.Tests.Localization { - [TestFixture(Ignore = true, IgnoreReason = "Long running tests, stable code.")] + [TestFixture()] public class DateTimePartsTests { [Test] diff --git a/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs b/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs index 0e9534109..a2135f09c 100644 --- a/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs +++ b/src/Orchard.Tests/Localization/DefaultDateFormatterTests.cs @@ -12,7 +12,8 @@ using Orchard.Localization.Services; namespace Orchard.Tests.Localization { - [TestFixture(Ignore = true, IgnoreReason = "Long running tests, stable code.")] + [TestFixture()] + [Category("longrunning")] public class DefaultDateFormatterTests { [SetUp] From a6855171184a28707ac7d5443719cdb2e23b50a0 Mon Sep 17 00:00:00 2001 From: Lombiq Date: Mon, 7 Sep 2015 00:17:57 +0200 Subject: [PATCH 14/33] Normalizing all catch (Exception ex) lines and adding exception fatality check where applicable, fixes #3949 --- src/Orchard.WarmupStarter/Starter.cs | 4 +- .../Navigation/Controllers/AdminController.cs | 5 +++ .../Navigation/Services/NavigationManager.cs | 10 +++++ .../Services/ScheduledTaskExecutor.cs | 4 ++ .../Drivers/SiteSettingsPartDriver.cs | 8 +++- .../Metadata/ContentDefinitionManager.cs | 4 ++ .../Caching/DefaultAsyncTokenProvider.cs | 10 +++-- src/Orchard/Commands/CommandHostAgent.cs | 39 ++++++++++++------- .../Commands/DefaultOrchardCommandHandler.cs | 8 +++- .../Data/Migration/AutomaticDataMigrations.cs | 8 +++- .../Data/Migration/DataMigrationManager.cs | 13 +++++-- .../Data/Migration/Schema/SchemaBuilder.cs | 4 ++ src/Orchard/Data/SessionConfigurationCache.cs | 12 ++++-- src/Orchard/Environment/DefaultOrchardHost.cs | 8 +++- .../Environment/DefaultOrchardShell.cs | 9 ++++- .../Compilers/DefaultExtensionCompiler.cs | 8 +++- .../Extensions/ExtensionManager.cs | 4 ++ .../Extensions/Folders/ExtensionHarvester.cs | 4 ++ src/Orchard/Environment/IAssemblyLoader.cs | 9 ++++- src/Orchard/Environment/IBuildManager.cs | 5 ++- src/Orchard/Environment/IHostLocalRestart.cs | 8 +++- .../Environment/ViewsBackgroundCompilation.cs | 8 +++- src/Orchard/Events/DefaultOrchardEventBus.cs | 4 ++ .../FileSystems/AppData/AppDataFolder.cs | 8 +++- .../DefaultExtensionDependenciesManager.cs | 8 +++- .../Media/FileSystemStorageProvider.cs | 4 ++ .../VirtualPath/DefaultVirtualPathProvider.cs | 15 +++++-- .../Services/DefaultMessageManager.cs | 15 +++++-- src/Orchard/Mvc/MvcModule.cs | 7 +++- src/Orchard/Tasks/BackgroundService.cs | 9 ++++- src/Orchard/Tasks/SweepGenerator.cs | 5 +++ src/Orchard/Time/SiteTimeZoneSelector.cs | 8 +++- .../Admin/Notification/NotificationManager.cs | 8 +++- 33 files changed, 217 insertions(+), 66 deletions(-) diff --git a/src/Orchard.WarmupStarter/Starter.cs b/src/Orchard.WarmupStarter/Starter.cs index ffa1f0763..b0b328da4 100644 --- a/src/Orchard.WarmupStarter/Starter.cs +++ b/src/Orchard.WarmupStarter/Starter.cs @@ -89,9 +89,9 @@ namespace Orchard.WarmupStarter { var result = _initialization(application); _initializationResult = result; } - catch (Exception e) { + catch (Exception ex) { lock (_synLock) { - _error = e; + _error = ex; _previousError = null; } } diff --git a/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs b/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs index 659a998db..a0b8087f2 100644 --- a/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs @@ -17,6 +17,7 @@ using Orchard.UI.Navigation; using Orchard.Utility; using System; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Core.Navigation.Controllers { [ValidateInput(false)] @@ -179,6 +180,10 @@ namespace Orchard.Core.Navigation.Controllers { return View(model); } catch (Exception exception) { + if (exception.IsFatal()) { + throw; + } + Logger.Error(T("Creating menu item failed: {0}", exception.Message).Text); Services.Notifier.Error(T("Creating menu item failed: {0}", exception.Message)); return this.RedirectLocal(returnUrl, () => RedirectToAction("Index")); diff --git a/src/Orchard.Web/Core/Navigation/Services/NavigationManager.cs b/src/Orchard.Web/Core/Navigation/Services/NavigationManager.cs index bf7a529ea..a090a1bb2 100644 --- a/src/Orchard.Web/Core/Navigation/Services/NavigationManager.cs +++ b/src/Orchard.Web/Core/Navigation/Services/NavigationManager.cs @@ -11,6 +11,7 @@ using Orchard.Security.Permissions; using Orchard.UI; using Orchard.UI.Navigation; using Orchard.Utility; +using Orchard.Exceptions; namespace Orchard.Core.Navigation.Services { public class NavigationManager : INavigationManager { @@ -152,6 +153,9 @@ namespace Orchard.Core.Navigation.Services { items = builder.Build(); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "Unexpected error while querying a navigation provider. It was ignored. The menu provided by the provider may not be complete."); } if (items != null) { @@ -170,6 +174,9 @@ namespace Orchard.Core.Navigation.Services { items = builder.Build(); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "Unexpected error while querying a menu provider. It was ignored. The menu provided by the provider may not be complete."); } if (items != null) { @@ -188,6 +195,9 @@ namespace Orchard.Core.Navigation.Services { imageSets = builder.BuildImageSets(); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "Unexpected error while querying a navigation provider. It was ignored. The menu provided by the provider may not be complete."); } if (imageSets != null) { diff --git a/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskExecutor.cs b/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskExecutor.cs index 8485a9518..d4483aaab 100644 --- a/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskExecutor.cs +++ b/src/Orchard.Web/Core/Scheduling/Services/ScheduledTaskExecutor.cs @@ -9,6 +9,7 @@ using Orchard.Logging; using Orchard.Services; using Orchard.Tasks; using Orchard.Tasks.Scheduling; +using Orchard.Exceptions; namespace Orchard.Core.Scheduling.Services { [UsedImplicitly] @@ -65,6 +66,9 @@ namespace Orchard.Core.Scheduling.Services { } } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Warning(ex, "Unable to process scheduled task #{0} of type {1}", taskEntry.Id, taskEntry.Action); _transactionManager.Cancel(); } diff --git a/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs b/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs index 6cba80e53..5591115e5 100644 --- a/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs +++ b/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs @@ -11,6 +11,7 @@ using Orchard.Logging; using Orchard.Security; using Orchard.Settings; using Orchard.UI.Notify; +using Orchard.Exceptions; namespace Orchard.Core.Settings.Drivers { [UsedImplicitly] @@ -102,9 +103,12 @@ namespace Orchard.Core.Settings.Drivers { using (request.GetResponse() as HttpWebResponse) {} } } - catch (Exception e) { + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } _notifier.Warning(T("The base url you entered could not be requested from current location.")); - Logger.Warning(e, "Could not query base url: {0}", model.Site.BaseUrl); + Logger.Warning(ex, "Could not query base url: {0}", model.Site.BaseUrl); } } } diff --git a/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs b/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs index e434318e1..16c1d1f78 100644 --- a/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs +++ b/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs @@ -9,6 +9,7 @@ using Orchard.ContentManagement.MetaData.Services; using Orchard.Core.Settings.Metadata.Records; using Orchard.Data; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Core.Settings.Metadata { public class ContentDefinitionManager : Component, IContentDefinitionManager { @@ -282,6 +283,9 @@ namespace Orchard.Core.Settings.Metadata { return XElement.Parse(settings); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "Unable to parse settings xml"); return null; } diff --git a/src/Orchard/Caching/DefaultAsyncTokenProvider.cs b/src/Orchard/Caching/DefaultAsyncTokenProvider.cs index b6769ec82..9f13571c0 100644 --- a/src/Orchard/Caching/DefaultAsyncTokenProvider.cs +++ b/src/Orchard/Caching/DefaultAsyncTokenProvider.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Caching { public class DefaultAsyncTokenProvider : IAsyncTokenProvider { @@ -37,9 +38,12 @@ namespace Orchard.Caching { try { _task(token => _taskTokens.Add(token)); } - catch (Exception e) { - Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current."); - _taskException = e; + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "Error while monitoring extension files. Assuming extensions are not current."); + _taskException = ex; } finally { _isTaskFinished = true; diff --git a/src/Orchard/Commands/CommandHostAgent.cs b/src/Orchard/Commands/CommandHostAgent.cs index 6c7a955aa..04ab5a31a 100644 --- a/src/Orchard/Commands/CommandHostAgent.cs +++ b/src/Orchard/Commands/CommandHostAgent.cs @@ -15,6 +15,7 @@ using Orchard.FileSystems.VirtualPath; using Orchard.Localization; using Orchard.Logging; using Orchard.Tasks; +using Orchard.Exceptions; namespace Orchard.Commands { @@ -94,19 +95,21 @@ namespace Orchard.Commands { return CommandReturnCodes.Ok; } - catch (OrchardCommandHostRetryException e) { + catch (OrchardCommandHostRetryException ex) { // Special "Retry" return code for our host - output.WriteLine(T("{0} (Retrying...)", e.Message)); + output.WriteLine(T("{0} (Retrying...)", ex.Message)); return CommandReturnCodes.Retry; } - catch (Exception e) { - if (e is TargetInvocationException && - e.InnerException != null) { - // If this is an exception coming from reflection and there is an innerexception which is the actual one, redirect - e = e.InnerException; + catch (Exception ex) { + if (ex.IsFatal()) { + throw; } - - OutputException(output, T("Error executing command \"{0}\"", string.Join(" ", args)), e); + if (ex is TargetInvocationException && + ex.InnerException != null) { + // If this is an exception coming from reflection and there is an innerexception which is the actual one, redirect + ex = ex.InnerException; + } + OutputException(output, T("Error executing command \"{0}\"", string.Join(" ", args)), ex); return CommandReturnCodes.Fail; } } @@ -116,13 +119,16 @@ namespace Orchard.Commands { _hostContainer = CreateHostContainer(); return CommandReturnCodes.Ok; } - catch (OrchardCommandHostRetryException e) { + catch (OrchardCommandHostRetryException ex) { // Special "Retry" return code for our host - output.WriteLine(T("{0} (Retrying...)", e.Message)); + output.WriteLine(T("{0} (Retrying...)", ex.Message)); return CommandReturnCodes.Retry; } - catch (Exception e) { - OutputException(output, T("Error starting up Orchard command line host"), e); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + OutputException(output, T("Error starting up Orchard command line host"), ex); return CommandReturnCodes.Fail; } } @@ -135,8 +141,11 @@ namespace Orchard.Commands { } return CommandReturnCodes.Ok; } - catch (Exception e) { - OutputException(output, T("Error shutting down Orchard command line host"), e); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + OutputException(output, T("Error shutting down Orchard command line host"), ex); return CommandReturnCodes.Fail; } } diff --git a/src/Orchard/Commands/DefaultOrchardCommandHandler.cs b/src/Orchard/Commands/DefaultOrchardCommandHandler.cs index a5e8a3d89..7936ddef1 100644 --- a/src/Orchard/Commands/DefaultOrchardCommandHandler.cs +++ b/src/Orchard/Commands/DefaultOrchardCommandHandler.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Orchard.Localization; +using Orchard.Exceptions; namespace Orchard.Commands { public abstract class DefaultOrchardCommandHandler : ICommandHandler { @@ -41,12 +42,15 @@ namespace Orchard.Commands { object value = Convert.ChangeType(commandSwitch.Value, propertyInfo.PropertyType); propertyInfo.SetValue(this, value, null/*index*/); } - catch(Exception e) { + catch(Exception ex) { + if (ex.IsFatal()) { + throw; + } string message = T("Error converting value \"{0}\" to \"{1}\" for switch \"{2}\"", LocalizedString.TextOrDefault(commandSwitch.Value, T("(empty)")), propertyInfo.PropertyType.FullName, commandSwitch.Key).Text; - throw new InvalidOperationException(message, e); + throw new InvalidOperationException(message, ex); } } diff --git a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs index 2a6e1ed49..9f3abddd9 100644 --- a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs +++ b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs @@ -3,6 +3,7 @@ using System.Linq; using Orchard.Environment; using Orchard.Environment.Features; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Data.Migration { /// @@ -41,8 +42,11 @@ namespace Orchard.Data.Migration { try { _dataMigrationManager.Update(feature); } - catch (Exception e) { - Logger.Error("Could not run migrations automatically on " + feature, e); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error("Could not run migrations automatically on " + feature, ex); } } } diff --git a/src/Orchard/Data/Migration/DataMigrationManager.cs b/src/Orchard/Data/Migration/DataMigrationManager.cs index 1ef6e33d7..02c6204f0 100644 --- a/src/Orchard/Data/Migration/DataMigrationManager.cs +++ b/src/Orchard/Data/Migration/DataMigrationManager.cs @@ -9,6 +9,7 @@ using Orchard.Data.Migration.Schema; using Orchard.Environment.Extensions; using Orchard.Localization; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Data.Migration { /// @@ -123,6 +124,9 @@ namespace Orchard.Data.Migration { current = (int)lookupTable[current].Invoke(migration, new object[0]); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}.", feature, current); throw; } @@ -139,10 +143,13 @@ namespace Orchard.Data.Migration { dataMigrationRecord.Version = current; } } - catch (Exception e) { - Logger.Error(e, "Error while running migration version {0} for {1}.", current, feature); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "Error while running migration version {0} for {1}.", current, feature); _transactionManager.Cancel(); - throw new OrchardException(T("Error while running migration version {0} for {1}.", current, feature), e); + throw new OrchardException(T("Error while running migration version {0} for {1}.", current, feature), ex); } } diff --git a/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs b/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs index de5291a61..15e149f1e 100644 --- a/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs +++ b/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs @@ -1,6 +1,7 @@ using System; using Orchard.Data.Migration.Interpreters; using Orchard.Localization; +using Orchard.Exceptions; namespace Orchard.Data.Migration.Schema { public class SchemaBuilder { @@ -65,6 +66,9 @@ namespace Orchard.Data.Migration.Schema { Run(sqlStatmentCommand); return this; } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } throw new OrchardException(T("An unexpected error occured while executing the SQL statement: {0}", sql), ex); // Add the sql to the nested exception information } } diff --git a/src/Orchard/Data/SessionConfigurationCache.cs b/src/Orchard/Data/SessionConfigurationCache.cs index 037f80801..30bae0547 100644 --- a/src/Orchard/Data/SessionConfigurationCache.cs +++ b/src/Orchard/Data/SessionConfigurationCache.cs @@ -11,6 +11,7 @@ using Orchard.Environment.ShellBuilders.Models; using Orchard.FileSystems.AppData; using Orchard.Logging; using Orchard.Utility; +using Orchard.Exceptions; namespace Orchard.Data { public class SessionConfigurationCache : ISessionConfigurationCache { @@ -80,11 +81,11 @@ namespace Orchard.Data { formatter.Serialize(stream, cache.Configuration); } } - catch (SerializationException e) { + catch (SerializationException ex) { //Note: This can happen when multiple processes/AppDomains try to save // the cached configuration at the same time. Only one concurrent // writer will win, and it's harmless for the other ones to fail. - for (Exception scan = e; scan != null; scan = scan.InnerException) + for (Exception scan = ex; scan != null; scan = scan.InnerException) Logger.Warning("Error storing new NHibernate cache configuration: {0}", scan.Message); } } @@ -118,8 +119,11 @@ namespace Orchard.Data { }; } } - catch (Exception e) { - for (var scan = e; scan != null; scan = scan.InnerException) + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + for (var scan = ex; scan != null; scan = scan.InnerException) Logger.Warning("Error reading the cached NHibernate configuration: {0}", scan.Message); Logger.Information("A new one will be re-generated."); return null; diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index 977515317..c3d9fa782 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -13,6 +13,7 @@ using Orchard.Environment.Descriptor.Models; using Orchard.Localization; using Orchard.Logging; using Orchard.Utility.Extensions; +using Orchard.Exceptions; namespace Orchard.Environment { // All the event handlers that DefaultOrchardHost implements have to be declared in OrchardStarter @@ -140,8 +141,11 @@ namespace Orchard.Environment { var context = CreateShellContext(settings); ActivateShell(context); } - catch (Exception e) { - Logger.Error(e, "A tenant could not be started: " + settings.Name); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "A tenant could not be started: " + settings.Name); } while (_processingEngine.AreTasksPending()) { Logger.Debug("Processing pending task after activate Shell"); diff --git a/src/Orchard/Environment/DefaultOrchardShell.cs b/src/Orchard/Environment/DefaultOrchardShell.cs index a679dec17..c4f42b786 100644 --- a/src/Orchard/Environment/DefaultOrchardShell.cs +++ b/src/Orchard/Environment/DefaultOrchardShell.cs @@ -13,6 +13,7 @@ using Orchard.Tasks; using Orchard.UI; using Orchard.WebApi.Routes; using Owin; +using Orchard.Exceptions; using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider; namespace Orchard.Environment { @@ -102,8 +103,12 @@ namespace Orchard.Environment { try { action(); } - catch(Exception e) { - Logger.Error(e, "An unexcepted error occured while terminating the Shell"); + catch(Exception ex) { + if (ex.IsFatal()) { + throw; + } + + Logger.Error(ex, "An unexcepted error occured while terminating the Shell"); } } } diff --git a/src/Orchard/Environment/Extensions/Compilers/DefaultExtensionCompiler.cs b/src/Orchard/Environment/Extensions/Compilers/DefaultExtensionCompiler.cs index 3dfc2d6af..488dcb90a 100644 --- a/src/Orchard/Environment/Extensions/Compilers/DefaultExtensionCompiler.cs +++ b/src/Orchard/Environment/Extensions/Compilers/DefaultExtensionCompiler.cs @@ -8,6 +8,7 @@ using Orchard.FileSystems.Dependencies; using Orchard.FileSystems.VirtualPath; using Orchard.Localization; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Environment.Extensions.Compilers { /// @@ -106,10 +107,13 @@ namespace Orchard.Environment.Extensions.Compilers { } } } - catch (Exception e) { + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } //Note: we need to embed the "e.Message" in the exception text because // ASP.NET build manager "swallows" inner exceptions from this method. - throw new OrchardCoreException(T("Error compiling module \"{0}\" from file \"{1}\":\r\n{2}", moduleName, context.VirtualPath, e.Message), e); + throw new OrchardCoreException(T("Error compiling module \"{0}\" from file \"{1}\":\r\n{2}", moduleName, context.VirtualPath, ex.Message), ex); } } diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index 3701c9764..4dc8c02d3 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -9,6 +9,7 @@ using Orchard.Localization; using Orchard.Logging; using Orchard.Utility; using Orchard.Utility.Extensions; +using Orchard.Exceptions; namespace Orchard.Environment.Extensions { public class ExtensionManager : IExtensionManager { @@ -119,6 +120,9 @@ namespace Orchard.Environment.Extensions { }); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "Error loading extension '{0}'", extensionId); throw new OrchardException(T("Error while loading extension '{0}'.", extensionId), ex); } diff --git a/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs b/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs index a6ad55c72..38215b366 100644 --- a/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs +++ b/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs @@ -8,6 +8,7 @@ using Orchard.FileSystems.WebSite; using Orchard.Localization; using Orchard.Logging; using Orchard.Utility.Extensions; +using Orchard.Exceptions; namespace Orchard.Environment.Extensions.Folders { public class ExtensionHarvester : IExtensionHarvester { @@ -98,6 +99,9 @@ namespace Orchard.Environment.Extensions.Folders { } catch (Exception ex) { // Ignore invalid module manifests + if (ex.IsFatal()) { + throw; + } Logger.Error(ex, "The module '{0}' could not be loaded. It was ignored.", extensionId); _criticalErrorProvider.RegisterErrorMessage(T("The extension '{0}' manifest could not be loaded. It was ignored.", extensionId)); } diff --git a/src/Orchard/Environment/IAssemblyLoader.cs b/src/Orchard/Environment/IAssemblyLoader.cs index 410822a45..32722b5f1 100644 --- a/src/Orchard/Environment/IAssemblyLoader.cs +++ b/src/Orchard/Environment/IAssemblyLoader.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using Orchard.Logging; +using Orchard.Exceptions; + namespace Orchard.Environment { public interface IAssemblyLoader { @@ -25,8 +27,11 @@ namespace Orchard.Environment { try { return _loadedAssemblies.GetOrAdd(this.ExtractAssemblyShortName(assemblyName), shortName => LoadWorker(shortName, assemblyName)); } - catch (Exception e) { - Logger.Error(e, "Error loading assembly '{0}'", assemblyName); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "Error loading assembly '{0}'", assemblyName); return null; } } diff --git a/src/Orchard/Environment/IBuildManager.cs b/src/Orchard/Environment/IBuildManager.cs index d9ac231ab..40b8c9aa8 100644 --- a/src/Orchard/Environment/IBuildManager.cs +++ b/src/Orchard/Environment/IBuildManager.cs @@ -53,8 +53,9 @@ namespace Orchard.Environment { return BuildManager.GetCompiledAssembly(virtualPath); } catch (Exception ex) { - if (ex.IsFatal()) throw; - + if (ex.IsFatal()) { + throw; + } Logger.Warning(ex, "Error when compiling assembly under {0}.", virtualPath); return null; } diff --git a/src/Orchard/Environment/IHostLocalRestart.cs b/src/Orchard/Environment/IHostLocalRestart.cs index 90a2371d2..f801e6efe 100644 --- a/src/Orchard/Environment/IHostLocalRestart.cs +++ b/src/Orchard/Environment/IHostLocalRestart.cs @@ -5,6 +5,7 @@ using Orchard.Environment.Descriptor; using Orchard.Environment.Descriptor.Models; using Orchard.FileSystems.AppData; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Environment { public interface IHostLocalRestart { @@ -45,8 +46,11 @@ namespace Orchard.Environment { try { _appDataFolder.CreateFile(fileName, "Host Restart"); } - catch(Exception e) { - Logger.Warning(e, "Error updating file '{0}'", fileName); + catch(Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Warning(ex, "Error updating file '{0}'", fileName); } } } diff --git a/src/Orchard/Environment/ViewsBackgroundCompilation.cs b/src/Orchard/Environment/ViewsBackgroundCompilation.cs index 67ae7ac1f..4d5e949d7 100644 --- a/src/Orchard/Environment/ViewsBackgroundCompilation.cs +++ b/src/Orchard/Environment/ViewsBackgroundCompilation.cs @@ -6,6 +6,7 @@ using System.Timers; using System.Web.Compilation; using Orchard.FileSystems.VirtualPath; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Environment { public interface IViewsBackgroundCompilation { @@ -136,10 +137,13 @@ namespace Orchard.Environment { if (firstFile != null) BuildManager.GetCompiledAssembly(firstFile); } - catch(Exception e) { + catch(Exception ex) { + if (ex.IsFatal()) { + throw; + } // Some views might not compile, this is ok and harmless in this // context of pre-compiling views. - Logger.Information(e, "Compilation of directory '{0}' skipped", viewDirectory); + Logger.Information(ex, "Compilation of directory '{0}' skipped", viewDirectory); } stopwatch.Stop(); Logger.Information("Directory '{0}' compiled in {1} msec", viewDirectory, stopwatch.ElapsedMilliseconds); diff --git a/src/Orchard/Events/DefaultOrchardEventBus.cs b/src/Orchard/Events/DefaultOrchardEventBus.cs index d69d84023..adcab90d4 100644 --- a/src/Orchard/Events/DefaultOrchardEventBus.cs +++ b/src/Orchard/Events/DefaultOrchardEventBus.cs @@ -7,6 +7,7 @@ using System.Reflection; using Autofac.Features.Indexed; using Orchard.Exceptions; using Orchard.Localization; +using Orchard.Exceptions; namespace Orchard.Events { public class DefaultOrchardEventBus : IEventBus { @@ -53,6 +54,9 @@ namespace Orchard.Events { return TryInvoke(eventHandler, messageName, interfaceName, methodName, eventData, out returnValue); } catch (Exception exception) { + if (exception.IsFatal()) { + throw; + } if (!_exceptionPolicy.HandleException(this, exception)) { throw; } diff --git a/src/Orchard/FileSystems/AppData/AppDataFolder.cs b/src/Orchard/FileSystems/AppData/AppDataFolder.cs index 02e60e283..092ca9b45 100644 --- a/src/Orchard/FileSystems/AppData/AppDataFolder.cs +++ b/src/Orchard/FileSystems/AppData/AppDataFolder.cs @@ -7,6 +7,7 @@ using Orchard.FileSystems.VirtualPath; using Orchard.Localization; using Orchard.Logging; using Orchard.Validation; +using Orchard.Exceptions; namespace Orchard.FileSystems.AppData { public class AppDataFolder : IAppDataFolder { @@ -78,8 +79,11 @@ namespace Orchard.FileSystems.AppData { try { File.Delete(destinationFileName); } - catch (Exception e) { - throw new OrchardCoreException(T("Unable to make room for file \"{0}\" in \"App_Data\" folder", destinationFileName), e); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + throw new OrchardCoreException(T("Unable to make room for file \"{0}\" in \"App_Data\" folder", destinationFileName), ex); } } diff --git a/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs b/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs index c917c679d..1afd04077 100644 --- a/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs +++ b/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs @@ -5,6 +5,7 @@ using System.Xml.Linq; using Orchard.Caching; using Orchard.FileSystems.AppData; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.FileSystems.Dependencies { /// @@ -135,8 +136,11 @@ namespace Orchard.FileSystems.Dependencies { return XDocument.Load(stream); } } - catch (Exception e) { - Logger.Information(e, "Error reading file '{0}'. Assuming empty.", persistancePath); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Information(ex, "Error reading file '{0}'. Assuming empty.", persistancePath); return new XDocument(); } } diff --git a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs index 5b6200657..ebcde7b54 100644 --- a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs +++ b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs @@ -6,6 +6,7 @@ using System.Web.Hosting; using Orchard.Environment.Configuration; using Orchard.Localization; using Orchard.Validation; +using Orchard.Exceptions; namespace Orchard.FileSystems.Media { public class FileSystemStorageProvider : IStorageProvider { @@ -155,6 +156,9 @@ namespace Orchard.FileSystems.Media { directoryInfo.Create(); } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } throw new ArgumentException(T("The folder could not be created at path: {0}. {1}", path, ex).ToString()); } } diff --git a/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathProvider.cs b/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathProvider.cs index 85a295d1b..4c2941e91 100644 --- a/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathProvider.cs +++ b/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathProvider.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Web; using System.Web.Hosting; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.FileSystems.VirtualPath { public class DefaultVirtualPathProvider : IVirtualPathProvider { @@ -59,9 +60,12 @@ namespace Orchard.FileSystems.VirtualPath { } return result; } - catch (Exception e) { + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } // The initial path might have been invalid (e.g. path indicates a path outside the application root) - Logger.Information(e, "Path '{0}' cannot be made app relative", virtualPath); + Logger.Information(ex, "Path '{0}' cannot be made app relative", virtualPath); return null; } } @@ -156,8 +160,11 @@ namespace Orchard.FileSystems.VirtualPath { try { return FileExists(virtualPath); } - catch (Exception e) { - Logger.Information(e, "File '{0}' can not be checked for existence. Assuming doesn't exist.", virtualPath); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Information(ex, "File '{0}' can not be checked for existence. Assuming doesn't exist.", virtualPath); return false; } } diff --git a/src/Orchard/Messaging/Services/DefaultMessageManager.cs b/src/Orchard/Messaging/Services/DefaultMessageManager.cs index 8e2911857..1495f9e37 100644 --- a/src/Orchard/Messaging/Services/DefaultMessageManager.cs +++ b/src/Orchard/Messaging/Services/DefaultMessageManager.cs @@ -5,6 +5,7 @@ using Orchard.Logging; using Orchard.Messaging.Events; using Orchard.Messaging.Models; using Orchard.ContentManagement.Records; +using Orchard.Exceptions; namespace Orchard.Messaging.Services { [Obsolete] @@ -40,8 +41,11 @@ namespace Orchard.Messaging.Services { PrepareAndSend(type, properties, context); } - catch ( Exception e ) { - Logger.Error(e, "An error occured while sending the message {0}", type); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "An error occured while sending the message {0}", type); } } @@ -60,8 +64,11 @@ namespace Orchard.Messaging.Services { PrepareAndSend(type, properties, context); } - catch (Exception e) { - Logger.Error(e, "An error occured while sending the message {0}", type); + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "An error occured while sending the message {0}", type); } } diff --git a/src/Orchard/Mvc/MvcModule.cs b/src/Orchard/Mvc/MvcModule.cs index 4125c4706..33cc7176d 100644 --- a/src/Orchard/Mvc/MvcModule.cs +++ b/src/Orchard/Mvc/MvcModule.cs @@ -11,6 +11,7 @@ using System.Web.Routing; using Autofac; using Orchard.Mvc.Routes; using Orchard.Settings; +using Orchard.Exceptions; namespace Orchard.Mvc { public class MvcModule : Module { @@ -31,7 +32,11 @@ namespace Orchard.Mvc { // The "Request" property throws at application startup on IIS integrated pipeline mode. var req = HttpContext.Current.Request; } - catch (Exception) { + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + return false; } diff --git a/src/Orchard/Tasks/BackgroundService.cs b/src/Orchard/Tasks/BackgroundService.cs index d796a2d0d..36d55b252 100644 --- a/src/Orchard/Tasks/BackgroundService.cs +++ b/src/Orchard/Tasks/BackgroundService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Orchard.Data; using Orchard.Environment.Configuration; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Tasks { @@ -39,9 +40,13 @@ namespace Orchard.Tasks { task.Sweep(); Logger.Information("Finished processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName); } - catch (Exception e) { + catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + _transactionManager.Cancel(); - Logger.Error(e, "Error while processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName); + Logger.Error(ex, "Error while processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName); } } } diff --git a/src/Orchard/Tasks/SweepGenerator.cs b/src/Orchard/Tasks/SweepGenerator.cs index feb8a3f0e..44429e50b 100644 --- a/src/Orchard/Tasks/SweepGenerator.cs +++ b/src/Orchard/Tasks/SweepGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Timers; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Tasks { @@ -51,6 +52,10 @@ namespace Orchard.Tasks { } } catch (Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Warning(ex, "Problem in background tasks"); } finally { diff --git a/src/Orchard/Time/SiteTimeZoneSelector.cs b/src/Orchard/Time/SiteTimeZoneSelector.cs index 28068b213..366718216 100644 --- a/src/Orchard/Time/SiteTimeZoneSelector.cs +++ b/src/Orchard/Time/SiteTimeZoneSelector.cs @@ -1,6 +1,7 @@ using System; using System.Web; using Orchard.Logging; +using Orchard.Exceptions; namespace Orchard.Time { /// @@ -31,8 +32,11 @@ namespace Orchard.Time { TimeZone = TimeZoneInfo.FindSystemTimeZoneById(siteTimeZoneId) }; } - catch(Exception e) { - Logger.Error(e, "TimeZone could not be loaded"); + catch(Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error(ex, "TimeZone could not be loaded"); // if the database could not be updated in time, ignore this provider return null; diff --git a/src/Orchard/UI/Admin/Notification/NotificationManager.cs b/src/Orchard/UI/Admin/Notification/NotificationManager.cs index 327b4f1c1..d0529224c 100644 --- a/src/Orchard/UI/Admin/Notification/NotificationManager.cs +++ b/src/Orchard/UI/Admin/Notification/NotificationManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Orchard.Logging; using Orchard.UI.Notify; +using Orchard.Exceptions; namespace Orchard.UI.Admin.Notification { public class NotificationManager : INotificationManager { @@ -22,8 +23,11 @@ namespace Orchard.UI.Admin.Notification { try { return n.GetNotifications(); } - catch(Exception e) { - Logger.Error("An unhandled exception was thrown while generating a notification: " + n.GetType(), e); + catch(Exception ex) { + if (ex.IsFatal()) { + throw; + } + Logger.Error("An unhandled exception was thrown while generating a notification: " + n.GetType(), ex); return Enumerable.Empty(); } }).ToList(); From 9947f3973e73b54bbd77d6e10c8afd31590aa1a6 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Fri, 24 Jul 2015 17:32:59 +0200 Subject: [PATCH 15/33] Add new Chain method for tokens The new method allows working with parameterized tokens. --- .../Modules/Orchard.Tokens/EvaluateFor.cs | 1 + .../Implementation/TokenManager.cs | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/EvaluateFor.cs b/src/Orchard.Web/Modules/Orchard.Tokens/EvaluateFor.cs index 39bda24bc..70438592c 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/EvaluateFor.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/EvaluateFor.cs @@ -7,5 +7,6 @@ namespace Orchard.Tokens { public abstract EvaluateFor Chain(string token, string chainTarget, Func chainValue); public abstract EvaluateFor Token(Func tokenValue); public abstract EvaluateFor Token(Func filter, Func tokenValue); + public abstract EvaluateFor Chain(Func> filter, string chainTarget, Func chainValue); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Implementation/TokenManager.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Implementation/TokenManager.cs index b87d6f353..c0a967914 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Implementation/TokenManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Implementation/TokenManager.cs @@ -153,6 +153,27 @@ namespace Orchard.Tokens.Implementation { } return this; } + + public override EvaluateFor Chain(Func> filter, string chainTarget, Func chainValue) { + var subTokens = _context.Tokens + .Where(kv => kv.Key.Contains('.')) + .Select(kv => { + var filterResult = filter(kv.Key); + return filterResult != null ? new Tuple(filterResult.Item1, filterResult.Item2, kv.Value) : null; + }) + .Where(st => st != null) + .ToList(); + if (!subTokens.Any()) { + return this; + } + foreach(var chainGroup in subTokens.GroupBy(st => st.Item1)) { + var subValues = _context._manager.Evaluate(chainTarget, chainGroup.ToDictionary(cg => cg.Item2, cg => cg.Item3), new Dictionary { { chainTarget, chainValue(chainGroup.Key, _data) } }); + foreach (var subValue in subValues) { + _context.Values[subValue.Key] = subValue.Value; + } + } + return this; + } } private class EvaluateForSilent : EvaluateFor { @@ -175,6 +196,10 @@ namespace Orchard.Tokens.Implementation { public override EvaluateFor Chain(string token, string chainTarget, Func chainValue) { return this; } + + public override EvaluateFor Chain(Func> filter, string chainTarget, Func chainValue) { + return this; + } } } From 75f3a618f08d5d01ebafd43d1a4fd39cb7e3ccee Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Fri, 24 Jul 2015 17:35:41 +0200 Subject: [PATCH 16/33] Enhances TaxonomyField's token chaining. --- .../Tokens/TaxonomyTokens.cs | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Tokens/TaxonomyTokens.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Tokens/TaxonomyTokens.cs index 3b2a9edc2..e921232ed 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Tokens/TaxonomyTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Tokens/TaxonomyTokens.cs @@ -31,21 +31,33 @@ namespace Orchard.Taxonomies.Tokens { context.For("TaxonomyField") .Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray())) - .Token( - token => { - var index = 0; - return (token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) && int.TryParse(token.Substring("Terms:".Length), out index)) ? index.ToString() : null; - }, - (token, t) => { - var index = Convert.ToInt32(token); - return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name; + .Token(FilterTokenParam, + (index, field) => { + var term = field.Terms.ElementAtOrDefault(Convert.ToInt32(index)); + return term != null ? term.Name : null; }) - // todo: extend Chain() in order to accept a filter like in Token() so that we can chain on an expression - .Chain("Terms:0", "Content", t => t.Terms.ElementAt(0)) - .Chain("Terms:1", "Content", t => t.Terms.ElementAt(1)) - .Chain("Terms:2", "Content", t => t.Terms.ElementAt(2)) - .Chain("Terms:3", "Content", t => t.Terms.ElementAt(3)) + .Chain(FilterChainParam, "Content", (index, field) => field.Terms.ElementAtOrDefault(Convert.ToInt32(index))) ; } + + private static string FilterTokenParam(string token) { + int index = 0; + return (token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) && int.TryParse(token.Substring("Terms:".Length), out index)) ? index.ToString() : null; + } + + private static Tuple FilterChainParam(string token) { + int tokenLength = "Terms:".Length; + int index = 0; + int chainIndex = token.IndexOf('.'); + if (!token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) + return null; + + if (int.TryParse(token.Substring(tokenLength, chainIndex - tokenLength), out index)) { + return new Tuple(index.ToString(), token.Substring(chainIndex + 1)); + } + else { + return null; + } + } } } \ No newline at end of file From 25c34d8bcae5b83c86793a7c4011a35fd9d8cdba Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Fri, 24 Jul 2015 17:39:10 +0200 Subject: [PATCH 17/33] Fixes #5563 : Allow token chaining on DynamicForms submissions. --- .../Orchard.DynamicForms/Tokens/FormTokens.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs index e26cb2626..68fbdb5c4 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Tokens/FormTokens.cs @@ -7,7 +7,7 @@ namespace Orchard.DynamicForms.Tokens { public void Describe(DescribeContext context) { context.For("FormSubmission", T("Dynamic Form submission"), T("Dynamic Form Submission tokens for use in workflows handling the Dynamic Form Submitted event.")) - .Token("Field:*", T("Field:"), T("The posted field value to access.")) + .Token("Field:*", T("Field:"), T("The posted field value to access."), "Text") .Token("IsValid:*", T("IsValid:"), T("The posted field validation status.")) ; } @@ -15,10 +15,20 @@ namespace Orchard.DynamicForms.Tokens { public void Evaluate(EvaluateContext context) { context.For("FormSubmission") .Token(token => token.StartsWith("Field:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Field:".Length) : null, GetFieldValue) + .Chain(FilterChainParam, "Text", GetFieldValue) .Token(token => token.StartsWith("IsValid:", StringComparison.OrdinalIgnoreCase) ? token.Substring("IsValid:".Length) : null, GetFieldValidationStatus); } - private object GetFieldValue(string fieldName, FormSubmissionTokenContext context) { + private static Tuple FilterChainParam(string token) { + int tokenLength = "Field:".Length; + int chainIndex = token.IndexOf('.'); + if (token.StartsWith("Field:", StringComparison.OrdinalIgnoreCase) && chainIndex > tokenLength) + return new Tuple(token.Substring(tokenLength, chainIndex - tokenLength), token.Substring(chainIndex + 1)); + else + return null; + } + + private string GetFieldValue(string fieldName, FormSubmissionTokenContext context) { return context.PostedValues[fieldName]; } From 67e7d1074e9a91984577fc2d50d9bb12e0eab9d9 Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Fri, 24 Jul 2015 17:42:07 +0200 Subject: [PATCH 18/33] Allow Text token chaining when possible. Correct some errors on token descriptions. --- .../Orchard.Tokens/Providers/ContentTokens.cs | 2 +- .../Orchard.Tokens/Providers/TextTokens.cs | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs index 257394d88..6e6dad645 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/ContentTokens.cs @@ -36,7 +36,7 @@ namespace Orchard.Tokens.Providers { .Token("DisplayUrl", T("Display Url"), T("Url to display the content."), "Url") .Token("EditUrl", T("Edit Url"), T("Url to edit the content."), "Url") .Token("Container", T("Container"), T("The container Content Item."), "Content") - .Token("Body", T("Body"), T("The body text of the content item."), "Content") + .Token("Body", T("Body"), T("The body text of the content item."), "Text") ; // Token descriptors for fields diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs index 89f77c018..045d67e09 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs @@ -13,38 +13,42 @@ namespace Orchard.Tokens.Providers { public void Describe(DescribeContext context) { context.For("Text", T("Text"), T("Tokens for text strings")) .Token("Limit:*", T("Limit:[,]"), T("Limit text to specified length and append an optional ellipsis text.")) - .Token("Format:*", T("Format:"), T("Optional format specifier (e.g. foo{0}bar). See format strings at Standard Formats and Custom Formats"), "DateTime") - .Token("TrimEnd:*", T("TrimEnd:"), T("Trims the specified characters or number of them from the end of the string."), "Text") + .Token("Format:*", T("Format:"), T("Optional format specifier (e.g. foo{0}bar).")) + .Token("TrimEnd:*", T("TrimEnd:"), T("Trims the specified characters or number of them from the end of the string.")) .Token("UrlEncode", T("Url Encode"), T("Encodes a URL string."), "Text") .Token("HtmlEncode", T("Html Encode"), T("Encodes an HTML string."), "Text") - .Token("LineEncode", T("Line Encode"), T("Replaces new lines with
tags.")) + .Token("LineEncode", T("Line Encode"), T("Replaces new lines with
tags."), "Text") ; } public void Evaluate(EvaluateContext context) { context.For("Text", () => "") - .Token( // {Text} + // {Text} + .Token( token => token == String.Empty ? String.Empty : null, (token, d) => d.ToString()) - .Token( // {Text.Limit:[,]} - token => { - if (token.StartsWith("Limit:", StringComparison.OrdinalIgnoreCase)) { - var param = token.Substring("Limit:".Length); - return param; - } - return null; - }, + // {Text.Limit:[,]} + .Token( + token => FilterTokenParam("Limit:", token), (token, t) => Limit(t, token)) // {Text.Format:} .Token( - token => token.StartsWith("Format:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Format:".Length) : null, - (token, d) => String.Format(d,token)) - .Token(token => token.StartsWith("TrimEnd:", StringComparison.OrdinalIgnoreCase) ? token.Substring("TrimEnd:".Length) : null, TrimEnd) + token => FilterTokenParam("Format:", token), + (token, d) => String.Format(d, token)) + // {Text.TrimEnd:} + .Token(token => FilterTokenParam("TrimEnd:", token), TrimEnd) .Token("UrlEncode", HttpUtility.UrlEncode) + .Chain("UrlEncode", "Text", HttpUtility.UrlEncode) .Token("HtmlEncode", HttpUtility.HtmlEncode) + .Chain("HtmlEncode", "Text", HttpUtility.HtmlEncode) .Token("LineEncode", text => text.Replace(System.Environment.NewLine, "
")) + .Chain("LineEncode", "Text", text => text.Replace(System.Environment.NewLine, "
")) ; - + + } + + private static string FilterTokenParam(string tokenName, string token) { + return token.StartsWith(tokenName, StringComparison.OrdinalIgnoreCase) ? token.Substring(tokenName.Length) : null; } private static string TrimEnd(string token, string param) { From 371238a882ed1423f66621ff2e6ea59f6149935d Mon Sep 17 00:00:00 2001 From: Thierry Fleury Date: Mon, 7 Sep 2015 15:14:20 +0200 Subject: [PATCH 19/33] Add parameterized tokens tests --- .../Orchard.Tokens/Tests/TestTokenProvider.cs | 28 +++++++++++++++++++ .../Orchard.Tokens/Tests/TokenizerTests.cs | 12 ++++++++ 2 files changed, 40 insertions(+) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TestTokenProvider.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TestTokenProvider.cs index 105f705d4..c65b76a65 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TestTokenProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TestTokenProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Orchard.ContentManagement; using Orchard.Localization; using Orchard.Security; @@ -24,6 +25,9 @@ namespace Orchard.Tokens.Tests { context.For("Date") .Token("Now", T("Now"), T("Current system date in short date format. You can chain a .NET DateTime format string to customize.")); + + context.For("Users") + .Token("Users[*:]", T("Users"), T("A user by its username"), "User"); } public void Evaluate(EvaluateContext context) { @@ -36,6 +40,7 @@ namespace Orchard.Tokens.Tests { context.For("User", () => new TestUser { UserName = "CurrentUser" }) .Token("Name", u => u.UserName) + .Token("Email", u => u.Email) .Token("Birthdate", u => "Nov 15") .Chain("Birthdate", "DateTime", u => new DateTime(1978, 11, 15)); @@ -45,6 +50,29 @@ namespace Orchard.Tokens.Tests { context.For("DateTime") .Token((token, value) => value.ToString(token)); + + context.For("Users", () => new TestUser[] { + new TestUser { UserName = "User1", Email = "user1@test.com" }, + new TestUser { UserName = "User2", Email = "user2@test.com" }, + new TestUser { UserName = "User3", Email = "user3@test.com" } + }) + .Token( + (token) => token.StartsWith("User:", StringComparison.OrdinalIgnoreCase) ? token.Substring("User:".Length) : null, + (userName, users) => users.Where(u => u.UserName == userName).Select(u => u.UserName).FirstOrDefault() + ) + .Chain( + (token) => { + int tokenLength = "User:".Length; + int chainIndex = token.IndexOf('.'); + if (token.StartsWith("User:", StringComparison.OrdinalIgnoreCase) && chainIndex > tokenLength) + return new Tuple(token.Substring(tokenLength, chainIndex - tokenLength), token.Substring(chainIndex + 1)); + else + return null; + }, + "User", + (userName, users) => users.Where(u => u.UserName == userName).FirstOrDefault() + ); + } } diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenizerTests.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenizerTests.cs index 999c3d87b..8c976f8d0 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenizerTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenizerTests.cs @@ -40,6 +40,18 @@ namespace Orchard.Tokens.Tests { Assert.That(_tokenizer.Replace("{Site.CurrentUser.Birthdate.yyyy}", null), Is.EqualTo("1978")); } + [Test] + public void TestParameterizedTokens() { + Assert.That(_tokenizer.Replace("{Users.User:User2}", null), Is.EqualTo("User2")); + Assert.That(_tokenizer.Replace("{Users.User:FakeUser}", null), Is.EqualTo("")); + } + + [Test] + public void TestParameterizedChainedTokens() { + Assert.That(_tokenizer.Replace("{Users.User:User2.Email}", null), Is.EqualTo("user2@test.com")); + Assert.That(_tokenizer.Replace("{Users.User:FakeUser.Email}", null), Is.EqualTo("")); + } + [Test] public void TestMissingTokens() { Assert.That(_tokenizer.Replace("[{Site.NotAToken}]", null), Is.EqualTo("[]")); From 2a0f866f26eb0f9a86abd5648f5aece66054e4f4 Mon Sep 17 00:00:00 2001 From: Lombiq Date: Tue, 8 Sep 2015 01:01:23 +0200 Subject: [PATCH 20/33] Fixing exception when importing Projection Elements with the default layout selected Fixed the export of this previously, this was remaining. --- .../Modules/Orchard.Layouts/Drivers/ProjectionElementDriver.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ProjectionElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ProjectionElementDriver.cs index d5d455290..68c7efe4d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ProjectionElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ProjectionElementDriver.cs @@ -307,10 +307,9 @@ namespace Orchard.Layouts.Drivers { var queryPart = query.As(); var layoutIndex = XmlHelper.Parse(context.ExportableData.Get("LayoutIndex")); - var layout = queryPart.Layouts[layoutIndex]; element.QueryId = queryPart.Id; - element.LayoutId = layout.Id; + element.LayoutId = layoutIndex != -1 ? queryPart.Layouts[layoutIndex].Id : -1; } private static string GetLayoutDescription(IEnumerable layouts, LayoutRecord l) { From 9bac35b3f1735da01609ac769ce48f50bff624cd Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 09:12:26 -0700 Subject: [PATCH 21/33] Removing duplicated using --- src/Orchard/Events/DefaultOrchardEventBus.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Orchard/Events/DefaultOrchardEventBus.cs b/src/Orchard/Events/DefaultOrchardEventBus.cs index adcab90d4..2a5faf49e 100644 --- a/src/Orchard/Events/DefaultOrchardEventBus.cs +++ b/src/Orchard/Events/DefaultOrchardEventBus.cs @@ -7,7 +7,6 @@ using System.Reflection; using Autofac.Features.Indexed; using Orchard.Exceptions; using Orchard.Localization; -using Orchard.Exceptions; namespace Orchard.Events { public class DefaultOrchardEventBus : IEventBus { From c4592aa65fd386d90f60e2dc6dc1fb84d5e491f0 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 09:27:36 -0700 Subject: [PATCH 22/33] Selecting the layer "Default" on the widgets start screen Fixes a specflow bug which expect "Default" to be the default selected layer. Appeared since layers are ordered alphabetically. --- .../Modules/Orchard.Widgets/Controllers/AdminController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs index 7daa44705..9c7fa0a0b 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs @@ -69,7 +69,7 @@ namespace Orchard.Widgets.Controllers { } LayerPart currentLayer = layerId == null - ? layers.FirstOrDefault() + ? layers.FirstOrDefault(x => x.Name == "Default") : layers.FirstOrDefault(layer => layer.Id == layerId); if (currentLayer == null && layerId != null) { // Incorrect layer id passed From 2bb7eb2f91f6cc44972d841818d61ba6f385c5cf Mon Sep 17 00:00:00 2001 From: Jamie Phillips Date: Tue, 8 Sep 2015 13:06:04 -0400 Subject: [PATCH 23/33] Updating DynamicForms Module.txt The CustomForms module name and website were listed. --- src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt b/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt index 7000b659c..8b8cb0e99 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt @@ -1,7 +1,7 @@ -Name: Custom Forms +Name: Dynamic Forms AntiForgery: enabled Author: The Orchard Team -Website: http://orchardcustomforms.codeplex.com +Website: http://www.orchardproject.net/ Version: 1.9.1 OrchardVersion: 1.9 Description: Create custom forms like contact forms using layouts. From e9f883c296ba9734210827844b9bcd466e3a0430 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Tue, 8 Sep 2015 20:56:28 +0100 Subject: [PATCH 24/33] Removed unnecessary call to DistributedLockSchemaBuilder. Also added code to commit the transaction if the schema was created so that it can be used in the same request (DataMigrationManager is doing the same after each migration). --- .../Modules/Orchard.Setup/Services/SetupService.cs | 5 ----- src/Orchard/Data/Migration/AutomaticDataMigrations.cs | 6 +++++- .../Tasks/Locking/Services/DistributedLockSchemaBuilder.cs | 5 +++-- .../Tasks/Locking/Services/DistributedLockService.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index dfff5b008..16b3e465b 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -23,7 +23,6 @@ using Orchard.Recipes.Models; using Orchard.Recipes.Services; using Orchard.Security; using Orchard.Settings; -using Orchard.Tasks.Locking.Services; using Orchard.Utility.Extensions; namespace Orchard.Setup.Services { @@ -155,10 +154,6 @@ namespace Orchard.Setup.Services { schemaBuilder.AlterTable("Orchard_Framework_DataMigrationRecord", table => table.AddUniqueConstraint("UC_DMR_DataMigrationClass_Version", "DataMigrationClass", "Version")); - // Create the distributed lock record schema. - var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder); - distributedLockSchemaBuilder.CreateSchema(); - var dataMigrationManager = environment.Resolve(); dataMigrationManager.Update("Settings"); diff --git a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs index 088903a06..ba6462cd1 100644 --- a/src/Orchard/Data/Migration/AutomaticDataMigrations.cs +++ b/src/Orchard/Data/Migration/AutomaticDataMigrations.cs @@ -18,18 +18,21 @@ namespace Orchard.Data.Migration { private readonly IDistributedLockService _distributedLockService; private readonly IDataMigrationInterpreter _dataMigrationInterpreter; private readonly ShellSettings _shellSettings; + private readonly ITransactionManager _transactionManager; public AutomaticDataMigrations( IDataMigrationManager dataMigrationManager, IDataMigrationInterpreter dataMigrationInterpreter, IFeatureManager featureManager, IDistributedLockService distributedLockService, + ITransactionManager transactionManager, ShellSettings shellSettings) { _dataMigrationManager = dataMigrationManager; _featureManager = featureManager; _distributedLockService = distributedLockService; _shellSettings = shellSettings; + _transactionManager = transactionManager; _dataMigrationInterpreter = dataMigrationInterpreter; Logger = NullLogger.Instance; @@ -77,7 +80,8 @@ namespace Orchard.Data.Migration { // Ensure the distributed lock record schema exists. var schemaBuilder = new SchemaBuilder(_dataMigrationInterpreter); var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder); - distributedLockSchemaBuilder.EnsureSchema(); + if (distributedLockSchemaBuilder.EnsureSchema()) + _transactionManager.RequireNew(); } } } diff --git a/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs b/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs index 8a577d8a1..2f22f1220 100644 --- a/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs +++ b/src/Orchard/Tasks/Locking/Services/DistributedLockSchemaBuilder.cs @@ -13,11 +13,12 @@ namespace Orchard.Tasks.Locking.Services { _schemaBuilder = schemaBuilder; } - public void EnsureSchema() { + public bool EnsureSchema() { if (SchemaExists()) - return; + return false; CreateSchema(); + return true; } public void CreateSchema() { diff --git a/src/Orchard/Tasks/Locking/Services/DistributedLockService.cs b/src/Orchard/Tasks/Locking/Services/DistributedLockService.cs index 34ab4332f..05c87b41f 100644 --- a/src/Orchard/Tasks/Locking/Services/DistributedLockService.cs +++ b/src/Orchard/Tasks/Locking/Services/DistributedLockService.cs @@ -110,7 +110,7 @@ namespace Orchard.Tasks.Locking.Services { ); }); - return result; + return result; } private DistributedLock AcquireLockInternal(string name, TimeSpan? maxValidFor) { From 691809cd8583fc6c3414b5ae948f66c83605a096 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 15:39:19 -0700 Subject: [PATCH 25/33] [Fixes #5733] Update default Layout state settings --- .../Orchard.DynamicForms/Migrations.cs | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Migrations.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Migrations.cs index 3aa00e1f9..04fbe114f 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Migrations.cs @@ -1,10 +1,15 @@ using System; +using System.Linq; +using System.Security.Cryptography; using Orchard.ContentManagement.MetaData; using Orchard.Core.Contents.Extensions; +using Orchard.Data; using Orchard.Data.Migration; namespace Orchard.DynamicForms { public class Migrations : DataMigrationImpl { + private readonly byte[] _oldLayoutHash = new byte[] { 0x91, 0x10, 0x3b, 0x97, 0xce, 0x1e, 0x1e, 0xc7, 0x7a, 0x41, 0xf7, 0x82, 0xe8, 0x58, 0x85, 0x91 }; + private const string DefaultFormLayoutData = @"{ ""elements"": [ @@ -59,7 +64,52 @@ namespace Orchard.DynamicForms { .WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData)) .WithSetting("Stereotype", "Widget") .DisplayedAs("Form Widget")); - return 1; + return 2; + } + + public int UpdateFrom1() { + // if the default layout data was unchanged, fix it with the new default + + var formLayoutPart = ContentDefinitionManager + .GetTypeDefinition("Form") + .Parts + .FirstOrDefault(x => x.PartDefinition.Name == "LayoutPart"); + + if (formLayoutPart != null && + formLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"] != null) { + var layout = formLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"]; + + if(GetMD5(layout) == _oldLayoutHash) { + ContentDefinitionManager.AlterTypeDefinition("Form", type => type + .WithPart("LayoutPart", p => p + .WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData)) + ); + } + } + + var formWidgetLayoutPart = ContentDefinitionManager + .GetTypeDefinition("FormWidget") + .Parts + .FirstOrDefault(x => x.PartDefinition.Name == "LayoutPart"); + + if (formWidgetLayoutPart != null && + formWidgetLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"] != null) { + var layout = formWidgetLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"]; + + if (GetMD5(layout) == _oldLayoutHash) { + ContentDefinitionManager.AlterTypeDefinition("FormWidget", type => type + .WithPart("LayoutPart", p => p + .WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData)) + ); + } + } + + return 2; + } + + private byte[] GetMD5(string text) { + byte[] encodedText = System.Text.Encoding.UTF8.GetBytes(text); + return ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedText); } } } \ No newline at end of file From 06bf56977410e8c4ed1dedb904ce7dc4c7ff4e6c Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 16:05:13 -0700 Subject: [PATCH 26/33] Fixing compilation issue on CI --- src/Orchard.Tests/Stubs/StubWorkContextScope.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Orchard.Tests/Stubs/StubWorkContextScope.cs b/src/Orchard.Tests/Stubs/StubWorkContextScope.cs index f8fb42041..a63c75957 100644 --- a/src/Orchard.Tests/Stubs/StubWorkContextScope.cs +++ b/src/Orchard.Tests/Stubs/StubWorkContextScope.cs @@ -9,7 +9,7 @@ namespace Orchard.Tests.Stubs { WorkContext = workContext; } - public WorkContext WorkContext { get; } + public WorkContext WorkContext { get; private set; } public void Dispose() { _lifetimeScope.Dispose(); From 2f2134412e85ca4aab6da507f71558e0d1c29d36 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 16:13:55 -0700 Subject: [PATCH 27/33] [Fixes #5492] Adding JavaScriptEncode token --- src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs index 045d67e09..255cee809 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Providers/TextTokens.cs @@ -17,6 +17,7 @@ namespace Orchard.Tokens.Providers { .Token("TrimEnd:*", T("TrimEnd:"), T("Trims the specified characters or number of them from the end of the string.")) .Token("UrlEncode", T("Url Encode"), T("Encodes a URL string."), "Text") .Token("HtmlEncode", T("Html Encode"), T("Encodes an HTML string."), "Text") + .Token("JavaScriptEncode", T("JavaScript Encode"), T("Encodes a JavaScript string."), "Text") .Token("LineEncode", T("Line Encode"), T("Replaces new lines with
tags."), "Text") ; } @@ -41,6 +42,8 @@ namespace Orchard.Tokens.Providers { .Chain("UrlEncode", "Text", HttpUtility.UrlEncode) .Token("HtmlEncode", HttpUtility.HtmlEncode) .Chain("HtmlEncode", "Text", HttpUtility.HtmlEncode) + .Token("JavaScriptEncode", HttpUtility.JavaScriptStringEncode) + .Chain("JavaScriptEncode", "Text", HttpUtility.JavaScriptStringEncode) .Token("LineEncode", text => text.Replace(System.Environment.NewLine, "
")) .Chain("LineEncode", "Text", text => text.Replace(System.Environment.NewLine, "
")) ; From c83f5d88cbdd1e1b4f603d2e5554f012a9f5e16b Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 17:04:45 -0700 Subject: [PATCH 28/33] Supporting lazy cache manager resolution --- src/Orchard.Tests/Caching/CacheTests.cs | 38 +++++++++++++++++++ .../Metadata/ContentDefinitionManager.cs | 6 +-- .../Core/Settings/Services/SiteService.cs | 2 +- .../Services/StereotypeService.cs | 2 +- .../Services/ElementManager.cs | 4 +- .../ImageProcessingFileNameProvider.cs | 2 +- .../Services/ImageProfileService.cs | 2 +- .../Filters/OutputCacheFilter.cs | 2 +- .../Services/CacheService.cs | 2 +- .../Services/RubyScriptExpressionEvaluator.cs | 4 +- .../ScriptExpressionEvaluator.cs | 2 +- .../Orchard.Tags/Services/TagCloudService.cs | 2 +- .../Services/TemplateShapeBindingResolver.cs | 2 +- src/Orchard/Caching/ICacheManager.cs | 13 +++++++ .../DefaultContentManager.cs | 2 +- .../ContentManagement/DefaultContentQuery.cs | 2 +- .../Descriptors/DefaultShapeTableManager.cs | 2 +- .../PlacementFileParser.cs | 2 +- .../ShapeTemplateBindingStrategy.cs | 2 +- .../Compilers/DefaultProjectFileParser.cs | 2 +- .../Extensions/ExtensionManager.cs | 8 ++-- .../Extensions/Folders/ExtensionHarvester.cs | 4 +- .../Environment/IAssemblyNameResolver.cs | 2 +- .../Dependencies/DefaultDependenciesFolder.cs | 2 +- .../DefaultExtensionDependenciesManager.cs | 2 +- .../Services/DefaultCultureManager.cs | 2 +- .../Services/DefaultLocalizedStringManager.cs | 2 +- 27 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/Orchard.Tests/Caching/CacheTests.cs b/src/Orchard.Tests/Caching/CacheTests.cs index 13af703fb..0201d3b26 100644 --- a/src/Orchard.Tests/Caching/CacheTests.cs +++ b/src/Orchard.Tests/Caching/CacheTests.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Threading; using Autofac; using NUnit.Framework; using Orchard.Caching; @@ -78,6 +80,42 @@ namespace Orchard.Tests.Caching { Is.Not.SameAs(c2.CacheManager.GetCache())); } + [Test] + public void CacheManagerIsNotBlocking() { + var hits = 0; + string result = ""; + + Enumerable.Range(0, 5).AsParallel().ForAll(x => + result = _cacheManager.Get("testItem", ctx => { + // by waiting for 100ms we expect all the calls to Get + // to enter this lambda + Thread.Sleep(100); + hits++; + return "testResult"; + }) + ); + + Assert.That(result, Is.EqualTo("testResult")); + Assert.That(hits, Is.GreaterThan(1)); + } + + [Test] + public void CacheManagerIsBlocking() { + var hits = 0; + string result = ""; + + Enumerable.Range(0, 5).AsParallel().ForAll(x => + result = _cacheManager.Get("testItem", true, ctx => { + Thread.Sleep(100); + hits++; + return "testResult"; + }) + ); + + Assert.That(result, Is.EqualTo("testResult")); + Assert.That(hits, Is.EqualTo(1)); + } + class ComponentOne { public ICacheManager CacheManager { get; set; } diff --git a/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs b/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs index 16c1d1f78..3ebb1b4ed 100644 --- a/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs +++ b/src/Orchard.Web/Core/Settings/Metadata/ContentDefinitionManager.cs @@ -125,7 +125,7 @@ namespace Orchard.Core.Settings.Metadata { } private IDictionary AcquireContentTypeDefinitions() { - return _cacheManager.Get("ContentTypeDefinitions", ctx => { + return _cacheManager.Get("ContentTypeDefinitions", true, ctx => { MonitorContentDefinitionSignal(ctx); AcquireContentPartDefinitions(); @@ -140,7 +140,7 @@ namespace Orchard.Core.Settings.Metadata { } private IDictionary AcquireContentPartDefinitions() { - return _cacheManager.Get("ContentPartDefinitions", ctx => { + return _cacheManager.Get("ContentPartDefinitions", true, ctx => { MonitorContentDefinitionSignal(ctx); var contentPartDefinitionRecords = _partDefinitionRepository.Table @@ -153,7 +153,7 @@ namespace Orchard.Core.Settings.Metadata { } private IDictionary AcquireContentFieldDefinitions() { - return _cacheManager.Get("ContentFieldDefinitions", ctx => { + return _cacheManager.Get("ContentFieldDefinitions", true, ctx => { MonitorContentDefinitionSignal(ctx); return _fieldDefinitionRepository.Table.Select(Build).ToDictionary(x => x.Name, y => y); diff --git a/src/Orchard.Web/Core/Settings/Services/SiteService.cs b/src/Orchard.Web/Core/Settings/Services/SiteService.cs index b83f23caa..721a3f619 100644 --- a/src/Orchard.Web/Core/Settings/Services/SiteService.cs +++ b/src/Orchard.Web/Core/Settings/Services/SiteService.cs @@ -24,7 +24,7 @@ namespace Orchard.Core.Settings.Services { public ILogger Logger { get; set; } public ISite GetSiteSettings() { - var siteId = _cacheManager.Get("SiteId", ctx => { + var siteId = _cacheManager.Get("SiteId", true, ctx => { var site = _contentManager.Query("Site") .List() .FirstOrDefault(); diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/StereotypeService.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/StereotypeService.cs index c00221328..4b4e8471a 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/StereotypeService.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/StereotypeService.cs @@ -22,7 +22,7 @@ namespace Orchard.ContentTypes.Services { } public IEnumerable GetStereotypes() { - return _cacheManager.Get("ContentType.Stereotypes", context => { + return _cacheManager.Get("ContentType.Stereotypes", true, context => { // TODO: Implement a signal in ContentDefinitionManager that gets raised whenever a type definition is updated. // For now, we'll just cache the stereotypes for 1 minute. diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs index fd5b94c8a..9bcb5075b 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementManager.cs @@ -38,7 +38,7 @@ namespace Orchard.Layouts.Services { public IEnumerable DescribeElements(DescribeElementsContext context) { var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string); var cacheKey = String.Format("LayoutElementTypes-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam); - return _cacheManager.Get(cacheKey, acquireContext => { + return _cacheManager.Get(cacheKey, true, acquireContext => { var harvesterContext = new HarvestElementsContext { Content = context.Content }; @@ -55,7 +55,7 @@ namespace Orchard.Layouts.Services { public IEnumerable GetCategories(DescribeElementsContext context) { var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string); - return _cacheManager.Get(String.Format("ElementCategories-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam), acquireContext => { + return _cacheManager.Get(String.Format("ElementCategories-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam), true, acquireContext => { var elements = DescribeElements(context); var categoryDictionary = GetCategories(); var categoryDescriptorDictionary = new Dictionary(); diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs index f8a7cf19a..340c2031d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProcessingFileNameProvider.cs @@ -58,7 +58,7 @@ namespace Orchard.MediaProcessing.Services { } private IDictionary GetProfileCache(string profile) { - return _cacheManager.Get("MediaProcessing_" + profile, ctx => { + return _cacheManager.Get("MediaProcessing_" + profile, true, ctx => { ctx.Monitor(_signals.When("MediaProcessing_Saved_" + profile)); var dictionary = new Dictionary(); diff --git a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs index c002f657f..3a3a982fa 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaProcessing/Services/ImageProfileService.cs @@ -32,7 +32,7 @@ namespace Orchard.MediaProcessing.Services { public ImageProfilePart GetImageProfileByName(string name) { - var profileId = _cacheManager.Get("ProfileId_" + name, ctx => { + var profileId = _cacheManager.Get("ProfileId_" + name, true, ctx => { var profile = _contentManager.Query() .Where(x => x.Name == name) .Slice(0, 1) diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs index ac35578ee..adc63a0e1 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Filters/OutputCacheFilter.cs @@ -461,7 +461,7 @@ namespace Orchard.OutputCache.Filters { private CacheSettings CacheSettings { get { - return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, context => { + return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, true, context => { context.Monitor(_signals.When(CacheSettings.CacheKey)); return new CacheSettings(_workContext.CurrentSite.As()); })); diff --git a/src/Orchard.Web/Modules/Orchard.OutputCache/Services/CacheService.cs b/src/Orchard.Web/Modules/Orchard.OutputCache/Services/CacheService.cs index 542983ab6..012a494d1 100644 --- a/src/Orchard.Web/Modules/Orchard.OutputCache/Services/CacheService.cs +++ b/src/Orchard.Web/Modules/Orchard.OutputCache/Services/CacheService.cs @@ -99,7 +99,7 @@ namespace Orchard.OutputCache.Services { } public IEnumerable GetRouteConfigs() { - return _cacheManager.Get(RouteConfigsCacheKey, + return _cacheManager.Get(RouteConfigsCacheKey, true, ctx => { ctx.Monitor(_signals.When(RouteConfigsCacheKey)); return _repository.Fetch(c => true).Select(c => new CacheRouteConfig { RouteKey = c.RouteKey, Duration = c.Duration, GraceTime = c.GraceTime }).ToReadOnlyCollection(); diff --git a/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Services/RubyScriptExpressionEvaluator.cs b/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Services/RubyScriptExpressionEvaluator.cs index 61a283ce3..e4a1385b6 100644 --- a/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Services/RubyScriptExpressionEvaluator.cs +++ b/src/Orchard.Web/Modules/Orchard.Scripting.Dlr/Services/RubyScriptExpressionEvaluator.cs @@ -14,7 +14,7 @@ namespace Orchard.Scripting.Dlr.Services { } public object Evaluate(string expression, IEnumerable providers) { - object execContextType = _cacheManager.Get("---", ctx => (object)_scriptingManager.ExecuteExpression(@" + object execContextType = _cacheManager.Get("---", true, ctx => (object)_scriptingManager.ExecuteExpression(@" class ExecBlock def initialize(callbacks) @callbacks = callbacks @@ -38,7 +38,7 @@ class ExecContext end ExecContext ")); - var ops = _cacheManager.Get("----", ctx => (ObjectOperations)_scriptingManager.ExecuteOperation(x => x)); + var ops = _cacheManager.Get("----", true, ctx => (ObjectOperations)_scriptingManager.ExecuteOperation(x => x)); object execContext = _cacheManager.Get(expression, ctx => (object)ops.InvokeMember(execContextType, "alloc", expression)); dynamic result = ops.InvokeMember(execContext, "evaluate", new CallbackApi(this, providers)); return ConvertRubyValue(result); diff --git a/src/Orchard.Web/Modules/Orchard.Scripting/ScriptExpressionEvaluator.cs b/src/Orchard.Web/Modules/Orchard.Scripting/ScriptExpressionEvaluator.cs index b6ebf4635..7d0148717 100644 --- a/src/Orchard.Web/Modules/Orchard.Scripting/ScriptExpressionEvaluator.cs +++ b/src/Orchard.Web/Modules/Orchard.Scripting/ScriptExpressionEvaluator.cs @@ -20,7 +20,7 @@ namespace Orchard.Scripting { public Localizer T { get; set; } public object Evaluate(string expression, IEnumerable providers) { - var expr = _cacheManager.Get(expression, ctx => { + var expr = _cacheManager.Get(expression, true, ctx => { var ast = ParseExpression(expression); return new { Tree = ast, Errors = ast.GetErrors().ToList() }; }); diff --git a/src/Orchard.Web/Modules/Orchard.Tags/Services/TagCloudService.cs b/src/Orchard.Web/Modules/Orchard.Tags/Services/TagCloudService.cs index 26dbf2c52..a05644f69 100644 --- a/src/Orchard.Web/Modules/Orchard.Tags/Services/TagCloudService.cs +++ b/src/Orchard.Web/Modules/Orchard.Tags/Services/TagCloudService.cs @@ -32,7 +32,7 @@ namespace Orchard.Tags.Services { public IEnumerable GetPopularTags(int buckets, string slug) { var cacheKey = "Orchard.Tags.TagCloud." + (slug ?? "") + '.' + buckets; - return _cacheManager.Get(cacheKey, + return _cacheManager.Get(cacheKey, true, ctx => { ctx.Monitor(_signals.When(TagCloudTagsChanged)); IEnumerable tagCounts; diff --git a/src/Orchard.Web/Modules/Orchard.Templates/Services/TemplateShapeBindingResolver.cs b/src/Orchard.Web/Modules/Orchard.Templates/Services/TemplateShapeBindingResolver.cs index 6d8e1743a..4fc5eb6a1 100644 --- a/src/Orchard.Web/Modules/Orchard.Templates/Services/TemplateShapeBindingResolver.cs +++ b/src/Orchard.Web/Modules/Orchard.Templates/Services/TemplateShapeBindingResolver.cs @@ -55,7 +55,7 @@ namespace Orchard.Templates.Services { } private IDictionary BuildShapeProcessors() { - return _cacheManager.Get("Template.ShapeProcessors", ctx => { + return _cacheManager.Get("Template.ShapeProcessors", true, ctx => { ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal)); // select all name of types which contains ShapePart diff --git a/src/Orchard/Caching/ICacheManager.cs b/src/Orchard/Caching/ICacheManager.cs index c54902eb9..785d34f0c 100644 --- a/src/Orchard/Caching/ICacheManager.cs +++ b/src/Orchard/Caching/ICacheManager.cs @@ -5,4 +5,17 @@ namespace Orchard.Caching { TResult Get(TKey key, Func, TResult> acquire); ICache GetCache(); } + + public static class CacheManagerExtensions { + public static TResult Get(this ICacheManager cacheManager, TKey key, bool lazy, Func, TResult> acquire) { + // Wrap the call in a Lazy initializer to prevent multiple processes from + // executing the same lambda in parallel. + if (lazy) { + return cacheManager.Get>(key, k => new Lazy(() => acquire(k))).Value; + } + else { + return cacheManager.Get(key, acquire); + } + } + } } diff --git a/src/Orchard/ContentManagement/DefaultContentManager.cs b/src/Orchard/ContentManagement/DefaultContentManager.cs index 7fef637aa..5ab03e3f2 100644 --- a/src/Orchard/ContentManagement/DefaultContentManager.cs +++ b/src/Orchard/ContentManagement/DefaultContentManager.cs @@ -814,7 +814,7 @@ namespace Orchard.ContentManagement { } private ContentTypeRecord AcquireContentTypeRecord(string contentType) { - var contentTypeId = _cacheManager.Get(contentType + "_Record", ctx => { + var contentTypeId = _cacheManager.Get(contentType + "_Record", true, ctx => { ctx.Monitor(_signals.When(contentType + "_Record")); var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType); diff --git a/src/Orchard/ContentManagement/DefaultContentQuery.cs b/src/Orchard/ContentManagement/DefaultContentQuery.cs index 468d105ef..befcd03aa 100644 --- a/src/Orchard/ContentManagement/DefaultContentQuery.cs +++ b/src/Orchard/ContentManagement/DefaultContentQuery.cs @@ -76,7 +76,7 @@ namespace Orchard.ContentManagement { } private int GetContentTypeRecordId(string contentType) { - return _cacheManager.Get(contentType + "_Record", ctx => { + return _cacheManager.Get(contentType + "_Record", true, ctx => { ctx.Monitor(_signals.When(contentType + "_Record")); var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType); diff --git a/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs b/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs index bc9eb0667..e1cfd57a7 100644 --- a/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs +++ b/src/Orchard/DisplayManagement/Descriptors/DefaultShapeTableManager.cs @@ -37,7 +37,7 @@ namespace Orchard.DisplayManagement.Descriptors { public ILogger Logger { get; set; } public ShapeTable GetShapeTable(string themeName) { - return _cacheManager.Get(themeName ?? "", x => { + return _cacheManager.Get(themeName ?? "", true, x => { Logger.Information("Start building shape table"); var alterationSets = _parallelCacheContext.RunInParallel(_bindingStrategies, bindingStrategy => { diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/PlacementFileParser.cs b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/PlacementFileParser.cs index 8725ded54..9ce3454b9 100644 --- a/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/PlacementFileParser.cs +++ b/src/Orchard/DisplayManagement/Descriptors/ShapePlacementStrategy/PlacementFileParser.cs @@ -30,7 +30,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy { public bool DisableMonitoring { get; set; } public PlacementFile Parse(string virtualPath) { - return _cacheManager.Get(virtualPath, context => { + return _cacheManager.Get(virtualPath, true, context => { if (!DisableMonitoring) { Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath); diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs index 5b04c9358..95b0c6694 100644 --- a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs +++ b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs @@ -77,7 +77,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy { var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => { var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/'); var virtualPath = Path.Combine(basePath, subPath).Replace(Path.DirectorySeparatorChar, '/'); - var fileNames = _cacheManager.Get(virtualPath, ctx => { + var fileNames = _cacheManager.Get(virtualPath, true, ctx => { if (!_virtualPathProvider.DirectoryExists(virtualPath)) return new List(); diff --git a/src/Orchard/Environment/Extensions/Compilers/DefaultProjectFileParser.cs b/src/Orchard/Environment/Extensions/Compilers/DefaultProjectFileParser.cs index 01a717b12..08adf43a1 100644 --- a/src/Orchard/Environment/Extensions/Compilers/DefaultProjectFileParser.cs +++ b/src/Orchard/Environment/Extensions/Compilers/DefaultProjectFileParser.cs @@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Compilers { public bool DisableMonitoring { get; set; } public ProjectFileDescriptor Parse(string virtualPath) { - return _cacheManager.Get(virtualPath, + return _cacheManager.Get(virtualPath, true, ctx => { if (!DisableMonitoring) { Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath); diff --git a/src/Orchard/Environment/Extensions/ExtensionManager.cs b/src/Orchard/Environment/Extensions/ExtensionManager.cs index 4dc8c02d3..40092fd21 100644 --- a/src/Orchard/Environment/Extensions/ExtensionManager.cs +++ b/src/Orchard/Environment/Extensions/ExtensionManager.cs @@ -45,7 +45,7 @@ namespace Orchard.Environment.Extensions { } public IEnumerable AvailableExtensions() { - return _cacheManager.Get("AvailableExtensions", ctx => + return _cacheManager.Get("AvailableExtensions", true, ctx => _parallelCacheContext .RunInParallel(_folders, folder => folder.AvailableExtensions().ToList()) .SelectMany(descriptors => descriptors) @@ -53,7 +53,7 @@ namespace Orchard.Environment.Extensions { } public IEnumerable AvailableFeatures() { - return _cacheManager.Get("AvailableFeatures", ctx => + return _cacheManager.Get("AvailableFeatures", true, ctx => AvailableExtensions() .SelectMany(ext => ext.Features) .OrderByDependenciesAndPriorities(HasDependency, GetPriority) @@ -93,7 +93,7 @@ namespace Orchard.Environment.Extensions { var result = _parallelCacheContext - .RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, ctx => LoadFeature(descriptor))) + .RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, true, ctx => LoadFeature(descriptor))) .ToArray(); Logger.Information("Done loading features"); @@ -107,7 +107,7 @@ namespace Orchard.Environment.Extensions { ExtensionEntry extensionEntry; try { - extensionEntry = _cacheManager.Get(extensionId, ctx => { + extensionEntry = _cacheManager.Get(extensionId, true, ctx => { var entry = BuildEntry(extensionDescriptor); if (entry != null) { ctx.Monitor(_asyncTokenProvider.GetToken(monitor => { diff --git a/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs b/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs index 38215b366..2a7bfbafb 100644 --- a/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs +++ b/src/Orchard/Environment/Extensions/Folders/ExtensionHarvester.cs @@ -56,7 +56,7 @@ namespace Orchard.Environment.Extensions.Folders { private IEnumerable HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) { string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType); - return _cacheManager.Get(key, ctx => { + return _cacheManager.Get(key, true, ctx => { if (!DisableMonitoring) { Logger.Debug("Monitoring virtual path \"{0}\"", path); ctx.Monitor(_webSiteFolder.WhenPathChanges(path)); @@ -135,7 +135,7 @@ namespace Orchard.Environment.Extensions.Folders { } private ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionId, string extensionType, string manifestPath, bool manifestIsOptional) { - return _cacheManager.Get(manifestPath, context => { + return _cacheManager.Get(manifestPath, true, context => { if (!DisableMonitoring) { Logger.Debug("Monitoring virtual path \"{0}\"", manifestPath); context.Monitor(_webSiteFolder.WhenPathChanges(manifestPath)); diff --git a/src/Orchard/Environment/IAssemblyNameResolver.cs b/src/Orchard/Environment/IAssemblyNameResolver.cs index f97631719..78d809ab7 100644 --- a/src/Orchard/Environment/IAssemblyNameResolver.cs +++ b/src/Orchard/Environment/IAssemblyNameResolver.cs @@ -37,7 +37,7 @@ namespace Orchard.Environment { public string Resolve(string shortName) { // A few common .net framework assemblies are referenced by the Orchard.Framework assembly. // Look into those to see if we can find the assembly we are looking for. - var orchardFrameworkReferences = _cacheManager.Get(typeof(IAssemblyLoader), ctx => + var orchardFrameworkReferences = _cacheManager.Get(typeof(IAssemblyLoader), true, ctx => ctx.Key.Assembly .GetReferencedAssemblies() .GroupBy(n => AssemblyLoaderExtensions.ExtractAssemblyShortName(n.FullName), StringComparer.OrdinalIgnoreCase) diff --git a/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs b/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs index de9c05869..ace5674fe 100644 --- a/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs +++ b/src/Orchard/FileSystems/Dependencies/DefaultDependenciesFolder.cs @@ -34,7 +34,7 @@ namespace Orchard.FileSystems.Dependencies { } public IEnumerable LoadDescriptors() { - return _cacheManager.Get(PersistencePath, + return _cacheManager.Get(PersistencePath, true, ctx => { _appDataFolder.CreateDirectory(BasePath); diff --git a/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs b/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs index 1afd04077..afde10403 100644 --- a/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs +++ b/src/Orchard/FileSystems/Dependencies/DefaultExtensionDependenciesManager.cs @@ -65,7 +65,7 @@ namespace Orchard.FileSystems.Dependencies { } public IEnumerable LoadDescriptors() { - return _cacheManager.Get(PersistencePath, ctx => { + return _cacheManager.Get(PersistencePath, true, ctx => { _appDataFolder.CreateDirectory(BasePath); if (!DisableMonitoring) { diff --git a/src/Orchard/Localization/Services/DefaultCultureManager.cs b/src/Orchard/Localization/Services/DefaultCultureManager.cs index 9026e4acb..19ffa05b8 100644 --- a/src/Orchard/Localization/Services/DefaultCultureManager.cs +++ b/src/Orchard/Localization/Services/DefaultCultureManager.cs @@ -26,7 +26,7 @@ namespace Orchard.Localization.Services { } public IEnumerable ListCultures() { - return _cacheManager.Get("Cultures", context => { + return _cacheManager.Get("Cultures", true, context => { context.Monitor(_signals.When("culturesChanged")); return _cultureRepository.Table.Select(o => o.Culture).ToList(); diff --git a/src/Orchard/Localization/Services/DefaultLocalizedStringManager.cs b/src/Orchard/Localization/Services/DefaultLocalizedStringManager.cs index cb9516399..e0a2a29de 100644 --- a/src/Orchard/Localization/Services/DefaultLocalizedStringManager.cs +++ b/src/Orchard/Localization/Services/DefaultLocalizedStringManager.cs @@ -90,7 +90,7 @@ namespace Orchard.Localization.Services { // Cache entry will be invalidated any time the directories hosting // the .po files are modified. private CultureDictionary LoadCulture(string culture) { - return _cacheManager.Get(culture, ctx => { + return _cacheManager.Get(culture, true, ctx => { ctx.Monitor(_signals.When("culturesChanged")); return new CultureDictionary { CultureName = culture, From 60798f93468d84fc6a48725ca30d996aab59c0e4 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 17:09:53 -0700 Subject: [PATCH 29/33] Fixing TokenManagerTests --- .../Modules/Orchard.Tokens/Tests/TokenManagerTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenManagerTests.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenManagerTests.cs index 341e5ed37..073442bb9 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenManagerTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Tests/TokenManagerTests.cs @@ -29,10 +29,11 @@ namespace Orchard.Tokens.Tests { [Test] public void TestDescribe() { var allTokens = _tokenManager.Describe(null); - Assert.That(allTokens.Count(), Is.EqualTo(3)); + Assert.That(allTokens.Count(), Is.EqualTo(4)); Assert.That(allTokens.Any(d => d.Target == "Site")); Assert.That(allTokens.Any(d => d.Target == "User")); Assert.That(allTokens.Any(d => d.Target == "Date")); + Assert.That(allTokens.Any(d => d.Target == "Users")); var tokens = allTokens.Single(d => d.Target == "Site").Tokens; Assert.That(string.Join(",", tokens.Select(td => td.Target)), Is.EqualTo("Site,Site,Site,Site")); @@ -59,7 +60,7 @@ namespace Orchard.Tokens.Tests { [Test] public void TestDescribeFilter() { var tokenDescriptors = _tokenManager.Describe(null); - Assert.That(tokenDescriptors.Count(), Is.EqualTo(3)); + Assert.That(tokenDescriptors.Count(), Is.EqualTo(4)); tokenDescriptors = _tokenManager.Describe(new[] { "Site" }); Assert.That(tokenDescriptors.Count(), Is.EqualTo(1)); Assert.That(tokenDescriptors.First().Target, Is.EqualTo("Site")); From e8f0ba6ec72b0ee48e953befa6676057259f1b3d Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 8 Sep 2015 17:12:44 -0700 Subject: [PATCH 30/33] Fixing RecipeManagerTests --- .../Recipes/Services/RecipeManagerTests.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs b/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs index c5d3902bd..9d58c475d 100644 --- a/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs +++ b/src/Orchard.Tests.Modules/Recipes/Services/RecipeManagerTests.cs @@ -98,23 +98,23 @@ namespace Orchard.Tests.Modules.Recipes.Services { [Test] public void HarvestRecipesFailsToFindRecipesWhenCalledWithNotExistingExtension() { - var recipes = (List) _recipeHarvester.HarvestRecipes("cantfindme"); + var recipes = _recipeHarvester.HarvestRecipes("cantfindme"); - Assert.That(recipes.Count, Is.EqualTo(0)); + Assert.That(recipes.Count(), Is.EqualTo(0)); } [Test] public void HarvestRecipesShouldHarvestRecipeXmlFiles() { - var recipes = (List)_recipeHarvester.HarvestRecipes("Sample1"); - Assert.That(recipes.Count, Is.EqualTo(1)); + var recipes = _recipeHarvester.HarvestRecipes("Sample1"); + Assert.That(recipes.Count(), Is.EqualTo(1)); } [Test] public void ParseRecipeLoadsRecipeMetaDataIntoModel() { - var recipes = (List) _recipeHarvester.HarvestRecipes("Sample1"); - Assert.That(recipes.Count, Is.EqualTo(1)); + var recipes = _recipeHarvester.HarvestRecipes("Sample1"); + Assert.That(recipes.Count(), Is.EqualTo(1)); - var sampleRecipe = recipes[0]; + var sampleRecipe = recipes.First(); Assert.That(sampleRecipe.Name, Is.EqualTo("cms")); Assert.That(sampleRecipe.Description, Is.EqualTo("a sample Orchard recipe describing a cms")); Assert.That(sampleRecipe.Author, Is.EqualTo("orchard")); From c75e6a808d37c87f692f7164b40698f61cd724bc Mon Sep 17 00:00:00 2001 From: qt1 Date: Thu, 10 Sep 2015 01:52:02 +0300 Subject: [PATCH 31/33] Order of projects change in sln - csprojs come before rebracer and gulp --- src/Orchard.sln | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Orchard.sln b/src/Orchard.sln index 40a51d6f3..ace52701a 100644 --- a/src/Orchard.sln +++ b/src/Orchard.sln @@ -255,14 +255,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Layouts", "Orchard. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.DynamicForms", "Orchard.Web\Modules\Orchard.DynamicForms\Orchard.DynamicForms.csproj", "{82190F52-2901-46D6-8A4C-34649959483F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Dashboards", "Orchard.Web\Modules\Orchard.Dashboards\Orchard.Dashboards.csproj", "{BAC82DB9-F4C4-4DD1-ABDB-F70E6229E6B0}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF3909B0-1DDD-4D8A-9919-56FC438E25E2}" ProjectSection(SolutionItems) = preProject Rebracer.xml = Rebracer.xml WebEssentials-Settings.json = WebEssentials-Settings.json EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Dashboards", "Orchard.Web\Modules\Orchard.Dashboards\Orchard.Dashboards.csproj", "{BAC82DB9-F4C4-4DD1-ABDB-F70E6229E6B0}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gulp", "Gulp", "{90EBEE36-B5CD-42A8-A21B-76270E2C5D24}" ProjectSection(SolutionItems) = preProject Gulpfile.js = Gulpfile.js From 57ad6190f8ddf1d98f0063f5e84c8cc1247dac00 Mon Sep 17 00:00:00 2001 From: Ryan Kelso Date: Thu, 10 Sep 2015 11:11:23 -0400 Subject: [PATCH 32/33] Updated StringExtension.cs - CamelFriendly method Made it more obvious how CamelFriendly was choosing to enter spaces in a string Done on behalf of Radio Systems Corporation --- src/Orchard/Utility/Extensions/StringExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Orchard/Utility/Extensions/StringExtensions.cs b/src/Orchard/Utility/Extensions/StringExtensions.cs index 1e66a8248..9553aa779 100644 --- a/src/Orchard/Utility/Extensions/StringExtensions.cs +++ b/src/Orchard/Utility/Extensions/StringExtensions.cs @@ -17,7 +17,7 @@ namespace Orchard.Utility.Extensions { for (int i = camel.Length-1; i>0; i--) { var current = sb[i]; - if('A' <= current && current <= 'Z') { + if(char.IsUpper(current)) { sb.Insert(i, ' '); } } @@ -357,4 +357,4 @@ namespace Orchard.Utility.Extensions { return Encoding.UTF8.GetString(Convert.FromBase64String(value)); } } -} \ No newline at end of file +} From ba35bc060f36a8df60710d499fe9f9fd2717ace5 Mon Sep 17 00:00:00 2001 From: Ryan Kelso Date: Thu, 10 Sep 2015 13:13:00 -0400 Subject: [PATCH 33/33] Update StringExtensions.cs Removed extraneous variable --- src/Orchard/Utility/Extensions/StringExtensions.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Orchard/Utility/Extensions/StringExtensions.cs b/src/Orchard/Utility/Extensions/StringExtensions.cs index 9553aa779..08b43ea9a 100644 --- a/src/Orchard/Utility/Extensions/StringExtensions.cs +++ b/src/Orchard/Utility/Extensions/StringExtensions.cs @@ -16,8 +16,7 @@ namespace Orchard.Utility.Extensions { var sb = new StringBuilder(camel); for (int i = camel.Length-1; i>0; i--) { - var current = sb[i]; - if(char.IsUpper(current)) { + if(char.IsUpper(sb[i])) { sb.Insert(i, ' '); } }