Merge remote-tracking branch 'origin/dev' into feature/tenantstateinitializing

This commit is contained in:
Sipke Schoorstra
2015-09-10 23:39:01 +01:00
84 changed files with 821 additions and 232 deletions

View File

@@ -13,7 +13,8 @@ var glob = require("glob"),
uglify = require("gulp-uglify"), uglify = require("gulp-uglify"),
rename = require("gulp-rename"), rename = require("gulp-rename"),
concat = require("gulp-concat"), concat = require("gulp-concat"),
header = require("gulp-header"); header = require("gulp-header"),
fs = require("fs");
/* /*
** GULP TASKS ** GULP TASKS
@@ -37,32 +38,53 @@ gulp.task("rebuild", function () {
return merge(assetGroupTasks); 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 () { gulp.task("watch", function () {
var pathWin32 = require("path"); var watchers;
getAssetGroups().forEach(function (assetGroup) { function restart() {
var watchPaths = assetGroup.inputPaths.concat(assetGroup.watchPaths); if (watchers) {
gulp.watch(watchPaths, function (event) { watchers.forEach(function (w) {
var isConcat = path.basename(assetGroup.outputFileName, path.extname(assetGroup.outputFileName)) !== "@"; w.remove();
if (isConcat) w.end();
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."); watchers = [];
var doRebuild = true; // Continuous watch (each asset group is built whenever one of its inputs changes).
var task = createAssetGroupTask(assetGroup, doRebuild); 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 ** ASSET GROUPS
*/ */
function getAssetGroups() { 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 = []; var assetGroups = [];
assetManifestPaths.forEach(function (assetManifestPath) { assetManifestPaths.forEach(function (assetManifestPath) {
var assetManifest = require("./" + assetManifestPath); var file = './' + assetManifestPath;
var json = fs.readFileSync(file, 'utf8');
assetManifest = eval(json);
assetManifest.forEach(function (assetGroup) { assetManifest.forEach(function (assetGroup) {
resolveAssetGroupPaths(assetGroup, assetManifestPath); resolveAssetGroupPaths(assetGroup, assetManifestPath);
assetGroups.push(assetGroup); assetGroups.push(assetGroup);

View File

@@ -110,23 +110,23 @@ namespace Orchard.Tests.Modules.Recipes.Services {
[Test] [Test]
public void HarvestRecipesFailsToFindRecipesWhenCalledWithNotExistingExtension() { public void HarvestRecipesFailsToFindRecipesWhenCalledWithNotExistingExtension() {
var recipes = (List<Recipe>)_recipeHarvester.HarvestRecipes("cantfindme"); var recipes = _recipeHarvester.HarvestRecipes("cantfindme");
Assert.That(recipes.Count, Is.EqualTo(0)); Assert.That(recipes.Count(), Is.EqualTo(0));
} }
[Test] [Test]
public void HarvestRecipesShouldHarvestRecipeXmlFiles() { public void HarvestRecipesShouldHarvestRecipeXmlFiles() {
var recipes = (List<Recipe>)_recipeHarvester.HarvestRecipes("Sample1"); var recipes = _recipeHarvester.HarvestRecipes("Sample1");
Assert.That(recipes.Count, Is.EqualTo(1)); Assert.That(recipes.Count(), Is.EqualTo(1));
} }
[Test] [Test]
public void ParseRecipeLoadsRecipeMetaDataIntoModel() { public void ParseRecipeLoadsRecipeMetaDataIntoModel() {
var recipes = (List<Recipe>)_recipeHarvester.HarvestRecipes("Sample1"); var recipes = _recipeHarvester.HarvestRecipes("Sample1");
Assert.That(recipes.Count, Is.EqualTo(1)); 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.Name, Is.EqualTo("cms"));
Assert.That(sampleRecipe.Description, Is.EqualTo("a sample Orchard recipe describing a cms")); Assert.That(sampleRecipe.Description, Is.EqualTo("a sample Orchard recipe describing a cms"));
Assert.That(sampleRecipe.Author, Is.EqualTo("orchard")); Assert.That(sampleRecipe.Author, Is.EqualTo("orchard"));

View File

@@ -1,4 +1,6 @@
using System; using System;
using System.Linq;
using System.Threading;
using Autofac; using Autofac;
using NUnit.Framework; using NUnit.Framework;
using Orchard.Caching; using Orchard.Caching;
@@ -78,6 +80,42 @@ namespace Orchard.Tests.Caching {
Is.Not.SameAs(c2.CacheManager.GetCache<string, string>())); Is.Not.SameAs(c2.CacheManager.GetCache<string, string>()));
} }
[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 { class ComponentOne {
public ICacheManager CacheManager { get; set; } public ICacheManager CacheManager { get; set; }

View File

@@ -4,7 +4,7 @@ using Orchard.Localization.Models;
namespace Orchard.Tests.Localization { namespace Orchard.Tests.Localization {
[TestFixture] [TestFixture()]
public class DateTimePartsTests { public class DateTimePartsTests {
[Test] [Test]

View File

@@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@@ -13,7 +12,8 @@ using Orchard.Localization.Services;
namespace Orchard.Tests.Localization { namespace Orchard.Tests.Localization {
[TestFixture] [TestFixture()]
[Category("longrunning")]
public class DefaultDateFormatterTests { public class DefaultDateFormatterTests {
[SetUp] [SetUp]

View File

@@ -9,7 +9,7 @@ namespace Orchard.Tests.Stubs {
WorkContext = workContext; WorkContext = workContext;
} }
public WorkContext WorkContext { get; } public WorkContext WorkContext { get; private set; }
public void Dispose() { public void Dispose() {
_lifetimeScope.Dispose(); _lifetimeScope.Dispose();

View File

@@ -89,9 +89,9 @@ namespace Orchard.WarmupStarter {
var result = _initialization(application); var result = _initialization(application);
_initializationResult = result; _initializationResult = result;
} }
catch (Exception e) { catch (Exception ex) {
lock (_synLock) { lock (_synLock) {
_error = e; _error = ex;
_previousError = null; _previousError = null;
} }
} }

View File

@@ -17,6 +17,7 @@ using Orchard.UI.Navigation;
using Orchard.Utility; using Orchard.Utility;
using System; using System;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Core.Navigation.Controllers { namespace Orchard.Core.Navigation.Controllers {
[ValidateInput(false)] [ValidateInput(false)]
@@ -179,6 +180,10 @@ namespace Orchard.Core.Navigation.Controllers {
return View(model); return View(model);
} }
catch (Exception exception) { catch (Exception exception) {
if (exception.IsFatal()) {
throw;
}
Logger.Error(T("Creating menu item failed: {0}", exception.Message).Text); Logger.Error(T("Creating menu item failed: {0}", exception.Message).Text);
Services.Notifier.Error(T("Creating menu item failed: {0}", exception.Message)); Services.Notifier.Error(T("Creating menu item failed: {0}", exception.Message));
return this.RedirectLocal(returnUrl, () => RedirectToAction("Index")); return this.RedirectLocal(returnUrl, () => RedirectToAction("Index"));

View File

@@ -11,6 +11,7 @@ using Orchard.Security.Permissions;
using Orchard.UI; using Orchard.UI;
using Orchard.UI.Navigation; using Orchard.UI.Navigation;
using Orchard.Utility; using Orchard.Utility;
using Orchard.Exceptions;
namespace Orchard.Core.Navigation.Services { namespace Orchard.Core.Navigation.Services {
public class NavigationManager : INavigationManager { public class NavigationManager : INavigationManager {
@@ -152,6 +153,9 @@ namespace Orchard.Core.Navigation.Services {
items = builder.Build(); items = builder.Build();
} }
catch (Exception ex) { 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."); 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) { if (items != null) {
@@ -170,6 +174,9 @@ namespace Orchard.Core.Navigation.Services {
items = builder.Build(); items = builder.Build();
} }
catch (Exception ex) { 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."); 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) { if (items != null) {
@@ -188,6 +195,9 @@ namespace Orchard.Core.Navigation.Services {
imageSets = builder.BuildImageSets(); imageSets = builder.BuildImageSets();
} }
catch (Exception ex) { 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."); 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) { if (imageSets != null) {

View File

@@ -8,6 +8,7 @@ using Orchard.Logging;
using Orchard.Services; using Orchard.Services;
using Orchard.Tasks; using Orchard.Tasks;
using Orchard.Tasks.Scheduling; using Orchard.Tasks.Scheduling;
using Orchard.Exceptions;
namespace Orchard.Core.Scheduling.Services { namespace Orchard.Core.Scheduling.Services {
public class ScheduledTaskExecutor : IBackgroundTask { public class ScheduledTaskExecutor : IBackgroundTask {
@@ -63,6 +64,9 @@ namespace Orchard.Core.Scheduling.Services {
} }
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
Logger.Warning(ex, "Unable to process scheduled task #{0} of type {1}", taskEntry.Id, taskEntry.Action); Logger.Warning(ex, "Unable to process scheduled task #{0} of type {1}", taskEntry.Id, taskEntry.Action);
_transactionManager.Cancel(); _transactionManager.Cancel();
} }

View File

@@ -10,6 +10,7 @@ using Orchard.Logging;
using Orchard.Security; using Orchard.Security;
using Orchard.Settings; using Orchard.Settings;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using Orchard.Exceptions;
namespace Orchard.Core.Settings.Drivers { namespace Orchard.Core.Settings.Drivers {
public class SiteSettingsPartDriver : ContentPartDriver<SiteSettingsPart> { public class SiteSettingsPartDriver : ContentPartDriver<SiteSettingsPart> {
@@ -100,9 +101,12 @@ namespace Orchard.Core.Settings.Drivers {
using (request.GetResponse() as HttpWebResponse) {} 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.")); _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);
} }
} }
} }

View File

@@ -9,6 +9,7 @@ using Orchard.ContentManagement.MetaData.Services;
using Orchard.Core.Settings.Metadata.Records; using Orchard.Core.Settings.Metadata.Records;
using Orchard.Data; using Orchard.Data;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Core.Settings.Metadata { namespace Orchard.Core.Settings.Metadata {
public class ContentDefinitionManager : Component, IContentDefinitionManager { public class ContentDefinitionManager : Component, IContentDefinitionManager {
@@ -124,7 +125,7 @@ namespace Orchard.Core.Settings.Metadata {
} }
private IDictionary<string, ContentTypeDefinition> AcquireContentTypeDefinitions() { private IDictionary<string, ContentTypeDefinition> AcquireContentTypeDefinitions() {
return _cacheManager.Get("ContentTypeDefinitions", ctx => { return _cacheManager.Get("ContentTypeDefinitions", true, ctx => {
MonitorContentDefinitionSignal(ctx); MonitorContentDefinitionSignal(ctx);
AcquireContentPartDefinitions(); AcquireContentPartDefinitions();
@@ -139,7 +140,7 @@ namespace Orchard.Core.Settings.Metadata {
} }
private IDictionary<string, ContentPartDefinition> AcquireContentPartDefinitions() { private IDictionary<string, ContentPartDefinition> AcquireContentPartDefinitions() {
return _cacheManager.Get("ContentPartDefinitions", ctx => { return _cacheManager.Get("ContentPartDefinitions", true, ctx => {
MonitorContentDefinitionSignal(ctx); MonitorContentDefinitionSignal(ctx);
var contentPartDefinitionRecords = _partDefinitionRepository.Table var contentPartDefinitionRecords = _partDefinitionRepository.Table
@@ -152,7 +153,7 @@ namespace Orchard.Core.Settings.Metadata {
} }
private IDictionary<string, ContentFieldDefinition> AcquireContentFieldDefinitions() { private IDictionary<string, ContentFieldDefinition> AcquireContentFieldDefinitions() {
return _cacheManager.Get("ContentFieldDefinitions", ctx => { return _cacheManager.Get("ContentFieldDefinitions", true, ctx => {
MonitorContentDefinitionSignal(ctx); MonitorContentDefinitionSignal(ctx);
return _fieldDefinitionRepository.Table.Select(Build).ToDictionary(x => x.Name, y => y); return _fieldDefinitionRepository.Table.Select(Build).ToDictionary(x => x.Name, y => y);
@@ -282,6 +283,9 @@ namespace Orchard.Core.Settings.Metadata {
return XElement.Parse(settings); return XElement.Parse(settings);
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "Unable to parse settings xml"); Logger.Error(ex, "Unable to parse settings xml");
return null; return null;
} }

View File

@@ -17,7 +17,7 @@ namespace Orchard.Core.Settings.Services {
} }
public ISite GetSiteSettings() { public ISite GetSiteSettings() {
var siteId = _cacheManager.Get("SiteId", ctx => { var siteId = _cacheManager.Get("SiteId", true, ctx => {
var site = _contentManager.Query("Site") var site = _contentManager.Query("Site")
.List() .List()
.FirstOrDefault(); .FirstOrDefault();

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Globalization;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
@@ -32,8 +31,20 @@ namespace Orchard.Core.Shapes {
DateTimeUtc = DateTimeUtc != System.DateTime.MinValue ? DateTimeUtc : dateTimeUtc; // Both capitalizations retained for compatibility. DateTimeUtc = DateTimeUtc != System.DateTime.MinValue ? DateTimeUtc : dateTimeUtc; // Both capitalizations retained for compatibility.
var time = _clock.UtcNow - DateTimeUtc; var time = _clock.UtcNow - DateTimeUtc;
if (time.TotalDays > 7 || time.TotalDays < -7) if (time.TotalYears() > 1)
return Display.DateTime(DateTimeUtc: DateTimeUtc, CustomFormat: null); 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) if (time.TotalHours > 24)
return T.Plural("1 day ago", "{0} days ago", time.Days); 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)); return new MvcHtmlString(_dateLocalizationServices.ConvertToLocalizedString(DateTimeUtc, CustomFormat.Text));
} }
} }
}
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;
}
}
}

View File

@@ -17,7 +17,7 @@ namespace Orchard.ContentPicker.Fields {
public IEnumerable<ContentItem> ContentItems { public IEnumerable<ContentItem> ContentItems {
get { get {
return _contentItems.Value; return _contentItems.Value ?? Enumerable.Empty<ContentItem>();
} }
} }

View File

@@ -22,7 +22,7 @@ namespace Orchard.ContentTypes.Services {
} }
public IEnumerable<StereotypeDescription> GetStereotypes() { public IEnumerable<StereotypeDescription> 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. // 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. // For now, we'll just cache the stereotypes for 1 minute.

View File

@@ -1,10 +1,15 @@
using System; using System;
using System.Linq;
using System.Security.Cryptography;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions; using Orchard.Core.Contents.Extensions;
using Orchard.Data;
using Orchard.Data.Migration; using Orchard.Data.Migration;
namespace Orchard.DynamicForms { namespace Orchard.DynamicForms {
public class Migrations : DataMigrationImpl { 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 = private const string DefaultFormLayoutData =
@"{ @"{
""elements"": [ ""elements"": [
@@ -59,7 +64,52 @@ namespace Orchard.DynamicForms {
.WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData)) .WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData))
.WithSetting("Stereotype", "Widget") .WithSetting("Stereotype", "Widget")
.DisplayedAs("Form 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);
} }
} }
} }

View File

@@ -1,7 +1,7 @@
Name: Custom Forms Name: Dynamic Forms
AntiForgery: enabled AntiForgery: enabled
Author: The Orchard Team Author: The Orchard Team
Website: http://orchardcustomforms.codeplex.com Website: http://www.orchardproject.net/
Version: 1.9.1 Version: 1.9.1
OrchardVersion: 1.9 OrchardVersion: 1.9
Description: Create custom forms like contact forms using layouts. Description: Create custom forms like contact forms using layouts.

View File

@@ -7,7 +7,7 @@ namespace Orchard.DynamicForms.Tokens {
public void Describe(DescribeContext context) { 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.")) 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:<field name>"), T("The posted field value to access.")) .Token("Field:*", T("Field:<field name>"), T("The posted field value to access."), "Text")
.Token("IsValid:*", T("IsValid:<field name>"), T("The posted field validation status.")) .Token("IsValid:*", T("IsValid:<field name>"), T("The posted field validation status."))
; ;
} }
@@ -15,10 +15,20 @@ namespace Orchard.DynamicForms.Tokens {
public void Evaluate(EvaluateContext context) { public void Evaluate(EvaluateContext context) {
context.For<FormSubmissionTokenContext>("FormSubmission") context.For<FormSubmissionTokenContext>("FormSubmission")
.Token(token => token.StartsWith("Field:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Field:".Length) : null, GetFieldValue) .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); .Token(token => token.StartsWith("IsValid:", StringComparison.OrdinalIgnoreCase) ? token.Substring("IsValid:".Length) : null, GetFieldValidationStatus);
} }
private object GetFieldValue(string fieldName, FormSubmissionTokenContext context) { private static Tuple<string, string> FilterChainParam(string token) {
int tokenLength = "Field:".Length;
int chainIndex = token.IndexOf('.');
if (token.StartsWith("Field:", StringComparison.OrdinalIgnoreCase) && chainIndex > tokenLength)
return new Tuple<string, string>(token.Substring(tokenLength, chainIndex - tokenLength), token.Substring(chainIndex + 1));
else
return null;
}
private string GetFieldValue(string fieldName, FormSubmissionTokenContext context) {
return context.PostedValues[fieldName]; return context.PostedValues[fieldName];
} }

View File

@@ -307,10 +307,9 @@ namespace Orchard.Layouts.Drivers {
var queryPart = query.As<QueryPart>(); var queryPart = query.As<QueryPart>();
var layoutIndex = XmlHelper.Parse<int>(context.ExportableData.Get("LayoutIndex")); var layoutIndex = XmlHelper.Parse<int>(context.ExportableData.Get("LayoutIndex"));
var layout = queryPart.Layouts[layoutIndex];
element.QueryId = queryPart.Id; element.QueryId = queryPart.Id;
element.LayoutId = layout.Id; element.LayoutId = layoutIndex != -1 ? queryPart.Layouts[layoutIndex].Id : -1;
} }
private static string GetLayoutDescription(IEnumerable<LayoutDescriptor> layouts, LayoutRecord l) { private static string GetLayoutDescription(IEnumerable<LayoutDescriptor> layouts, LayoutRecord l) {

View File

@@ -38,7 +38,7 @@ namespace Orchard.Layouts.Services {
public IEnumerable<ElementDescriptor> DescribeElements(DescribeElementsContext context) { public IEnumerable<ElementDescriptor> DescribeElements(DescribeElementsContext context) {
var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string); var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string);
var cacheKey = String.Format("LayoutElementTypes-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam); 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 { var harvesterContext = new HarvestElementsContext {
Content = context.Content Content = context.Content
}; };
@@ -55,7 +55,7 @@ namespace Orchard.Layouts.Services {
public IEnumerable<CategoryDescriptor> GetCategories(DescribeElementsContext context) { public IEnumerable<CategoryDescriptor> GetCategories(DescribeElementsContext context) {
var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string); 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 elements = DescribeElements(context);
var categoryDictionary = GetCategories(); var categoryDictionary = GetCategories();
var categoryDescriptorDictionary = new Dictionary<string, CategoryDescriptor>(); var categoryDescriptorDictionary = new Dictionary<string, CategoryDescriptor>();

View File

@@ -5,17 +5,17 @@
} }
<div class="item-properties actions"> <div class="item-properties actions">
<p> <p>
@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", (string)Model.ContainerDisplayName), "Edit", new { Area = "Contents", Id = (int)Model.ContainerId, ReturnUrl = Html.ViewContext.HttpContext.Request.RawUrl })
</p> </p>
</div> </div>
<div class="manage"> <div class="manage">
@if (itemContentTypes.Any()) { @if (itemContentTypes.Any()) {
foreach (var contentType in itemContentTypes) { 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}", contentType.DisplayName), "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" })
} }
} }
else { 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" })
} }
<a id="chooseItems" href="#" class="button primaryAction">@T("Choose Items")</a> <a id="chooseItems" href="#" class="button primaryAction">@T("Choose Items")</a>
</div> </div>

View File

@@ -58,7 +58,7 @@ namespace Orchard.MediaProcessing.Services {
} }
private IDictionary<string, string> GetProfileCache(string profile) { private IDictionary<string, string> GetProfileCache(string profile) {
return _cacheManager.Get("MediaProcessing_" + profile, ctx => { return _cacheManager.Get("MediaProcessing_" + profile, true, ctx => {
ctx.Monitor(_signals.When("MediaProcessing_Saved_" + profile)); ctx.Monitor(_signals.When("MediaProcessing_Saved_" + profile));
var dictionary = new Dictionary<string, string>(); var dictionary = new Dictionary<string, string>();

View File

@@ -32,7 +32,7 @@ namespace Orchard.MediaProcessing.Services {
public ImageProfilePart GetImageProfileByName(string name) { public ImageProfilePart GetImageProfileByName(string name) {
var profileId = _cacheManager.Get("ProfileId_" + name, ctx => { var profileId = _cacheManager.Get("ProfileId_" + name, true, ctx => {
var profile = _contentManager.Query<ImageProfilePart, ImageProfilePartRecord>() var profile = _contentManager.Query<ImageProfilePart, ImageProfilePartRecord>()
.Where(x => x.Name == name) .Where(x => x.Name == name)
.Slice(0, 1) .Slice(0, 1)

View File

@@ -463,7 +463,7 @@ namespace Orchard.OutputCache.Filters {
private CacheSettings CacheSettings { private CacheSettings CacheSettings {
get { get {
return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, context => { return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, true, context => {
context.Monitor(_signals.When(CacheSettings.CacheKey)); context.Monitor(_signals.When(CacheSettings.CacheKey));
return new CacheSettings(_workContext.CurrentSite.As<CacheSettingsPart>()); return new CacheSettings(_workContext.CurrentSite.As<CacheSettingsPart>());
})); }));

View File

@@ -99,7 +99,7 @@ namespace Orchard.OutputCache.Services {
} }
public IEnumerable<CacheRouteConfig> GetRouteConfigs() { public IEnumerable<CacheRouteConfig> GetRouteConfigs() {
return _cacheManager.Get(RouteConfigsCacheKey, return _cacheManager.Get(RouteConfigsCacheKey, true,
ctx => { ctx => {
ctx.Monitor(_signals.When(RouteConfigsCacheKey)); ctx.Monitor(_signals.When(RouteConfigsCacheKey));
return _repository.Fetch(c => true).Select(c => new CacheRouteConfig { RouteKey = c.RouteKey, Duration = c.Duration, GraceTime = c.GraceTime }).ToReadOnlyCollection(); return _repository.Fetch(c => true).Select(c => new CacheRouteConfig { RouteKey = c.RouteKey, Duration = c.Duration, GraceTime = c.GraceTime }).ToReadOnlyCollection();

View File

@@ -14,7 +14,7 @@ namespace Orchard.Scripting.Dlr.Services {
} }
public object Evaluate(string expression, IEnumerable<IGlobalMethodProvider> providers) { public object Evaluate(string expression, IEnumerable<IGlobalMethodProvider> providers) {
object execContextType = _cacheManager.Get("---", ctx => (object)_scriptingManager.ExecuteExpression(@" object execContextType = _cacheManager.Get("---", true, ctx => (object)_scriptingManager.ExecuteExpression(@"
class ExecBlock class ExecBlock
def initialize(callbacks) def initialize(callbacks)
@callbacks = callbacks @callbacks = callbacks
@@ -38,7 +38,7 @@ class ExecContext
end end
ExecContext 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)); object execContext = _cacheManager.Get(expression, ctx => (object)ops.InvokeMember(execContextType, "alloc", expression));
dynamic result = ops.InvokeMember(execContext, "evaluate", new CallbackApi(this, providers)); dynamic result = ops.InvokeMember(execContext, "evaluate", new CallbackApi(this, providers));
return ConvertRubyValue(result); return ConvertRubyValue(result);

View File

@@ -20,7 +20,7 @@ namespace Orchard.Scripting {
public Localizer T { get; set; } public Localizer T { get; set; }
public object Evaluate(string expression, IEnumerable<IGlobalMethodProvider> providers) { public object Evaluate(string expression, IEnumerable<IGlobalMethodProvider> providers) {
var expr = _cacheManager.Get(expression, ctx => { var expr = _cacheManager.Get(expression, true, ctx => {
var ast = ParseExpression(expression); var ast = ParseExpression(expression);
return new { Tree = ast, Errors = ast.GetErrors().ToList() }; return new { Tree = ast, Errors = ast.GetErrors().ToList() };
}); });

View File

@@ -32,7 +32,7 @@ namespace Orchard.Tags.Services {
public IEnumerable<TagCount> GetPopularTags(int buckets, string slug) { public IEnumerable<TagCount> GetPopularTags(int buckets, string slug) {
var cacheKey = "Orchard.Tags.TagCloud." + (slug ?? "") + '.' + buckets; var cacheKey = "Orchard.Tags.TagCloud." + (slug ?? "") + '.' + buckets;
return _cacheManager.Get(cacheKey, return _cacheManager.Get(cacheKey, true,
ctx => { ctx => {
ctx.Monitor(_signals.When(TagCloudTagsChanged)); ctx.Monitor(_signals.When(TagCloudTagsChanged));
IEnumerable<TagCount> tagCounts; IEnumerable<TagCount> tagCounts;

View File

@@ -31,21 +31,33 @@ namespace Orchard.Taxonomies.Tokens {
context.For<TaxonomyField>("TaxonomyField") context.For<TaxonomyField>("TaxonomyField")
.Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray())) .Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray()))
.Token( .Token(FilterTokenParam,
token => { (index, field) => {
var index = 0; var term = field.Terms.ElementAtOrDefault(Convert.ToInt32(index));
return (token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) && int.TryParse(token.Substring("Terms:".Length), out index)) ? index.ToString() : null; return term != null ? term.Name : null;
},
(token, t) => {
var index = Convert.ToInt32(token);
return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name;
}) })
// todo: extend Chain() in order to accept a filter like in Token() so that we can chain on an expression .Chain(FilterChainParam, "Content", (index, field) => field.Terms.ElementAtOrDefault(Convert.ToInt32(index)))
.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))
; ;
} }
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<string, string> 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<string, string>(index.ToString(), token.Substring(chainIndex + 1));
}
else {
return null;
}
}
} }
} }

View File

@@ -55,7 +55,7 @@ namespace Orchard.Templates.Services {
} }
private IDictionary<string, TemplateResult> BuildShapeProcessors() { private IDictionary<string, TemplateResult> BuildShapeProcessors() {
return _cacheManager.Get("Template.ShapeProcessors", ctx => { return _cacheManager.Get("Template.ShapeProcessors", true, ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal)); ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
// select all name of types which contains ShapePart // select all name of types which contains ShapePart

View File

@@ -7,5 +7,6 @@ namespace Orchard.Tokens {
public abstract EvaluateFor<TData> Chain(string token, string chainTarget, Func<TData, object> chainValue); public abstract EvaluateFor<TData> Chain(string token, string chainTarget, Func<TData, object> chainValue);
public abstract EvaluateFor<TData> Token(Func<string, TData, object> tokenValue); public abstract EvaluateFor<TData> Token(Func<string, TData, object> tokenValue);
public abstract EvaluateFor<TData> Token(Func<string, string> filter, Func<string, TData, object> tokenValue); public abstract EvaluateFor<TData> Token(Func<string, string> filter, Func<string, TData, object> tokenValue);
public abstract EvaluateFor<TData> Chain(Func<string, Tuple<string, string>> filter, string chainTarget, Func<string, TData, object> chainValue);
} }
} }

View File

@@ -153,6 +153,27 @@ namespace Orchard.Tokens.Implementation {
} }
return this; return this;
} }
public override EvaluateFor<TData> Chain(Func<string, Tuple<string, string>> filter, string chainTarget, Func<string, TData, object> chainValue) {
var subTokens = _context.Tokens
.Where(kv => kv.Key.Contains('.'))
.Select(kv => {
var filterResult = filter(kv.Key);
return filterResult != null ? new Tuple<string, string, string>(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<string, object> { { chainTarget, chainValue(chainGroup.Key, _data) } });
foreach (var subValue in subValues) {
_context.Values[subValue.Key] = subValue.Value;
}
}
return this;
}
} }
private class EvaluateForSilent<TData> : EvaluateFor<TData> { private class EvaluateForSilent<TData> : EvaluateFor<TData> {
@@ -175,6 +196,10 @@ namespace Orchard.Tokens.Implementation {
public override EvaluateFor<TData> Chain(string token, string chainTarget, Func<TData, object> chainValue) { public override EvaluateFor<TData> Chain(string token, string chainTarget, Func<TData, object> chainValue) {
return this; return this;
} }
public override EvaluateFor<TData> Chain(Func<string, Tuple<string, string>> filter, string chainTarget, Func<string, TData, object> chainValue) {
return this;
}
} }
} }

View File

@@ -36,7 +36,7 @@ namespace Orchard.Tokens.Providers {
.Token("DisplayUrl", T("Display Url"), T("Url to display the content."), "Url") .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("EditUrl", T("Edit Url"), T("Url to edit the content."), "Url")
.Token("Container", T("Container"), T("The container Content Item."), "Content") .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 // Token descriptors for fields

View File

@@ -13,38 +13,45 @@ namespace Orchard.Tokens.Providers {
public void Describe(DescribeContext context) { public void Describe(DescribeContext context) {
context.For("Text", T("Text"), T("Tokens for text strings")) context.For("Text", T("Text"), T("Tokens for text strings"))
.Token("Limit:*", T("Limit:<text length>[,<ellipsis>]"), T("Limit text to specified length and append an optional ellipsis text.")) .Token("Limit:*", T("Limit:<text length>[,<ellipsis>]"), T("Limit text to specified length and append an optional ellipsis text."))
.Token("Format:*", T("Format:<text format>"), T("Optional format specifier (e.g. foo{0}bar). See format strings at <a target=\"_blank\" href=\"http://msdn.microsoft.com/en-us/library/az4se3k1.aspx\">Standard Formats</a> and <a target=\"_blank\" href=\"http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx\">Custom Formats</a>"), "DateTime") .Token("Format:*", T("Format:<text format>"), T("Optional format specifier (e.g. foo{0}bar)."))
.Token("TrimEnd:*", T("TrimEnd:<chars|number>"), T("Trims the specified characters or number of them from the end of the string."), "Text") .Token("TrimEnd:*", T("TrimEnd:<chars|number>"), 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("UrlEncode", T("Url Encode"), T("Encodes a URL string."), "Text")
.Token("HtmlEncode", T("Html Encode"), T("Encodes an HTML string."), "Text") .Token("HtmlEncode", T("Html Encode"), T("Encodes an HTML string."), "Text")
.Token("LineEncode", T("Line Encode"), T("Replaces new lines with <br /> tags.")) .Token("JavaScriptEncode", T("JavaScript Encode"), T("Encodes a JavaScript string."), "Text")
.Token("LineEncode", T("Line Encode"), T("Replaces new lines with <br /> tags."), "Text")
; ;
} }
public void Evaluate(EvaluateContext context) { public void Evaluate(EvaluateContext context) {
context.For<String>("Text", () => "") context.For<String>("Text", () => "")
.Token( // {Text} // {Text}
.Token(
token => token == String.Empty ? String.Empty : null, token => token == String.Empty ? String.Empty : null,
(token, d) => d.ToString()) (token, d) => d.ToString())
.Token( // {Text.Limit:<length>[,<ellipsis>]} // {Text.Limit:<length>[,<ellipsis>]}
token => { .Token(
if (token.StartsWith("Limit:", StringComparison.OrdinalIgnoreCase)) { token => FilterTokenParam("Limit:", token),
var param = token.Substring("Limit:".Length);
return param;
}
return null;
},
(token, t) => Limit(t, token)) (token, t) => Limit(t, token))
// {Text.Format:<formatstring>} // {Text.Format:<formatstring>}
.Token( .Token(
token => token.StartsWith("Format:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Format:".Length) : null, token => FilterTokenParam("Format:", token),
(token, d) => String.Format(d,token)) (token, d) => String.Format(d, token))
.Token(token => token.StartsWith("TrimEnd:", StringComparison.OrdinalIgnoreCase) ? token.Substring("TrimEnd:".Length) : null, TrimEnd) // {Text.TrimEnd:<chars|number>}
.Token(token => FilterTokenParam("TrimEnd:", token), TrimEnd)
.Token("UrlEncode", HttpUtility.UrlEncode) .Token("UrlEncode", HttpUtility.UrlEncode)
.Chain("UrlEncode", "Text", HttpUtility.UrlEncode)
.Token("HtmlEncode", HttpUtility.HtmlEncode) .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, "<br />")) .Token("LineEncode", text => text.Replace(System.Environment.NewLine, "<br />"))
.Chain("LineEncode", "Text", text => text.Replace(System.Environment.NewLine, "<br />"))
; ;
}
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) { private static string TrimEnd(string token, string param) {

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Security; using Orchard.Security;
@@ -24,6 +25,9 @@ namespace Orchard.Tokens.Tests {
context.For("Date") 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.")); .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) { public void Evaluate(EvaluateContext context) {
@@ -36,6 +40,7 @@ namespace Orchard.Tokens.Tests {
context.For<IUser>("User", () => new TestUser { UserName = "CurrentUser" }) context.For<IUser>("User", () => new TestUser { UserName = "CurrentUser" })
.Token("Name", u => u.UserName) .Token("Name", u => u.UserName)
.Token("Email", u => u.Email)
.Token("Birthdate", u => "Nov 15") .Token("Birthdate", u => "Nov 15")
.Chain("Birthdate", "DateTime", u => new DateTime(1978, 11, 15)); .Chain("Birthdate", "DateTime", u => new DateTime(1978, 11, 15));
@@ -45,6 +50,29 @@ namespace Orchard.Tokens.Tests {
context.For<DateTime>("DateTime") context.For<DateTime>("DateTime")
.Token((token, value) => value.ToString(token)); .Token((token, value) => value.ToString(token));
context.For<TestUser[]>("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<string, string>(token.Substring(tokenLength, chainIndex - tokenLength), token.Substring(chainIndex + 1));
else
return null;
},
"User",
(userName, users) => users.Where(u => u.UserName == userName).FirstOrDefault()
);
} }
} }

View File

@@ -29,10 +29,11 @@ namespace Orchard.Tokens.Tests {
[Test] [Test]
public void TestDescribe() { public void TestDescribe() {
var allTokens = _tokenManager.Describe(null); 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 == "Site"));
Assert.That(allTokens.Any(d => d.Target == "User")); Assert.That(allTokens.Any(d => d.Target == "User"));
Assert.That(allTokens.Any(d => d.Target == "Date")); 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; var tokens = allTokens.Single(d => d.Target == "Site").Tokens;
Assert.That(string.Join(",", tokens.Select(td => td.Target)), Is.EqualTo("Site,Site,Site,Site")); Assert.That(string.Join(",", tokens.Select(td => td.Target)), Is.EqualTo("Site,Site,Site,Site"));
@@ -59,7 +60,7 @@ namespace Orchard.Tokens.Tests {
[Test] [Test]
public void TestDescribeFilter() { public void TestDescribeFilter() {
var tokenDescriptors = _tokenManager.Describe(null); var tokenDescriptors = _tokenManager.Describe(null);
Assert.That(tokenDescriptors.Count(), Is.EqualTo(3)); Assert.That(tokenDescriptors.Count(), Is.EqualTo(4));
tokenDescriptors = _tokenManager.Describe(new[] { "Site" }); tokenDescriptors = _tokenManager.Describe(new[] { "Site" });
Assert.That(tokenDescriptors.Count(), Is.EqualTo(1)); Assert.That(tokenDescriptors.Count(), Is.EqualTo(1));
Assert.That(tokenDescriptors.First().Target, Is.EqualTo("Site")); Assert.That(tokenDescriptors.First().Target, Is.EqualTo("Site"));

View File

@@ -40,6 +40,18 @@ namespace Orchard.Tokens.Tests {
Assert.That(_tokenizer.Replace("{Site.CurrentUser.Birthdate.yyyy}", null), Is.EqualTo("1978")); 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] [Test]
public void TestMissingTokens() { public void TestMissingTokens() {
Assert.That(_tokenizer.Replace("[{Site.NotAToken}]", null), Is.EqualTo("[]")); Assert.That(_tokenizer.Replace("[{Site.NotAToken}]", null), Is.EqualTo("[]"));

View File

@@ -255,14 +255,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Layouts", "Orchard.
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.DynamicForms", "Orchard.Web\Modules\Orchard.DynamicForms\Orchard.DynamicForms.csproj", "{82190F52-2901-46D6-8A4C-34649959483F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.DynamicForms", "Orchard.Web\Modules\Orchard.DynamicForms\Orchard.DynamicForms.csproj", "{82190F52-2901-46D6-8A4C-34649959483F}"
EndProject 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}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF3909B0-1DDD-4D8A-9919-56FC438E25E2}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
Rebracer.xml = Rebracer.xml Rebracer.xml = Rebracer.xml
WebEssentials-Settings.json = WebEssentials-Settings.json WebEssentials-Settings.json = WebEssentials-Settings.json
EndProjectSection EndProjectSection
EndProject 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}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gulp", "Gulp", "{90EBEE36-B5CD-42A8-A21B-76270E2C5D24}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
Gulpfile.js = Gulpfile.js Gulpfile.js = Gulpfile.js

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Caching { namespace Orchard.Caching {
public class DefaultAsyncTokenProvider : IAsyncTokenProvider { public class DefaultAsyncTokenProvider : IAsyncTokenProvider {
@@ -37,9 +38,12 @@ namespace Orchard.Caching {
try { try {
_task(token => _taskTokens.Add(token)); _task(token => _taskTokens.Add(token));
} }
catch (Exception e) { catch (Exception ex) {
Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current."); if (ex.IsFatal()) {
_taskException = e; throw;
}
Logger.Error(ex, "Error while monitoring extension files. Assuming extensions are not current.");
_taskException = ex;
} }
finally { finally {
_isTaskFinished = true; _isTaskFinished = true;

View File

@@ -5,4 +5,17 @@ namespace Orchard.Caching {
TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire); TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
ICache<TKey, TResult> GetCache<TKey, TResult>(); ICache<TKey, TResult> GetCache<TKey, TResult>();
} }
public static class CacheManagerExtensions {
public static TResult Get<TKey, TResult>(this ICacheManager cacheManager, TKey key, bool lazy, Func<AcquireContext<TKey>, 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<TKey, Lazy<TResult>>(key, k => new Lazy<TResult>(() => acquire(k))).Value;
}
else {
return cacheManager.Get(key, acquire);
}
}
}
} }

View File

@@ -15,6 +15,7 @@ using Orchard.FileSystems.VirtualPath;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Tasks; using Orchard.Tasks;
using Orchard.Exceptions;
namespace Orchard.Commands { namespace Orchard.Commands {
@@ -94,19 +95,21 @@ namespace Orchard.Commands {
return CommandReturnCodes.Ok; return CommandReturnCodes.Ok;
} }
catch (OrchardCommandHostRetryException e) { catch (OrchardCommandHostRetryException ex) {
// Special "Retry" return code for our host // Special "Retry" return code for our host
output.WriteLine(T("{0} (Retrying...)", e.Message)); output.WriteLine(T("{0} (Retrying...)", ex.Message));
return CommandReturnCodes.Retry; return CommandReturnCodes.Retry;
} }
catch (Exception e) { catch (Exception ex) {
if (e is TargetInvocationException && if (ex.IsFatal()) {
e.InnerException != null) { throw;
// If this is an exception coming from reflection and there is an innerexception which is the actual one, redirect
e = e.InnerException;
} }
if (ex is TargetInvocationException &&
OutputException(output, T("Error executing command \"{0}\"", string.Join(" ", args)), e); 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; return CommandReturnCodes.Fail;
} }
} }
@@ -116,13 +119,16 @@ namespace Orchard.Commands {
_hostContainer = CreateHostContainer(); _hostContainer = CreateHostContainer();
return CommandReturnCodes.Ok; return CommandReturnCodes.Ok;
} }
catch (OrchardCommandHostRetryException e) { catch (OrchardCommandHostRetryException ex) {
// Special "Retry" return code for our host // Special "Retry" return code for our host
output.WriteLine(T("{0} (Retrying...)", e.Message)); output.WriteLine(T("{0} (Retrying...)", ex.Message));
return CommandReturnCodes.Retry; return CommandReturnCodes.Retry;
} }
catch (Exception e) { catch (Exception ex) {
OutputException(output, T("Error starting up Orchard command line host"), e); if (ex.IsFatal()) {
throw;
}
OutputException(output, T("Error starting up Orchard command line host"), ex);
return CommandReturnCodes.Fail; return CommandReturnCodes.Fail;
} }
} }
@@ -135,8 +141,11 @@ namespace Orchard.Commands {
} }
return CommandReturnCodes.Ok; return CommandReturnCodes.Ok;
} }
catch (Exception e) { catch (Exception ex) {
OutputException(output, T("Error shutting down Orchard command line host"), e); if (ex.IsFatal()) {
throw;
}
OutputException(output, T("Error shutting down Orchard command line host"), ex);
return CommandReturnCodes.Fail; return CommandReturnCodes.Fail;
} }
} }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Exceptions;
namespace Orchard.Commands { namespace Orchard.Commands {
public abstract class DefaultOrchardCommandHandler : ICommandHandler { public abstract class DefaultOrchardCommandHandler : ICommandHandler {
@@ -41,12 +42,15 @@ namespace Orchard.Commands {
object value = Convert.ChangeType(commandSwitch.Value, propertyInfo.PropertyType); object value = Convert.ChangeType(commandSwitch.Value, propertyInfo.PropertyType);
propertyInfo.SetValue(this, value, null/*index*/); 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}\"", string message = T("Error converting value \"{0}\" to \"{1}\" for switch \"{2}\"",
LocalizedString.TextOrDefault(commandSwitch.Value, T("(empty)")), LocalizedString.TextOrDefault(commandSwitch.Value, T("(empty)")),
propertyInfo.PropertyType.FullName, propertyInfo.PropertyType.FullName,
commandSwitch.Key).Text; commandSwitch.Key).Text;
throw new InvalidOperationException(message, e); throw new InvalidOperationException(message, ex);
} }
} }

View File

@@ -817,7 +817,7 @@ namespace Orchard.ContentManagement {
} }
private ContentTypeRecord AcquireContentTypeRecord(string contentType) { 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")); ctx.Monitor(_signals.When(contentType + "_Record"));
var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType); var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType);

View File

@@ -76,7 +76,7 @@ namespace Orchard.ContentManagement {
} }
private int GetContentTypeRecordId(string contentType) { private int GetContentTypeRecordId(string contentType) {
return _cacheManager.Get(contentType + "_Record", ctx => { return _cacheManager.Get(contentType + "_Record", true, ctx => {
ctx.Monitor(_signals.When(contentType + "_Record")); ctx.Monitor(_signals.When(contentType + "_Record"));
var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType); var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType);

View File

@@ -1,9 +1,13 @@
using System; using System;
using System.Linq; using System.Linq;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Migration.Schema;
using Orchard.Environment; using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Environment.Features; using Orchard.Environment.Features;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Tasks.Locking.Services; using Orchard.Tasks.Locking.Services;
using Orchard.Exceptions;
namespace Orchard.Data.Migration { namespace Orchard.Data.Migration {
/// <summary> /// <summary>
@@ -13,24 +17,35 @@ namespace Orchard.Data.Migration {
private readonly IDataMigrationManager _dataMigrationManager; private readonly IDataMigrationManager _dataMigrationManager;
private readonly IFeatureManager _featureManager; private readonly IFeatureManager _featureManager;
private readonly IDistributedLockService _distributedLockService; private readonly IDistributedLockService _distributedLockService;
private readonly IDataMigrationInterpreter _dataMigrationInterpreter;
private readonly ShellSettings _shellSettings;
private readonly ITransactionManager _transactionManager;
public AutomaticDataMigrations( public AutomaticDataMigrations(
IDataMigrationManager dataMigrationManager, IDataMigrationManager dataMigrationManager,
IDataMigrationInterpreter dataMigrationInterpreter,
IFeatureManager featureManager, IFeatureManager featureManager,
IDistributedLockService distributedLockService) { IDistributedLockService distributedLockService,
ITransactionManager transactionManager,
ShellSettings shellSettings) {
_dataMigrationManager = dataMigrationManager; _dataMigrationManager = dataMigrationManager;
_featureManager = featureManager; _featureManager = featureManager;
_distributedLockService = distributedLockService; _distributedLockService = distributedLockService;
_shellSettings = shellSettings;
_transactionManager = transactionManager;
_dataMigrationInterpreter = dataMigrationInterpreter;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
} }
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public void Activated() { public void Activated() {
EnsureDistributedLockSchemaExists();
IDistributedLock @lock; IDistributedLock @lock;
if(_distributedLockService.TryAcquireLock(GetType().FullName, TimeSpan.FromMinutes(30), TimeSpan.FromMilliseconds(250), out @lock)) { if (_distributedLockService.TryAcquireLock(GetType().FullName, TimeSpan.FromMinutes(30), TimeSpan.FromMilliseconds(250), out @lock)) {
using (@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. // 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.
var theseFeaturesShouldAlwaysBeActive = new[] { var theseFeaturesShouldAlwaysBeActive = new[] {
@@ -48,7 +63,10 @@ namespace Orchard.Data.Migration {
_dataMigrationManager.Update(feature); _dataMigrationManager.Update(feature);
} }
catch (Exception ex) { catch (Exception ex) {
Logger.Error(ex, "Could not run migrations automatically on {0}.", feature); if (ex.IsFatal()) {
throw;
}
Logger.Error("Could not run migrations automatically on " + feature, ex);
} }
} }
} }
@@ -58,5 +76,16 @@ namespace Orchard.Data.Migration {
public void Terminating() { public void Terminating() {
// No-op. // No-op.
} }
/// <summary>
/// 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.
/// </summary>
private void EnsureDistributedLockSchemaExists() {
// Ensure the distributed lock record schema exists.
var schemaBuilder = new SchemaBuilder(_dataMigrationInterpreter);
var distributedLockSchemaBuilder = new DistributedLockSchemaBuilder(_shellSettings, schemaBuilder);
if (distributedLockSchemaBuilder.EnsureSchema())
_transactionManager.RequireNew();
}
} }
} }

View File

@@ -9,6 +9,7 @@ using Orchard.Data.Migration.Schema;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Data.Migration { namespace Orchard.Data.Migration {
/// <summary> /// <summary>
@@ -123,6 +124,9 @@ namespace Orchard.Data.Migration {
current = (int)lookupTable[current].Invoke(migration, new object[0]); current = (int)lookupTable[current].Invoke(migration, new object[0]);
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}.", feature, current); Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}.", feature, current);
throw; throw;
} }
@@ -139,10 +143,13 @@ namespace Orchard.Data.Migration {
dataMigrationRecord.Version = current; dataMigrationRecord.Version = current;
} }
} }
catch (Exception e) { catch (Exception ex) {
Logger.Error(e, "Error while running migration version {0} for {1}.", current, feature); if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "Error while running migration version {0} for {1}.", current, feature);
_transactionManager.Cancel(); _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);
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using Orchard.Data.Migration.Interpreters; using Orchard.Data.Migration.Interpreters;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Exceptions;
namespace Orchard.Data.Migration.Schema { namespace Orchard.Data.Migration.Schema {
public class SchemaBuilder { public class SchemaBuilder {
@@ -72,6 +73,9 @@ namespace Orchard.Data.Migration.Schema {
Run(sqlStatmentCommand); Run(sqlStatmentCommand);
return this; return this;
} catch (Exception ex) { } 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 throw new OrchardException(T("An unexpected error occured while executing the SQL statement: {0}", sql), ex); // Add the sql to the nested exception information
} }
} }

View File

@@ -11,6 +11,7 @@ using Orchard.Environment.ShellBuilders.Models;
using Orchard.FileSystems.AppData; using Orchard.FileSystems.AppData;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Utility; using Orchard.Utility;
using Orchard.Exceptions;
namespace Orchard.Data { namespace Orchard.Data {
public class SessionConfigurationCache : ISessionConfigurationCache { public class SessionConfigurationCache : ISessionConfigurationCache {
@@ -80,11 +81,11 @@ namespace Orchard.Data {
formatter.Serialize(stream, cache.Configuration); formatter.Serialize(stream, cache.Configuration);
} }
} }
catch (SerializationException e) { catch (SerializationException ex) {
//Note: This can happen when multiple processes/AppDomains try to save //Note: This can happen when multiple processes/AppDomains try to save
// the cached configuration at the same time. Only one concurrent // the cached configuration at the same time. Only one concurrent
// writer will win, and it's harmless for the other ones to fail. // 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); Logger.Warning("Error storing new NHibernate cache configuration: {0}", scan.Message);
} }
} }
@@ -118,8 +119,11 @@ namespace Orchard.Data {
}; };
} }
} }
catch (Exception e) { catch (Exception ex) {
for (var scan = e; scan != null; scan = scan.InnerException) 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.Warning("Error reading the cached NHibernate configuration: {0}", scan.Message);
Logger.Information("A new one will be re-generated."); Logger.Information("A new one will be re-generated.");
return null; return null;

View File

@@ -37,7 +37,7 @@ namespace Orchard.DisplayManagement.Descriptors {
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public ShapeTable GetShapeTable(string themeName) { public ShapeTable GetShapeTable(string themeName) {
return _cacheManager.Get(themeName ?? "", x => { return _cacheManager.Get(themeName ?? "", true, x => {
Logger.Information("Start building shape table"); Logger.Information("Start building shape table");
var alterationSets = _parallelCacheContext.RunInParallel(_bindingStrategies, bindingStrategy => { var alterationSets = _parallelCacheContext.RunInParallel(_bindingStrategies, bindingStrategy => {

View File

@@ -30,7 +30,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
public bool DisableMonitoring { get; set; } public bool DisableMonitoring { get; set; }
public PlacementFile Parse(string virtualPath) { public PlacementFile Parse(string virtualPath) {
return _cacheManager.Get(virtualPath, context => { return _cacheManager.Get(virtualPath, true, context => {
if (!DisableMonitoring) { if (!DisableMonitoring) {
Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath); Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath);

View File

@@ -77,7 +77,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => { var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => {
var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/'); var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
var virtualPath = Path.Combine(basePath, subPath).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)) if (!_virtualPathProvider.DirectoryExists(virtualPath))
return new List<string>(); return new List<string>();

View File

@@ -14,6 +14,7 @@ using Orchard.Logging;
using Orchard.Mvc; using Orchard.Mvc;
using Orchard.Mvc.Extensions; using Orchard.Mvc.Extensions;
using Orchard.Utility.Extensions; using Orchard.Utility.Extensions;
using Orchard.Exceptions;
namespace Orchard.Environment { namespace Orchard.Environment {
// All the event handlers that DefaultOrchardHost implements have to be declared in OrchardStarter. // All the event handlers that DefaultOrchardHost implements have to be declared in OrchardStarter.
@@ -145,8 +146,11 @@ namespace Orchard.Environment {
var context = CreateShellContext(settings, StandaloneEnvironmentOptions.None); var context = CreateShellContext(settings, StandaloneEnvironmentOptions.None);
ActivateShell(context); ActivateShell(context);
} }
catch (Exception e) { catch (Exception ex) {
Logger.Error(e, "A tenant could not be started: " + settings.Name); if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "A tenant could not be started: " + settings.Name);
} }
while (_processingEngine.AreTasksPending()) { while (_processingEngine.AreTasksPending()) {
Logger.Debug("Processing pending task after activate Shell"); Logger.Debug("Processing pending task after activate Shell");

View File

@@ -11,6 +11,7 @@ using Orchard.Owin;
using Orchard.Tasks; using Orchard.Tasks;
using Orchard.UI; using Orchard.UI;
using Orchard.WebApi.Routes; using Orchard.WebApi.Routes;
using Orchard.Exceptions;
using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider; using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider;
namespace Orchard.Environment { namespace Orchard.Environment {
@@ -98,8 +99,12 @@ namespace Orchard.Environment {
try { try {
action(); action();
} }
catch(Exception e) { catch(Exception ex) {
Logger.Error(e, "An unexcepted error occured while terminating the Shell"); if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "An unexcepted error occured while terminating the Shell");
} }
} }
} }

View File

@@ -8,6 +8,7 @@ using Orchard.FileSystems.Dependencies;
using Orchard.FileSystems.VirtualPath; using Orchard.FileSystems.VirtualPath;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Environment.Extensions.Compilers { namespace Orchard.Environment.Extensions.Compilers {
/// <summary> /// <summary>
@@ -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 //Note: we need to embed the "e.Message" in the exception text because
// ASP.NET build manager "swallows" inner exceptions from this method. // 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);
} }
} }

View File

@@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Compilers {
public bool DisableMonitoring { get; set; } public bool DisableMonitoring { get; set; }
public ProjectFileDescriptor Parse(string virtualPath) { public ProjectFileDescriptor Parse(string virtualPath) {
return _cacheManager.Get(virtualPath, return _cacheManager.Get(virtualPath, true,
ctx => { ctx => {
if (!DisableMonitoring) { if (!DisableMonitoring) {
Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath); Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath);

View File

@@ -9,6 +9,7 @@ using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Utility; using Orchard.Utility;
using Orchard.Utility.Extensions; using Orchard.Utility.Extensions;
using Orchard.Exceptions;
namespace Orchard.Environment.Extensions { namespace Orchard.Environment.Extensions {
public class ExtensionManager : IExtensionManager { public class ExtensionManager : IExtensionManager {
@@ -44,7 +45,7 @@ namespace Orchard.Environment.Extensions {
} }
public IEnumerable<ExtensionDescriptor> AvailableExtensions() { public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
return _cacheManager.Get("AvailableExtensions", ctx => return _cacheManager.Get("AvailableExtensions", true, ctx =>
_parallelCacheContext _parallelCacheContext
.RunInParallel(_folders, folder => folder.AvailableExtensions().ToList()) .RunInParallel(_folders, folder => folder.AvailableExtensions().ToList())
.SelectMany(descriptors => descriptors) .SelectMany(descriptors => descriptors)
@@ -52,7 +53,7 @@ namespace Orchard.Environment.Extensions {
} }
public IEnumerable<FeatureDescriptor> AvailableFeatures() { public IEnumerable<FeatureDescriptor> AvailableFeatures() {
return _cacheManager.Get("AvailableFeatures", ctx => return _cacheManager.Get("AvailableFeatures", true, ctx =>
AvailableExtensions() AvailableExtensions()
.SelectMany(ext => ext.Features) .SelectMany(ext => ext.Features)
.OrderByDependenciesAndPriorities(HasDependency, GetPriority) .OrderByDependenciesAndPriorities(HasDependency, GetPriority)
@@ -92,7 +93,7 @@ namespace Orchard.Environment.Extensions {
var result = var result =
_parallelCacheContext _parallelCacheContext
.RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, ctx => LoadFeature(descriptor))) .RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, true, ctx => LoadFeature(descriptor)))
.ToArray(); .ToArray();
Logger.Information("Done loading features"); Logger.Information("Done loading features");
@@ -106,7 +107,7 @@ namespace Orchard.Environment.Extensions {
ExtensionEntry extensionEntry; ExtensionEntry extensionEntry;
try { try {
extensionEntry = _cacheManager.Get(extensionId, ctx => { extensionEntry = _cacheManager.Get(extensionId, true, ctx => {
var entry = BuildEntry(extensionDescriptor); var entry = BuildEntry(extensionDescriptor);
if (entry != null) { if (entry != null) {
ctx.Monitor(_asyncTokenProvider.GetToken(monitor => { ctx.Monitor(_asyncTokenProvider.GetToken(monitor => {
@@ -119,6 +120,9 @@ namespace Orchard.Environment.Extensions {
}); });
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "Error loading extension '{0}'", extensionId); Logger.Error(ex, "Error loading extension '{0}'", extensionId);
throw new OrchardException(T("Error while loading extension '{0}'.", extensionId), ex); throw new OrchardException(T("Error while loading extension '{0}'.", extensionId), ex);
} }

View File

@@ -9,6 +9,7 @@ using Orchard.FileSystems.WebSite;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Utility.Extensions; using Orchard.Utility.Extensions;
using Orchard.Exceptions;
namespace Orchard.Environment.Extensions.Folders { namespace Orchard.Environment.Extensions.Folders {
public class ExtensionHarvester : IExtensionHarvester { public class ExtensionHarvester : IExtensionHarvester {
@@ -57,7 +58,7 @@ namespace Orchard.Environment.Extensions.Folders {
private IEnumerable<ExtensionDescriptor> HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) { private IEnumerable<ExtensionDescriptor> HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) {
string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType); string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType);
return _cacheManager.Get(key, ctx => { return _cacheManager.Get(key, true, ctx => {
if (!DisableMonitoring) { if (!DisableMonitoring) {
Logger.Debug("Monitoring virtual path \"{0}\"", path); Logger.Debug("Monitoring virtual path \"{0}\"", path);
ctx.Monitor(_webSiteFolder.WhenPathChanges(path)); ctx.Monitor(_webSiteFolder.WhenPathChanges(path));
@@ -100,6 +101,9 @@ namespace Orchard.Environment.Extensions.Folders {
} }
catch (Exception ex) { catch (Exception ex) {
// Ignore invalid module manifests // Ignore invalid module manifests
if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "The module '{0}' could not be loaded. It was ignored.", extensionId); 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)); _criticalErrorProvider.RegisterErrorMessage(T("The extension '{0}' manifest could not be loaded. It was ignored.", extensionId));
} }
@@ -134,7 +138,7 @@ namespace Orchard.Environment.Extensions.Folders {
} }
private ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionId, string extensionType, string manifestPath, bool manifestIsOptional) { 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) { if (!DisableMonitoring) {
Logger.Debug("Monitoring virtual path \"{0}\"", manifestPath); Logger.Debug("Monitoring virtual path \"{0}\"", manifestPath);
context.Monitor(_webSiteFolder.WhenPathChanges(manifestPath)); context.Monitor(_webSiteFolder.WhenPathChanges(manifestPath));

View File

@@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Environment { namespace Orchard.Environment {
public interface IAssemblyLoader { public interface IAssemblyLoader {
@@ -25,8 +27,11 @@ namespace Orchard.Environment {
try { try {
return _loadedAssemblies.GetOrAdd(this.ExtractAssemblyShortName(assemblyName), shortName => LoadWorker(shortName, assemblyName)); return _loadedAssemblies.GetOrAdd(this.ExtractAssemblyShortName(assemblyName), shortName => LoadWorker(shortName, assemblyName));
} }
catch (Exception e) { catch (Exception ex) {
Logger.Error(e, "Error loading assembly '{0}'", assemblyName); if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "Error loading assembly '{0}'", assemblyName);
return null; return null;
} }
} }

View File

@@ -37,7 +37,7 @@ namespace Orchard.Environment {
public string Resolve(string shortName) { public string Resolve(string shortName) {
// A few common .net framework assemblies are referenced by the Orchard.Framework assembly. // 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. // 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 ctx.Key.Assembly
.GetReferencedAssemblies() .GetReferencedAssemblies()
.GroupBy(n => AssemblyLoaderExtensions.ExtractAssemblyShortName(n.FullName), StringComparer.OrdinalIgnoreCase) .GroupBy(n => AssemblyLoaderExtensions.ExtractAssemblyShortName(n.FullName), StringComparer.OrdinalIgnoreCase)

View File

@@ -53,8 +53,9 @@ namespace Orchard.Environment {
return BuildManager.GetCompiledAssembly(virtualPath); return BuildManager.GetCompiledAssembly(virtualPath);
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) throw; if (ex.IsFatal()) {
throw;
}
Logger.Warning(ex, "Error when compiling assembly under {0}.", virtualPath); Logger.Warning(ex, "Error when compiling assembly under {0}.", virtualPath);
return null; return null;
} }

View File

@@ -5,6 +5,7 @@ using Orchard.Environment.Descriptor;
using Orchard.Environment.Descriptor.Models; using Orchard.Environment.Descriptor.Models;
using Orchard.FileSystems.AppData; using Orchard.FileSystems.AppData;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Environment { namespace Orchard.Environment {
public interface IHostLocalRestart { public interface IHostLocalRestart {
@@ -45,8 +46,11 @@ namespace Orchard.Environment {
try { try {
_appDataFolder.CreateFile(fileName, "Host Restart"); _appDataFolder.CreateFile(fileName, "Host Restart");
} }
catch(Exception e) { catch(Exception ex) {
Logger.Warning(e, "Error updating file '{0}'", fileName); if (ex.IsFatal()) {
throw;
}
Logger.Warning(ex, "Error updating file '{0}'", fileName);
} }
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Timers;
using System.Web.Compilation; using System.Web.Compilation;
using Orchard.FileSystems.VirtualPath; using Orchard.FileSystems.VirtualPath;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Environment { namespace Orchard.Environment {
public interface IViewsBackgroundCompilation { public interface IViewsBackgroundCompilation {
@@ -136,10 +137,13 @@ namespace Orchard.Environment {
if (firstFile != null) if (firstFile != null)
BuildManager.GetCompiledAssembly(firstFile); 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 // Some views might not compile, this is ok and harmless in this
// context of pre-compiling views. // 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(); stopwatch.Stop();
Logger.Information("Directory '{0}' compiled in {1} msec", viewDirectory, stopwatch.ElapsedMilliseconds); Logger.Information("Directory '{0}' compiled in {1} msec", viewDirectory, stopwatch.ElapsedMilliseconds);

View File

@@ -53,6 +53,9 @@ namespace Orchard.Events {
return TryInvoke(eventHandler, messageName, interfaceName, methodName, eventData, out returnValue); return TryInvoke(eventHandler, messageName, interfaceName, methodName, eventData, out returnValue);
} }
catch (Exception exception) { catch (Exception exception) {
if (exception.IsFatal()) {
throw;
}
if (!_exceptionPolicy.HandleException(this, exception)) { if (!_exceptionPolicy.HandleException(this, exception)) {
throw; throw;
} }

View File

@@ -7,6 +7,7 @@ using Orchard.FileSystems.VirtualPath;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Validation; using Orchard.Validation;
using Orchard.Exceptions;
namespace Orchard.FileSystems.AppData { namespace Orchard.FileSystems.AppData {
public class AppDataFolder : IAppDataFolder { public class AppDataFolder : IAppDataFolder {
@@ -78,8 +79,11 @@ namespace Orchard.FileSystems.AppData {
try { try {
File.Delete(destinationFileName); File.Delete(destinationFileName);
} }
catch (Exception e) { catch (Exception ex) {
throw new OrchardCoreException(T("Unable to make room for file \"{0}\" in \"App_Data\" folder", destinationFileName), e); if (ex.IsFatal()) {
throw;
}
throw new OrchardCoreException(T("Unable to make room for file \"{0}\" in \"App_Data\" folder", destinationFileName), ex);
} }
} }

View File

@@ -34,7 +34,7 @@ namespace Orchard.FileSystems.Dependencies {
} }
public IEnumerable<DependencyDescriptor> LoadDescriptors() { public IEnumerable<DependencyDescriptor> LoadDescriptors() {
return _cacheManager.Get(PersistencePath, return _cacheManager.Get(PersistencePath, true,
ctx => { ctx => {
_appDataFolder.CreateDirectory(BasePath); _appDataFolder.CreateDirectory(BasePath);

View File

@@ -5,6 +5,7 @@ using System.Xml.Linq;
using Orchard.Caching; using Orchard.Caching;
using Orchard.FileSystems.AppData; using Orchard.FileSystems.AppData;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.FileSystems.Dependencies { namespace Orchard.FileSystems.Dependencies {
/// <summary> /// <summary>
@@ -64,7 +65,7 @@ namespace Orchard.FileSystems.Dependencies {
} }
public IEnumerable<ActivatedExtensionDescriptor> LoadDescriptors() { public IEnumerable<ActivatedExtensionDescriptor> LoadDescriptors() {
return _cacheManager.Get(PersistencePath, ctx => { return _cacheManager.Get(PersistencePath, true, ctx => {
_appDataFolder.CreateDirectory(BasePath); _appDataFolder.CreateDirectory(BasePath);
if (!DisableMonitoring) { if (!DisableMonitoring) {
@@ -135,8 +136,11 @@ namespace Orchard.FileSystems.Dependencies {
return XDocument.Load(stream); return XDocument.Load(stream);
} }
} }
catch (Exception e) { catch (Exception ex) {
Logger.Information(e, "Error reading file '{0}'. Assuming empty.", persistancePath); if (ex.IsFatal()) {
throw;
}
Logger.Information(ex, "Error reading file '{0}'. Assuming empty.", persistancePath);
return new XDocument(); return new XDocument();
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Web.Hosting;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Validation; using Orchard.Validation;
using Orchard.Exceptions;
namespace Orchard.FileSystems.Media { namespace Orchard.FileSystems.Media {
public class FileSystemStorageProvider : IStorageProvider { public class FileSystemStorageProvider : IStorageProvider {
@@ -155,6 +156,9 @@ namespace Orchard.FileSystems.Media {
directoryInfo.Create(); directoryInfo.Create();
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
throw new ArgumentException(T("The folder could not be created at path: {0}. {1}", path, ex).ToString()); throw new ArgumentException(T("The folder could not be created at path: {0}. {1}", path, ex).ToString());
} }
} }

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Web; using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.FileSystems.VirtualPath { namespace Orchard.FileSystems.VirtualPath {
public class DefaultVirtualPathProvider : IVirtualPathProvider { public class DefaultVirtualPathProvider : IVirtualPathProvider {
@@ -59,9 +60,12 @@ namespace Orchard.FileSystems.VirtualPath {
} }
return result; 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) // 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; return null;
} }
} }
@@ -156,8 +160,11 @@ namespace Orchard.FileSystems.VirtualPath {
try { try {
return FileExists(virtualPath); return FileExists(virtualPath);
} }
catch (Exception e) { catch (Exception ex) {
Logger.Information(e, "File '{0}' can not be checked for existence. Assuming doesn't exist.", virtualPath); if (ex.IsFatal()) {
throw;
}
Logger.Information(ex, "File '{0}' can not be checked for existence. Assuming doesn't exist.", virtualPath);
return false; return false;
} }
} }

View File

@@ -26,7 +26,7 @@ namespace Orchard.Localization.Services {
} }
public IEnumerable<string> ListCultures() { public IEnumerable<string> ListCultures() {
return _cacheManager.Get("Cultures", context => { return _cacheManager.Get("Cultures", true, context => {
context.Monitor(_signals.When("culturesChanged")); context.Monitor(_signals.When("culturesChanged"));
return _cultureRepository.Table.Select(o => o.Culture).ToList(); return _cultureRepository.Table.Select(o => o.Culture).ToList();

View File

@@ -90,7 +90,7 @@ namespace Orchard.Localization.Services {
// Cache entry will be invalidated any time the directories hosting // Cache entry will be invalidated any time the directories hosting
// the .po files are modified. // the .po files are modified.
private CultureDictionary LoadCulture(string culture) { private CultureDictionary LoadCulture(string culture) {
return _cacheManager.Get(culture, ctx => { return _cacheManager.Get(culture, true, ctx => {
ctx.Monitor(_signals.When("culturesChanged")); ctx.Monitor(_signals.When("culturesChanged"));
return new CultureDictionary { return new CultureDictionary {
CultureName = culture, CultureName = culture,

View File

@@ -5,6 +5,7 @@ using Orchard.Logging;
using Orchard.Messaging.Events; using Orchard.Messaging.Events;
using Orchard.Messaging.Models; using Orchard.Messaging.Models;
using Orchard.ContentManagement.Records; using Orchard.ContentManagement.Records;
using Orchard.Exceptions;
namespace Orchard.Messaging.Services { namespace Orchard.Messaging.Services {
[Obsolete] [Obsolete]
@@ -40,8 +41,11 @@ namespace Orchard.Messaging.Services {
PrepareAndSend(type, properties, context); PrepareAndSend(type, properties, context);
} }
catch ( Exception e ) { catch (Exception ex) {
Logger.Error(e, "An error occured while sending the message {0}", type); 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); PrepareAndSend(type, properties, context);
} }
catch (Exception e) { catch (Exception ex) {
Logger.Error(e, "An error occured while sending the message {0}", type); if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "An error occured while sending the message {0}", type);
} }
} }

View File

@@ -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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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<string, object> 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;
}
}
}

View File

@@ -11,6 +11,7 @@ using System.Web.Routing;
using Autofac; using Autofac;
using Orchard.Mvc.Routes; using Orchard.Mvc.Routes;
using Orchard.Settings; using Orchard.Settings;
using Orchard.Exceptions;
namespace Orchard.Mvc { namespace Orchard.Mvc {
public class MvcModule : Module { public class MvcModule : Module {
@@ -31,7 +32,11 @@ namespace Orchard.Mvc {
// The "Request" property throws at application startup on IIS integrated pipeline mode. // The "Request" property throws at application startup on IIS integrated pipeline mode.
var req = HttpContext.Current.Request; var req = HttpContext.Current.Request;
} }
catch (Exception) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
return false; return false;
} }

View File

@@ -188,6 +188,7 @@
<Compile Include="Security\IMembershipValidationService.cs" /> <Compile Include="Security\IMembershipValidationService.cs" />
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" /> <Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
<Compile Include="Localization\Services\LocalizationStreamParser.cs" /> <Compile Include="Localization\Services\LocalizationStreamParser.cs" />
<Compile Include="Mvc\Html\LinkExtensions.cs" />
<Compile Include="Security\ISslSettingsProvider.cs" /> <Compile Include="Security\ISslSettingsProvider.cs" />
<Compile Include="Security\NullMembershipService.cs" /> <Compile Include="Security\NullMembershipService.cs" />
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" /> <Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
@@ -401,7 +402,7 @@
<Compile Include="Services\IJsonConverter.cs" /> <Compile Include="Services\IJsonConverter.cs" />
<Compile Include="Settings\CurrentSiteWorkContext.cs" /> <Compile Include="Settings\CurrentSiteWorkContext.cs" />
<Compile Include="Settings\ResourceDebugMode.cs" /> <Compile Include="Settings\ResourceDebugMode.cs" />
<Compile Include="Tasks\Locking\Migrations\FrameworkMigrations.cs" /> <Compile Include="Tasks\Locking\Services\DistributedLockSchemaBuilder.cs" />
<Compile Include="Tasks\Locking\Services\IDistributedLock.cs" /> <Compile Include="Tasks\Locking\Services\IDistributedLock.cs" />
<Compile Include="Tasks\Locking\Services\DistributedLock.cs" /> <Compile Include="Tasks\Locking\Services\DistributedLock.cs" />
<Compile Include="Tasks\Locking\Services\IDistributedLockService.cs" /> <Compile Include="Tasks\Locking\Services\IDistributedLockService.cs" />

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Orchard.Data; using Orchard.Data;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Tasks { namespace Orchard.Tasks {
@@ -39,9 +40,13 @@ namespace Orchard.Tasks {
task.Sweep(); task.Sweep();
Logger.Information("Finished processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName); Logger.Information("Finished processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName);
} }
catch (Exception e) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
_transactionManager.Cancel(); _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);
} }
} }
} }

View File

@@ -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<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("Name", column => column.NotNull().WithLength(512).Unique())
.Column<string>("MachineName", column => column.WithLength(256))
.Column<DateTime>("CreatedUtc")
.Column<DateTime>("ValidUntilUtc", column => column.Nullable()));
SchemaBuilder.AlterTable("DistributedLockRecord", table => {
table.CreateIndex("IDX_DistributedLockRecord_Name", "Name");
});
return 1;
}
}
}

View File

@@ -0,0 +1,48 @@
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 bool EnsureSchema() {
if (SchemaExists())
return false;
CreateSchema();
return true;
}
public void CreateSchema() {
_schemaBuilder.CreateTable(TableName, table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("Name", column => column.NotNull().WithLength(512).Unique())
.Column<string>("MachineName", column => column.WithLength(256))
.Column<DateTime>("CreatedUtc")
.Column<DateTime>("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;
}
}
}
}

View File

@@ -44,30 +44,30 @@ namespace Orchard.Tasks.Locking.Services {
if (dLock != null) { if (dLock != null) {
Logger.Debug("Successfully acquired lock '{0}'.", name); Logger.Debug("Successfully acquired lock '{0}'.", name);
return true; return true;
} }
Logger.Warning("Failed to acquire lock '{0}' within the specified timeout ({1}).", name, timeout); Logger.Warning("Failed to acquire lock '{0}' within the specified timeout ({1}).", name, timeout);
} }
catch (Exception ex) { catch (Exception ex) {
Logger.Error(ex, "Error while trying to acquire lock '{0}'.", name); Logger.Error(ex, "Error while trying to acquire lock '{0}'.", name);
// TODO: Is it correct to not throw here? Should we instead ONLY swallow TimeoutException? // TODO: Is it correct to not throw here? Should we instead ONLY swallow TimeoutException?
} }
dLock = null; dLock = null;
return false; return false;
} }
public IDistributedLock AcquireLock(string name, TimeSpan? maxValidFor, TimeSpan? timeout) { public IDistributedLock AcquireLock(string name, TimeSpan? maxValidFor, TimeSpan? timeout) {
try { try {
DistributedLock result = AcquireLockInternal(name, maxValidFor, timeout, throwOnTimeout: true); DistributedLock result = AcquireLockInternal(name, maxValidFor, timeout, throwOnTimeout: true);
Logger.Debug("Successfully acquired lock '{0}'.", name); Logger.Debug("Successfully acquired lock '{0}'.", name);
return result; return result;
} }
catch (Exception ex) { catch (Exception ex) {
Logger.Error(ex, "Error while trying to acquire lock '{0}'.", name); Logger.Error(ex, "Error while trying to acquire lock '{0}'.", name);
throw; throw;
} }
} }
private DistributedLock AcquireLockInternal(string name, TimeSpan? maxValidFor, TimeSpan? timeout, bool throwOnTimeout) { private DistributedLock AcquireLockInternal(string name, TimeSpan? maxValidFor, TimeSpan? timeout, bool throwOnTimeout) {
var internalName = GetInternalLockName(name); var internalName = GetInternalLockName(name);
@@ -81,7 +81,7 @@ namespace Orchard.Tasks.Locking.Services {
throw new TimeoutException(String.Format("Failed to acquire lock '{0}' within the specified timeout ({1}).", internalName, timeout)); throw new TimeoutException(String.Format("Failed to acquire lock '{0}' within the specified timeout ({1}).", internalName, timeout));
return null; return null;
} }
Logger.Debug("Successfully entered local monitor for lock '{0}'.", internalName); Logger.Debug("Successfully entered local monitor for lock '{0}'.", internalName);
@@ -106,34 +106,34 @@ namespace Orchard.Tasks.Locking.Services {
dLock = new DistributedLock(name, internalName, releaseLockAction: () => { dLock = new DistributedLock(name, internalName, releaseLockAction: () => {
Monitor.Exit(monitorObj); Monitor.Exit(monitorObj);
DeleteDistributedLockRecord(internalName); DeleteDistributedLockRecord(internalName);
}); });
_locks.Add(monitorObj, dLock); _locks.Add(monitorObj, dLock);
return true; return true;
} }
return false; return false;
}); });
if (!success) { if (!success) {
Logger.Debug("Record for lock '{0}' could not be created for current machine within the specified timeout ({1}).", internalName, timeout); Logger.Debug("Record for lock '{0}' could not be created for current machine within the specified timeout ({1}).", internalName, timeout);
if (throwOnTimeout) if (throwOnTimeout)
throw new TimeoutException(String.Format("Failed to acquire lock '{0}' within the specified timeout ({1}).", internalName, timeout)); throw new TimeoutException(String.Format("Failed to acquire lock '{0}' within the specified timeout ({1}).", internalName, timeout));
return null; return null;
} }
} }
return dLock; return dLock;
} }
catch (Exception ex) { catch (Exception ex) {
Monitor.Exit(monitorObj); Monitor.Exit(monitorObj);
Logger.Error(ex, "An error occurred while trying to acquire lock '{0}'.", internalName); Logger.Error(ex, "An error occurred while trying to acquire lock '{0}'.", internalName);
throw; throw;
} }
} }
private bool EnsureDistributedLockRecord(string internalName, TimeSpan? maxValidFor) { private bool EnsureDistributedLockRecord(string internalName, TimeSpan? maxValidFor) {
var localMachineName = _machineNameProvider.GetMachineName(); var localMachineName = _machineNameProvider.GetMachineName();
@@ -145,7 +145,7 @@ namespace Orchard.Tasks.Locking.Services {
if (record == null) { if (record == null) {
// No record existed, so we're good to create a new one. // No record existed, so we're good to create a new one.
Logger.Debug("No valid record was found for lock '{0}'; creating a new record.", internalName); Logger.Debug("No valid record was found for lock '{0}'; creating a new record.", internalName);
repository.Create(new DistributedLockRecord { repository.Create(new DistributedLockRecord {
Name = internalName, Name = internalName,
MachineName = localMachineName, MachineName = localMachineName,
@@ -163,7 +163,7 @@ namespace Orchard.Tasks.Locking.Services {
}); });
return hasLockRecord; return hasLockRecord;
} }
private void DeleteDistributedLockRecord(string internalName) { private void DeleteDistributedLockRecord(string internalName) {
try { try {
@@ -177,9 +177,9 @@ namespace Orchard.Tasks.Locking.Services {
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) if (ex.IsFatal())
throw; throw;
Logger.Warning(ex, "An error occurred while deleting record for lock '{0}'.", internalName); Logger.Warning(ex, "An error occurred while deleting record for lock '{0}'.", internalName);
} }
} }
private bool RepeatUntilTimeout(TimeSpan? timeout, TimeSpan repeatInterval, Func<bool> action) { private bool RepeatUntilTimeout(TimeSpan? timeout, TimeSpan repeatInterval, Func<bool> action) {
@@ -198,14 +198,14 @@ namespace Orchard.Tasks.Locking.Services {
if (action == null) if (action == null)
throw new ArgumentNullException(); throw new ArgumentNullException();
using (var childLifetimeScope = _lifetimeScope.BeginLifetimeScope()) { using (var childLifetimeScope = _lifetimeScope.BeginLifetimeScope()) {
var repository = childLifetimeScope.Resolve<IRepository<DistributedLockRecord>>(); var repository = childLifetimeScope.Resolve<IRepository<DistributedLockRecord>>();
var transactionManager = childLifetimeScope.Resolve<ITransactionManager>(); var transactionManager = childLifetimeScope.Resolve<ITransactionManager>();
transactionManager.RequireNew(IsolationLevel.ReadCommitted); transactionManager.RequireNew(IsolationLevel.ReadCommitted);
action(repository); action(repository);
}
} }
}
private string GetInternalLockName(string name) { private string GetInternalLockName(string name) {
// Prefix the requested lock name by a constant and the tenant name. // Prefix the requested lock name by a constant and the tenant name.
return String.Format("DistributedLock:{0}:{1}", _shellSettings.Name, name); return String.Format("DistributedLock:{0}:{1}", _shellSettings.Name, name);

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Timers; using System.Timers;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Tasks { namespace Orchard.Tasks {
@@ -51,6 +52,10 @@ namespace Orchard.Tasks {
} }
} }
catch (Exception ex) { catch (Exception ex) {
if (ex.IsFatal()) {
throw;
}
Logger.Warning(ex, "Problem in background tasks"); Logger.Warning(ex, "Problem in background tasks");
} }
finally { finally {

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Web; using System.Web;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Exceptions;
namespace Orchard.Time { namespace Orchard.Time {
/// <summary> /// <summary>
@@ -31,8 +32,11 @@ namespace Orchard.Time {
TimeZone = TimeZoneInfo.FindSystemTimeZoneById(siteTimeZoneId) TimeZone = TimeZoneInfo.FindSystemTimeZoneById(siteTimeZoneId)
}; };
} }
catch(Exception e) { catch(Exception ex) {
Logger.Error(e, "TimeZone could not be loaded"); if (ex.IsFatal()) {
throw;
}
Logger.Error(ex, "TimeZone could not be loaded");
// if the database could not be updated in time, ignore this provider // if the database could not be updated in time, ignore this provider
return null; return null;

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using Orchard.Logging; using Orchard.Logging;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using Orchard.Exceptions;
namespace Orchard.UI.Admin.Notification { namespace Orchard.UI.Admin.Notification {
public class NotificationManager : INotificationManager { public class NotificationManager : INotificationManager {
@@ -22,8 +23,11 @@ namespace Orchard.UI.Admin.Notification {
try { try {
return n.GetNotifications(); return n.GetNotifications();
} }
catch(Exception e) { catch(Exception ex) {
Logger.Error("An unhandled exception was thrown while generating a notification: " + n.GetType(), e); if (ex.IsFatal()) {
throw;
}
Logger.Error("An unhandled exception was thrown while generating a notification: " + n.GetType(), ex);
return Enumerable.Empty<NotifyEntry>(); return Enumerable.Empty<NotifyEntry>();
} }
}).ToList(); }).ToList();

View File

@@ -16,8 +16,7 @@ namespace Orchard.Utility.Extensions {
var sb = new StringBuilder(camel); var sb = new StringBuilder(camel);
for (int i = camel.Length-1; i>0; i--) { for (int i = camel.Length-1; i>0; i--) {
var current = sb[i]; if(char.IsUpper(sb[i])) {
if('A' <= current && current <= 'Z') {
sb.Insert(i, ' '); sb.Insert(i, ' ');
} }
} }
@@ -357,4 +356,4 @@ namespace Orchard.Utility.Extensions {
return Encoding.UTF8.GetString(Convert.FromBase64String(value)); return Encoding.UTF8.GetString(Convert.FromBase64String(value));
} }
} }
} }

View File

@@ -16,7 +16,8 @@
"gulp-uglify": "^1.2.0", "gulp-uglify": "^1.2.0",
"gulp-rename": "^1.2.2", "gulp-rename": "^1.2.2",
"gulp-concat": "^2.5.2", "gulp-concat": "^2.5.2",
"gulp-header": "^1.2.2" "gulp-header": "^1.2.2",
"fs": "^0.0.2"
}, },
"dependencies": { } "dependencies": { }
} }