mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Merge remote-tracking branch 'origin/dev' into feature/tenantstateinitializing
This commit is contained in:
@@ -13,7 +13,8 @@ var glob = require("glob"),
|
||||
uglify = require("gulp-uglify"),
|
||||
rename = require("gulp-rename"),
|
||||
concat = require("gulp-concat"),
|
||||
header = require("gulp-header");
|
||||
header = require("gulp-header"),
|
||||
fs = require("fs");
|
||||
|
||||
/*
|
||||
** GULP TASKS
|
||||
@@ -37,32 +38,53 @@ gulp.task("rebuild", function () {
|
||||
return merge(assetGroupTasks);
|
||||
});
|
||||
|
||||
// Continuous watch (each asset group is built whenever one of its inputs changes).
|
||||
|
||||
// Set "Watchers" as sub-processes in order to restart the task when Assets.json changes.
|
||||
gulp.task("watch", function () {
|
||||
var pathWin32 = require("path");
|
||||
getAssetGroups().forEach(function (assetGroup) {
|
||||
var watchPaths = assetGroup.inputPaths.concat(assetGroup.watchPaths);
|
||||
gulp.watch(watchPaths, function (event) {
|
||||
var isConcat = path.basename(assetGroup.outputFileName, path.extname(assetGroup.outputFileName)) !== "@";
|
||||
if (isConcat)
|
||||
console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group with output '" + assetGroup.outputPath + "'.");
|
||||
else
|
||||
console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group.");
|
||||
var doRebuild = true;
|
||||
var task = createAssetGroupTask(assetGroup, doRebuild);
|
||||
var watchers;
|
||||
function restart() {
|
||||
if (watchers) {
|
||||
watchers.forEach(function (w) {
|
||||
w.remove();
|
||||
w.end();
|
||||
});
|
||||
}
|
||||
watchers = [];
|
||||
// Continuous watch (each asset group is built whenever one of its inputs changes).
|
||||
getAssetGroups().forEach(function (assetGroup) {
|
||||
var watchPaths = assetGroup.inputPaths.concat(assetGroup.watchPaths);
|
||||
var watcher = gulp.watch(watchPaths, function (event) {
|
||||
var isConcat = path.basename(assetGroup.outputFileName, path.extname(assetGroup.outputFileName)) !== "@";
|
||||
if (isConcat)
|
||||
console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group with output '" + assetGroup.outputPath + "'.");
|
||||
else
|
||||
console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding asset group.");
|
||||
var doRebuild = true;
|
||||
var task = createAssetGroupTask(assetGroup, doRebuild);
|
||||
});
|
||||
watchers.push(watcher);
|
||||
});
|
||||
}
|
||||
var p;
|
||||
if (p) { p.exit(); }
|
||||
p = gulp.watch("Orchard.Web/{Core,Modules,Themes}/*/Assets.json", function (event) {
|
||||
console.log("Asset file '" + event.path + "' was " + event.type + ", resetting asset watchers.");
|
||||
restart();
|
||||
});
|
||||
restart();
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
** ASSET GROUPS
|
||||
*/
|
||||
|
||||
function getAssetGroups() {
|
||||
var assetManifestPaths = glob.sync("Orchard.Web/{Core,Modules,Themes}/*/Assets.json");
|
||||
var assetManifestPaths = glob.sync("Orchard.Web/{Core,Modules,Themes}/*/Assets.json", {});
|
||||
var assetGroups = [];
|
||||
assetManifestPaths.forEach(function (assetManifestPath) {
|
||||
var assetManifest = require("./" + assetManifestPath);
|
||||
var file = './' + assetManifestPath;
|
||||
var json = fs.readFileSync(file, 'utf8');
|
||||
assetManifest = eval(json);
|
||||
assetManifest.forEach(function (assetGroup) {
|
||||
resolveAssetGroupPaths(assetGroup, assetManifestPath);
|
||||
assetGroups.push(assetGroup);
|
||||
|
@@ -110,23 +110,23 @@ namespace Orchard.Tests.Modules.Recipes.Services {
|
||||
|
||||
[Test]
|
||||
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]
|
||||
public void HarvestRecipesShouldHarvestRecipeXmlFiles() {
|
||||
var recipes = (List<Recipe>)_recipeHarvester.HarvestRecipes("Sample1");
|
||||
Assert.That(recipes.Count, Is.EqualTo(1));
|
||||
var recipes = _recipeHarvester.HarvestRecipes("Sample1");
|
||||
Assert.That(recipes.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseRecipeLoadsRecipeMetaDataIntoModel() {
|
||||
var recipes = (List<Recipe>)_recipeHarvester.HarvestRecipes("Sample1");
|
||||
Assert.That(recipes.Count, Is.EqualTo(1));
|
||||
var recipes = _recipeHarvester.HarvestRecipes("Sample1");
|
||||
Assert.That(recipes.Count(), Is.EqualTo(1));
|
||||
|
||||
var sampleRecipe = recipes[0];
|
||||
var sampleRecipe = recipes.First();
|
||||
Assert.That(sampleRecipe.Name, Is.EqualTo("cms"));
|
||||
Assert.That(sampleRecipe.Description, Is.EqualTo("a sample Orchard recipe describing a cms"));
|
||||
Assert.That(sampleRecipe.Author, Is.EqualTo("orchard"));
|
||||
|
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Autofac;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Caching;
|
||||
@@ -78,6 +80,42 @@ namespace Orchard.Tests.Caching {
|
||||
Is.Not.SameAs(c2.CacheManager.GetCache<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 {
|
||||
public ICacheManager CacheManager { get; set; }
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using Orchard.Localization.Models;
|
||||
|
||||
namespace Orchard.Tests.Localization {
|
||||
|
||||
[TestFixture]
|
||||
[TestFixture()]
|
||||
public class DateTimePartsTests {
|
||||
|
||||
[Test]
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -13,7 +12,8 @@ using Orchard.Localization.Services;
|
||||
|
||||
namespace Orchard.Tests.Localization {
|
||||
|
||||
[TestFixture]
|
||||
[TestFixture()]
|
||||
[Category("longrunning")]
|
||||
public class DefaultDateFormatterTests {
|
||||
|
||||
[SetUp]
|
||||
|
@@ -9,7 +9,7 @@ namespace Orchard.Tests.Stubs {
|
||||
WorkContext = workContext;
|
||||
}
|
||||
|
||||
public WorkContext WorkContext { get; }
|
||||
public WorkContext WorkContext { get; private set; }
|
||||
|
||||
public void Dispose() {
|
||||
_lifetimeScope.Dispose();
|
||||
|
@@ -89,9 +89,9 @@ namespace Orchard.WarmupStarter {
|
||||
var result = _initialization(application);
|
||||
_initializationResult = result;
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
lock (_synLock) {
|
||||
_error = e;
|
||||
_error = ex;
|
||||
_previousError = null;
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ using Orchard.UI.Navigation;
|
||||
using Orchard.Utility;
|
||||
using System;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Core.Navigation.Controllers {
|
||||
[ValidateInput(false)]
|
||||
@@ -179,6 +180,10 @@ namespace Orchard.Core.Navigation.Controllers {
|
||||
return View(model);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
if (exception.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
Logger.Error(T("Creating menu item failed: {0}", exception.Message).Text);
|
||||
Services.Notifier.Error(T("Creating menu item failed: {0}", exception.Message));
|
||||
return this.RedirectLocal(returnUrl, () => RedirectToAction("Index"));
|
||||
|
@@ -11,6 +11,7 @@ using Orchard.Security.Permissions;
|
||||
using Orchard.UI;
|
||||
using Orchard.UI.Navigation;
|
||||
using Orchard.Utility;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Core.Navigation.Services {
|
||||
public class NavigationManager : INavigationManager {
|
||||
@@ -152,6 +153,9 @@ namespace Orchard.Core.Navigation.Services {
|
||||
items = builder.Build();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Unexpected error while querying a navigation provider. It was ignored. The menu provided by the provider may not be complete.");
|
||||
}
|
||||
if (items != null) {
|
||||
@@ -170,6 +174,9 @@ namespace Orchard.Core.Navigation.Services {
|
||||
items = builder.Build();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Unexpected error while querying a menu provider. It was ignored. The menu provided by the provider may not be complete.");
|
||||
}
|
||||
if (items != null) {
|
||||
@@ -188,6 +195,9 @@ namespace Orchard.Core.Navigation.Services {
|
||||
imageSets = builder.BuildImageSets();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Unexpected error while querying a navigation provider. It was ignored. The menu provided by the provider may not be complete.");
|
||||
}
|
||||
if (imageSets != null) {
|
||||
|
@@ -8,6 +8,7 @@ using Orchard.Logging;
|
||||
using Orchard.Services;
|
||||
using Orchard.Tasks;
|
||||
using Orchard.Tasks.Scheduling;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Core.Scheduling.Services {
|
||||
public class ScheduledTaskExecutor : IBackgroundTask {
|
||||
@@ -63,6 +64,9 @@ namespace Orchard.Core.Scheduling.Services {
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Warning(ex, "Unable to process scheduled task #{0} of type {1}", taskEntry.Id, taskEntry.Action);
|
||||
_transactionManager.Cancel();
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ using Orchard.Logging;
|
||||
using Orchard.Security;
|
||||
using Orchard.Settings;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Core.Settings.Drivers {
|
||||
public class SiteSettingsPartDriver : ContentPartDriver<SiteSettingsPart> {
|
||||
@@ -100,9 +101,12 @@ namespace Orchard.Core.Settings.Drivers {
|
||||
using (request.GetResponse() as HttpWebResponse) {}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
_notifier.Warning(T("The base url you entered could not be requested from current location."));
|
||||
Logger.Warning(e, "Could not query base url: {0}", model.Site.BaseUrl);
|
||||
Logger.Warning(ex, "Could not query base url: {0}", model.Site.BaseUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ using Orchard.ContentManagement.MetaData.Services;
|
||||
using Orchard.Core.Settings.Metadata.Records;
|
||||
using Orchard.Data;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Core.Settings.Metadata {
|
||||
public class ContentDefinitionManager : Component, IContentDefinitionManager {
|
||||
@@ -124,7 +125,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
private IDictionary<string, ContentTypeDefinition> AcquireContentTypeDefinitions() {
|
||||
return _cacheManager.Get("ContentTypeDefinitions", ctx => {
|
||||
return _cacheManager.Get("ContentTypeDefinitions", true, ctx => {
|
||||
MonitorContentDefinitionSignal(ctx);
|
||||
|
||||
AcquireContentPartDefinitions();
|
||||
@@ -139,7 +140,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
private IDictionary<string, ContentPartDefinition> AcquireContentPartDefinitions() {
|
||||
return _cacheManager.Get("ContentPartDefinitions", ctx => {
|
||||
return _cacheManager.Get("ContentPartDefinitions", true, ctx => {
|
||||
MonitorContentDefinitionSignal(ctx);
|
||||
|
||||
var contentPartDefinitionRecords = _partDefinitionRepository.Table
|
||||
@@ -152,7 +153,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
private IDictionary<string, ContentFieldDefinition> AcquireContentFieldDefinitions() {
|
||||
return _cacheManager.Get("ContentFieldDefinitions", ctx => {
|
||||
return _cacheManager.Get("ContentFieldDefinitions", true, ctx => {
|
||||
MonitorContentDefinitionSignal(ctx);
|
||||
|
||||
return _fieldDefinitionRepository.Table.Select(Build).ToDictionary(x => x.Name, y => y);
|
||||
@@ -282,6 +283,9 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
return XElement.Parse(settings);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Unable to parse settings xml");
|
||||
return null;
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ namespace Orchard.Core.Settings.Services {
|
||||
}
|
||||
|
||||
public ISite GetSiteSettings() {
|
||||
var siteId = _cacheManager.Get("SiteId", ctx => {
|
||||
var siteId = _cacheManager.Get("SiteId", true, ctx => {
|
||||
var site = _contentManager.Query("Site")
|
||||
.List()
|
||||
.FirstOrDefault();
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.DisplayManagement;
|
||||
@@ -32,8 +31,20 @@ namespace Orchard.Core.Shapes {
|
||||
DateTimeUtc = DateTimeUtc != System.DateTime.MinValue ? DateTimeUtc : dateTimeUtc; // Both capitalizations retained for compatibility.
|
||||
var time = _clock.UtcNow - DateTimeUtc;
|
||||
|
||||
if (time.TotalDays > 7 || time.TotalDays < -7)
|
||||
return Display.DateTime(DateTimeUtc: DateTimeUtc, CustomFormat: null);
|
||||
if (time.TotalYears() > 1)
|
||||
return T.Plural("1 year ago", "{0} years ago", time.TotalYears());
|
||||
if (time.TotalYears() < -1)
|
||||
return T.Plural("in 1 year", "in {0} years", -time.TotalYears());
|
||||
|
||||
if (time.TotalMonths() > 1)
|
||||
return T.Plural("1 month ago", "{0} months ago", time.TotalMonths());
|
||||
if (time.TotalMonths() < -1)
|
||||
return T.Plural("in 1 month", "in {0} months", -time.TotalMonths());
|
||||
|
||||
if (time.TotalWeeks() > 1)
|
||||
return T.Plural("1 week ago", "{0} weeks ago", time.TotalWeeks());
|
||||
if (time.TotalWeeks() < -1)
|
||||
return T.Plural("in 1 week", "in {0} weeks", -time.TotalWeeks());
|
||||
|
||||
if (time.TotalHours > 24)
|
||||
return T.Plural("1 day ago", "{0} days ago", time.Days);
|
||||
@@ -71,4 +82,18 @@ namespace Orchard.Core.Shapes {
|
||||
return new MvcHtmlString(_dateLocalizationServices.ConvertToLocalizedString(DateTimeUtc, CustomFormat.Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ namespace Orchard.ContentPicker.Fields {
|
||||
|
||||
public IEnumerable<ContentItem> ContentItems {
|
||||
get {
|
||||
return _contentItems.Value;
|
||||
return _contentItems.Value ?? Enumerable.Empty<ContentItem>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@ namespace Orchard.ContentTypes.Services {
|
||||
}
|
||||
|
||||
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.
|
||||
// For now, we'll just cache the stereotypes for 1 minute.
|
||||
|
@@ -1,10 +1,15 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.Core.Contents.Extensions;
|
||||
using Orchard.Data;
|
||||
using Orchard.Data.Migration;
|
||||
|
||||
namespace Orchard.DynamicForms {
|
||||
public class Migrations : DataMigrationImpl {
|
||||
private readonly byte[] _oldLayoutHash = new byte[] { 0x91, 0x10, 0x3b, 0x97, 0xce, 0x1e, 0x1e, 0xc7, 0x7a, 0x41, 0xf7, 0x82, 0xe8, 0x58, 0x85, 0x91 };
|
||||
|
||||
private const string DefaultFormLayoutData =
|
||||
@"{
|
||||
""elements"": [
|
||||
@@ -59,7 +64,52 @@ namespace Orchard.DynamicForms {
|
||||
.WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData))
|
||||
.WithSetting("Stereotype", "Widget")
|
||||
.DisplayedAs("Form Widget"));
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
public int UpdateFrom1() {
|
||||
// if the default layout data was unchanged, fix it with the new default
|
||||
|
||||
var formLayoutPart = ContentDefinitionManager
|
||||
.GetTypeDefinition("Form")
|
||||
.Parts
|
||||
.FirstOrDefault(x => x.PartDefinition.Name == "LayoutPart");
|
||||
|
||||
if (formLayoutPart != null &&
|
||||
formLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"] != null) {
|
||||
var layout = formLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"];
|
||||
|
||||
if(GetMD5(layout) == _oldLayoutHash) {
|
||||
ContentDefinitionManager.AlterTypeDefinition("Form", type => type
|
||||
.WithPart("LayoutPart", p => p
|
||||
.WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var formWidgetLayoutPart = ContentDefinitionManager
|
||||
.GetTypeDefinition("FormWidget")
|
||||
.Parts
|
||||
.FirstOrDefault(x => x.PartDefinition.Name == "LayoutPart");
|
||||
|
||||
if (formWidgetLayoutPart != null &&
|
||||
formWidgetLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"] != null) {
|
||||
var layout = formWidgetLayoutPart.Settings["LayoutTypePartSettings.DefaultLayoutData"];
|
||||
|
||||
if (GetMD5(layout) == _oldLayoutHash) {
|
||||
ContentDefinitionManager.AlterTypeDefinition("FormWidget", type => type
|
||||
.WithPart("LayoutPart", p => p
|
||||
.WithSetting("LayoutTypePartSettings.DefaultLayoutData", DefaultFormLayoutData))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
private byte[] GetMD5(string text) {
|
||||
byte[] encodedText = System.Text.Encoding.UTF8.GetBytes(text);
|
||||
return ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedText);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
Name: Custom Forms
|
||||
Name: Dynamic Forms
|
||||
AntiForgery: enabled
|
||||
Author: The Orchard Team
|
||||
Website: http://orchardcustomforms.codeplex.com
|
||||
Website: http://www.orchardproject.net/
|
||||
Version: 1.9.1
|
||||
OrchardVersion: 1.9
|
||||
Description: Create custom forms like contact forms using layouts.
|
||||
|
@@ -7,7 +7,7 @@ namespace Orchard.DynamicForms.Tokens {
|
||||
|
||||
public void Describe(DescribeContext context) {
|
||||
context.For("FormSubmission", T("Dynamic Form submission"), T("Dynamic Form Submission tokens for use in workflows handling the Dynamic Form Submitted event."))
|
||||
.Token("Field:*", T("Field:<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."))
|
||||
;
|
||||
}
|
||||
@@ -15,10 +15,20 @@ namespace Orchard.DynamicForms.Tokens {
|
||||
public void Evaluate(EvaluateContext context) {
|
||||
context.For<FormSubmissionTokenContext>("FormSubmission")
|
||||
.Token(token => token.StartsWith("Field:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Field:".Length) : null, GetFieldValue)
|
||||
.Chain(FilterChainParam, "Text", GetFieldValue)
|
||||
.Token(token => token.StartsWith("IsValid:", StringComparison.OrdinalIgnoreCase) ? token.Substring("IsValid:".Length) : null, GetFieldValidationStatus);
|
||||
}
|
||||
|
||||
private object GetFieldValue(string fieldName, FormSubmissionTokenContext context) {
|
||||
private static Tuple<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];
|
||||
}
|
||||
|
||||
|
@@ -307,10 +307,9 @@ namespace Orchard.Layouts.Drivers {
|
||||
|
||||
var queryPart = query.As<QueryPart>();
|
||||
var layoutIndex = XmlHelper.Parse<int>(context.ExportableData.Get("LayoutIndex"));
|
||||
var layout = queryPart.Layouts[layoutIndex];
|
||||
|
||||
element.QueryId = queryPart.Id;
|
||||
element.LayoutId = layout.Id;
|
||||
element.LayoutId = layoutIndex != -1 ? queryPart.Layouts[layoutIndex].Id : -1;
|
||||
}
|
||||
|
||||
private static string GetLayoutDescription(IEnumerable<LayoutDescriptor> layouts, LayoutRecord l) {
|
||||
|
@@ -38,7 +38,7 @@ namespace Orchard.Layouts.Services {
|
||||
public IEnumerable<ElementDescriptor> DescribeElements(DescribeElementsContext context) {
|
||||
var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string);
|
||||
var cacheKey = String.Format("LayoutElementTypes-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam);
|
||||
return _cacheManager.Get(cacheKey, acquireContext => {
|
||||
return _cacheManager.Get(cacheKey, true, acquireContext => {
|
||||
var harvesterContext = new HarvestElementsContext {
|
||||
Content = context.Content
|
||||
};
|
||||
@@ -55,7 +55,7 @@ namespace Orchard.Layouts.Services {
|
||||
|
||||
public IEnumerable<CategoryDescriptor> GetCategories(DescribeElementsContext context) {
|
||||
var contentType = context.Content != null ? context.Content.ContentItem.ContentType : default(string);
|
||||
return _cacheManager.Get(String.Format("ElementCategories-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam), acquireContext => {
|
||||
return _cacheManager.Get(String.Format("ElementCategories-{0}-{1}", contentType ?? "AnyType", context.CacheVaryParam), true, acquireContext => {
|
||||
var elements = DescribeElements(context);
|
||||
var categoryDictionary = GetCategories();
|
||||
var categoryDescriptorDictionary = new Dictionary<string, CategoryDescriptor>();
|
||||
|
@@ -5,17 +5,17 @@
|
||||
}
|
||||
<div class="item-properties actions">
|
||||
<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>
|
||||
</div>
|
||||
<div class="manage">
|
||||
@if (itemContentTypes.Any()) {
|
||||
foreach (var contentType in itemContentTypes) {
|
||||
@Html.ActionLink(T("New {0}", contentType.DisplayName).ToString(), "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" })
|
||||
@Html.ActionLink(T("New {0}", contentType.DisplayName), "Create", "Admin", new { area = "Contents", id = contentType.Name, containerId }, new { @class = "button primaryAction create-content" })
|
||||
}
|
||||
}
|
||||
else {
|
||||
@Html.ActionLink(T("New Content").ToString(), "Create", "Admin", new { area = "Contents", containerId }, new { @class = "button primaryAction create-content" })
|
||||
@Html.ActionLink(T("New Content"), "Create", "Admin", new { area = "Contents", containerId }, new { @class = "button primaryAction create-content" })
|
||||
}
|
||||
<a id="chooseItems" href="#" class="button primaryAction">@T("Choose Items")</a>
|
||||
</div>
|
||||
|
@@ -58,7 +58,7 @@ namespace Orchard.MediaProcessing.Services {
|
||||
}
|
||||
|
||||
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));
|
||||
var dictionary = new Dictionary<string, string>();
|
||||
|
||||
|
@@ -32,7 +32,7 @@ namespace Orchard.MediaProcessing.Services {
|
||||
|
||||
public ImageProfilePart GetImageProfileByName(string name) {
|
||||
|
||||
var profileId = _cacheManager.Get("ProfileId_" + name, ctx => {
|
||||
var profileId = _cacheManager.Get("ProfileId_" + name, true, ctx => {
|
||||
var profile = _contentManager.Query<ImageProfilePart, ImageProfilePartRecord>()
|
||||
.Where(x => x.Name == name)
|
||||
.Slice(0, 1)
|
||||
|
@@ -463,7 +463,7 @@ namespace Orchard.OutputCache.Filters {
|
||||
|
||||
private CacheSettings CacheSettings {
|
||||
get {
|
||||
return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, context => {
|
||||
return _cacheSettings ?? (_cacheSettings = _cacheManager.Get(CacheSettings.CacheKey, true, context => {
|
||||
context.Monitor(_signals.When(CacheSettings.CacheKey));
|
||||
return new CacheSettings(_workContext.CurrentSite.As<CacheSettingsPart>());
|
||||
}));
|
||||
|
@@ -99,7 +99,7 @@ namespace Orchard.OutputCache.Services {
|
||||
}
|
||||
|
||||
public IEnumerable<CacheRouteConfig> GetRouteConfigs() {
|
||||
return _cacheManager.Get(RouteConfigsCacheKey,
|
||||
return _cacheManager.Get(RouteConfigsCacheKey, true,
|
||||
ctx => {
|
||||
ctx.Monitor(_signals.When(RouteConfigsCacheKey));
|
||||
return _repository.Fetch(c => true).Select(c => new CacheRouteConfig { RouteKey = c.RouteKey, Duration = c.Duration, GraceTime = c.GraceTime }).ToReadOnlyCollection();
|
||||
|
@@ -14,7 +14,7 @@ namespace Orchard.Scripting.Dlr.Services {
|
||||
}
|
||||
|
||||
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
|
||||
def initialize(callbacks)
|
||||
@callbacks = callbacks
|
||||
@@ -38,7 +38,7 @@ class ExecContext
|
||||
end
|
||||
ExecContext
|
||||
"));
|
||||
var ops = _cacheManager.Get("----", ctx => (ObjectOperations)_scriptingManager.ExecuteOperation(x => x));
|
||||
var ops = _cacheManager.Get("----", true, ctx => (ObjectOperations)_scriptingManager.ExecuteOperation(x => x));
|
||||
object execContext = _cacheManager.Get(expression, ctx => (object)ops.InvokeMember(execContextType, "alloc", expression));
|
||||
dynamic result = ops.InvokeMember(execContext, "evaluate", new CallbackApi(this, providers));
|
||||
return ConvertRubyValue(result);
|
||||
|
@@ -20,7 +20,7 @@ namespace Orchard.Scripting {
|
||||
public Localizer T { get; set; }
|
||||
|
||||
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);
|
||||
return new { Tree = ast, Errors = ast.GetErrors().ToList() };
|
||||
});
|
||||
|
@@ -32,7 +32,7 @@ namespace Orchard.Tags.Services {
|
||||
|
||||
public IEnumerable<TagCount> GetPopularTags(int buckets, string slug) {
|
||||
var cacheKey = "Orchard.Tags.TagCloud." + (slug ?? "") + '.' + buckets;
|
||||
return _cacheManager.Get(cacheKey,
|
||||
return _cacheManager.Get(cacheKey, true,
|
||||
ctx => {
|
||||
ctx.Monitor(_signals.When(TagCloudTagsChanged));
|
||||
IEnumerable<TagCount> tagCounts;
|
||||
|
@@ -31,21 +31,33 @@ namespace Orchard.Taxonomies.Tokens {
|
||||
|
||||
context.For<TaxonomyField>("TaxonomyField")
|
||||
.Token("Terms", field => String.Join(", ", field.Terms.Select(t => t.Name).ToArray()))
|
||||
.Token(
|
||||
token => {
|
||||
var index = 0;
|
||||
return (token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) && int.TryParse(token.Substring("Terms:".Length), out index)) ? index.ToString() : null;
|
||||
},
|
||||
(token, t) => {
|
||||
var index = Convert.ToInt32(token);
|
||||
return index + 1 > t.Terms.Count() ? null : t.Terms.ElementAt(index).Name;
|
||||
.Token(FilterTokenParam,
|
||||
(index, field) => {
|
||||
var term = field.Terms.ElementAtOrDefault(Convert.ToInt32(index));
|
||||
return term != null ? term.Name : null;
|
||||
})
|
||||
// todo: extend Chain() in order to accept a filter like in Token() so that we can chain on an expression
|
||||
.Chain("Terms:0", "Content", t => t.Terms.ElementAt(0))
|
||||
.Chain("Terms:1", "Content", t => t.Terms.ElementAt(1))
|
||||
.Chain("Terms:2", "Content", t => t.Terms.ElementAt(2))
|
||||
.Chain("Terms:3", "Content", t => t.Terms.ElementAt(3))
|
||||
.Chain(FilterChainParam, "Content", (index, field) => field.Terms.ElementAtOrDefault(Convert.ToInt32(index)))
|
||||
;
|
||||
}
|
||||
|
||||
private static string FilterTokenParam(string token) {
|
||||
int index = 0;
|
||||
return (token.StartsWith("Terms:", StringComparison.OrdinalIgnoreCase) && int.TryParse(token.Substring("Terms:".Length), out index)) ? index.ToString() : null;
|
||||
}
|
||||
|
||||
private static Tuple<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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -55,7 +55,7 @@ namespace Orchard.Templates.Services {
|
||||
}
|
||||
|
||||
private IDictionary<string, TemplateResult> BuildShapeProcessors() {
|
||||
return _cacheManager.Get("Template.ShapeProcessors", ctx => {
|
||||
return _cacheManager.Get("Template.ShapeProcessors", true, ctx => {
|
||||
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
|
||||
|
||||
// select all name of types which contains ShapePart
|
||||
|
@@ -7,5 +7,6 @@ namespace Orchard.Tokens {
|
||||
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, 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);
|
||||
}
|
||||
}
|
@@ -153,6 +153,27 @@ namespace Orchard.Tokens.Implementation {
|
||||
}
|
||||
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> {
|
||||
@@ -175,6 +196,10 @@ namespace Orchard.Tokens.Implementation {
|
||||
public override EvaluateFor<TData> Chain(string token, string chainTarget, Func<TData, object> chainValue) {
|
||||
return this;
|
||||
}
|
||||
|
||||
public override EvaluateFor<TData> Chain(Func<string, Tuple<string, string>> filter, string chainTarget, Func<string, TData, object> chainValue) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,7 @@ namespace Orchard.Tokens.Providers {
|
||||
.Token("DisplayUrl", T("Display Url"), T("Url to display the content."), "Url")
|
||||
.Token("EditUrl", T("Edit Url"), T("Url to edit the content."), "Url")
|
||||
.Token("Container", T("Container"), T("The container Content Item."), "Content")
|
||||
.Token("Body", T("Body"), T("The body text of the content item."), "Content")
|
||||
.Token("Body", T("Body"), T("The body text of the content item."), "Text")
|
||||
;
|
||||
|
||||
// Token descriptors for fields
|
||||
|
@@ -13,38 +13,45 @@ namespace Orchard.Tokens.Providers {
|
||||
public void Describe(DescribeContext context) {
|
||||
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("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("TrimEnd:*", T("TrimEnd:<chars|number>"), T("Trims the specified characters or number of them from the end of the string."), "Text")
|
||||
.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."))
|
||||
.Token("UrlEncode", T("Url Encode"), T("Encodes a URL string."), "Text")
|
||||
.Token("HtmlEncode", T("Html Encode"), T("Encodes an HTML string."), "Text")
|
||||
.Token("LineEncode", T("Line Encode"), T("Replaces new lines with <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) {
|
||||
context.For<String>("Text", () => "")
|
||||
.Token( // {Text}
|
||||
// {Text}
|
||||
.Token(
|
||||
token => token == String.Empty ? String.Empty : null,
|
||||
(token, d) => d.ToString())
|
||||
.Token( // {Text.Limit:<length>[,<ellipsis>]}
|
||||
token => {
|
||||
if (token.StartsWith("Limit:", StringComparison.OrdinalIgnoreCase)) {
|
||||
var param = token.Substring("Limit:".Length);
|
||||
return param;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// {Text.Limit:<length>[,<ellipsis>]}
|
||||
.Token(
|
||||
token => FilterTokenParam("Limit:", token),
|
||||
(token, t) => Limit(t, token))
|
||||
// {Text.Format:<formatstring>}
|
||||
.Token(
|
||||
token => token.StartsWith("Format:", StringComparison.OrdinalIgnoreCase) ? token.Substring("Format:".Length) : null,
|
||||
(token, d) => String.Format(d,token))
|
||||
.Token(token => token.StartsWith("TrimEnd:", StringComparison.OrdinalIgnoreCase) ? token.Substring("TrimEnd:".Length) : null, TrimEnd)
|
||||
token => FilterTokenParam("Format:", token),
|
||||
(token, d) => String.Format(d, token))
|
||||
// {Text.TrimEnd:<chars|number>}
|
||||
.Token(token => FilterTokenParam("TrimEnd:", token), TrimEnd)
|
||||
.Token("UrlEncode", HttpUtility.UrlEncode)
|
||||
.Chain("UrlEncode", "Text", HttpUtility.UrlEncode)
|
||||
.Token("HtmlEncode", HttpUtility.HtmlEncode)
|
||||
.Chain("HtmlEncode", "Text", HttpUtility.HtmlEncode)
|
||||
.Token("JavaScriptEncode", HttpUtility.JavaScriptStringEncode)
|
||||
.Chain("JavaScriptEncode", "Text", HttpUtility.JavaScriptStringEncode)
|
||||
.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) {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
@@ -24,6 +25,9 @@ namespace Orchard.Tokens.Tests {
|
||||
|
||||
context.For("Date")
|
||||
.Token("Now", T("Now"), T("Current system date in short date format. You can chain a .NET DateTime format string to customize."));
|
||||
|
||||
context.For("Users")
|
||||
.Token("Users[*:]", T("Users"), T("A user by its username"), "User");
|
||||
}
|
||||
|
||||
public void Evaluate(EvaluateContext context) {
|
||||
@@ -36,6 +40,7 @@ namespace Orchard.Tokens.Tests {
|
||||
|
||||
context.For<IUser>("User", () => new TestUser { UserName = "CurrentUser" })
|
||||
.Token("Name", u => u.UserName)
|
||||
.Token("Email", u => u.Email)
|
||||
.Token("Birthdate", u => "Nov 15")
|
||||
.Chain("Birthdate", "DateTime", u => new DateTime(1978, 11, 15));
|
||||
|
||||
@@ -45,6 +50,29 @@ namespace Orchard.Tokens.Tests {
|
||||
|
||||
context.For<DateTime>("DateTime")
|
||||
.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()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -29,10 +29,11 @@ namespace Orchard.Tokens.Tests {
|
||||
[Test]
|
||||
public void TestDescribe() {
|
||||
var allTokens = _tokenManager.Describe(null);
|
||||
Assert.That(allTokens.Count(), Is.EqualTo(3));
|
||||
Assert.That(allTokens.Count(), Is.EqualTo(4));
|
||||
Assert.That(allTokens.Any(d => d.Target == "Site"));
|
||||
Assert.That(allTokens.Any(d => d.Target == "User"));
|
||||
Assert.That(allTokens.Any(d => d.Target == "Date"));
|
||||
Assert.That(allTokens.Any(d => d.Target == "Users"));
|
||||
|
||||
var tokens = allTokens.Single(d => d.Target == "Site").Tokens;
|
||||
Assert.That(string.Join(",", tokens.Select(td => td.Target)), Is.EqualTo("Site,Site,Site,Site"));
|
||||
@@ -59,7 +60,7 @@ namespace Orchard.Tokens.Tests {
|
||||
[Test]
|
||||
public void TestDescribeFilter() {
|
||||
var tokenDescriptors = _tokenManager.Describe(null);
|
||||
Assert.That(tokenDescriptors.Count(), Is.EqualTo(3));
|
||||
Assert.That(tokenDescriptors.Count(), Is.EqualTo(4));
|
||||
tokenDescriptors = _tokenManager.Describe(new[] { "Site" });
|
||||
Assert.That(tokenDescriptors.Count(), Is.EqualTo(1));
|
||||
Assert.That(tokenDescriptors.First().Target, Is.EqualTo("Site"));
|
||||
|
@@ -40,6 +40,18 @@ namespace Orchard.Tokens.Tests {
|
||||
Assert.That(_tokenizer.Replace("{Site.CurrentUser.Birthdate.yyyy}", null), Is.EqualTo("1978"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestParameterizedTokens() {
|
||||
Assert.That(_tokenizer.Replace("{Users.User:User2}", null), Is.EqualTo("User2"));
|
||||
Assert.That(_tokenizer.Replace("{Users.User:FakeUser}", null), Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestParameterizedChainedTokens() {
|
||||
Assert.That(_tokenizer.Replace("{Users.User:User2.Email}", null), Is.EqualTo("user2@test.com"));
|
||||
Assert.That(_tokenizer.Replace("{Users.User:FakeUser.Email}", null), Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMissingTokens() {
|
||||
Assert.That(_tokenizer.Replace("[{Site.NotAToken}]", null), Is.EqualTo("[]"));
|
||||
|
@@ -255,14 +255,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Layouts", "Orchard.
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.DynamicForms", "Orchard.Web\Modules\Orchard.DynamicForms\Orchard.DynamicForms.csproj", "{82190F52-2901-46D6-8A4C-34649959483F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Dashboards", "Orchard.Web\Modules\Orchard.Dashboards\Orchard.Dashboards.csproj", "{BAC82DB9-F4C4-4DD1-ABDB-F70E6229E6B0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DF3909B0-1DDD-4D8A-9919-56FC438E25E2}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Rebracer.xml = Rebracer.xml
|
||||
WebEssentials-Settings.json = WebEssentials-Settings.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Dashboards", "Orchard.Web\Modules\Orchard.Dashboards\Orchard.Dashboards.csproj", "{BAC82DB9-F4C4-4DD1-ABDB-F70E6229E6B0}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gulp", "Gulp", "{90EBEE36-B5CD-42A8-A21B-76270E2C5D24}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Gulpfile.js = Gulpfile.js
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Caching {
|
||||
public class DefaultAsyncTokenProvider : IAsyncTokenProvider {
|
||||
@@ -37,9 +38,12 @@ namespace Orchard.Caching {
|
||||
try {
|
||||
_task(token => _taskTokens.Add(token));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Error while monitoring extension files. Assuming extensions are not current.");
|
||||
_taskException = e;
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Error while monitoring extension files. Assuming extensions are not current.");
|
||||
_taskException = ex;
|
||||
}
|
||||
finally {
|
||||
_isTaskFinished = true;
|
||||
|
@@ -5,4 +5,17 @@ namespace Orchard.Caching {
|
||||
TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Tasks;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Commands {
|
||||
|
||||
@@ -94,19 +95,21 @@ namespace Orchard.Commands {
|
||||
|
||||
return CommandReturnCodes.Ok;
|
||||
}
|
||||
catch (OrchardCommandHostRetryException e) {
|
||||
catch (OrchardCommandHostRetryException ex) {
|
||||
// Special "Retry" return code for our host
|
||||
output.WriteLine(T("{0} (Retrying...)", e.Message));
|
||||
output.WriteLine(T("{0} (Retrying...)", ex.Message));
|
||||
return CommandReturnCodes.Retry;
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e is TargetInvocationException &&
|
||||
e.InnerException != null) {
|
||||
// If this is an exception coming from reflection and there is an innerexception which is the actual one, redirect
|
||||
e = e.InnerException;
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
OutputException(output, T("Error executing command \"{0}\"", string.Join(" ", args)), e);
|
||||
if (ex is TargetInvocationException &&
|
||||
ex.InnerException != null) {
|
||||
// If this is an exception coming from reflection and there is an innerexception which is the actual one, redirect
|
||||
ex = ex.InnerException;
|
||||
}
|
||||
OutputException(output, T("Error executing command \"{0}\"", string.Join(" ", args)), ex);
|
||||
return CommandReturnCodes.Fail;
|
||||
}
|
||||
}
|
||||
@@ -116,13 +119,16 @@ namespace Orchard.Commands {
|
||||
_hostContainer = CreateHostContainer();
|
||||
return CommandReturnCodes.Ok;
|
||||
}
|
||||
catch (OrchardCommandHostRetryException e) {
|
||||
catch (OrchardCommandHostRetryException ex) {
|
||||
// Special "Retry" return code for our host
|
||||
output.WriteLine(T("{0} (Retrying...)", e.Message));
|
||||
output.WriteLine(T("{0} (Retrying...)", ex.Message));
|
||||
return CommandReturnCodes.Retry;
|
||||
}
|
||||
catch (Exception e) {
|
||||
OutputException(output, T("Error starting up Orchard command line host"), e);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
OutputException(output, T("Error starting up Orchard command line host"), ex);
|
||||
return CommandReturnCodes.Fail;
|
||||
}
|
||||
}
|
||||
@@ -135,8 +141,11 @@ namespace Orchard.Commands {
|
||||
}
|
||||
return CommandReturnCodes.Ok;
|
||||
}
|
||||
catch (Exception e) {
|
||||
OutputException(output, T("Error shutting down Orchard command line host"), e);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
OutputException(output, T("Error shutting down Orchard command line host"), ex);
|
||||
return CommandReturnCodes.Fail;
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Commands {
|
||||
public abstract class DefaultOrchardCommandHandler : ICommandHandler {
|
||||
@@ -41,12 +42,15 @@ namespace Orchard.Commands {
|
||||
object value = Convert.ChangeType(commandSwitch.Value, propertyInfo.PropertyType);
|
||||
propertyInfo.SetValue(this, value, null/*index*/);
|
||||
}
|
||||
catch(Exception e) {
|
||||
catch(Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
string message = T("Error converting value \"{0}\" to \"{1}\" for switch \"{2}\"",
|
||||
LocalizedString.TextOrDefault(commandSwitch.Value, T("(empty)")),
|
||||
propertyInfo.PropertyType.FullName,
|
||||
commandSwitch.Key).Text;
|
||||
throw new InvalidOperationException(message, e);
|
||||
throw new InvalidOperationException(message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -817,7 +817,7 @@ namespace Orchard.ContentManagement {
|
||||
}
|
||||
|
||||
private ContentTypeRecord AcquireContentTypeRecord(string contentType) {
|
||||
var contentTypeId = _cacheManager.Get(contentType + "_Record", ctx => {
|
||||
var contentTypeId = _cacheManager.Get(contentType + "_Record", true, ctx => {
|
||||
ctx.Monitor(_signals.When(contentType + "_Record"));
|
||||
|
||||
var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType);
|
||||
|
@@ -76,7 +76,7 @@ namespace Orchard.ContentManagement {
|
||||
}
|
||||
|
||||
private int GetContentTypeRecordId(string contentType) {
|
||||
return _cacheManager.Get(contentType + "_Record", ctx => {
|
||||
return _cacheManager.Get(contentType + "_Record", true, ctx => {
|
||||
ctx.Monitor(_signals.When(contentType + "_Record"));
|
||||
|
||||
var contentTypeRecord = _contentTypeRepository.Get(x => x.Name == contentType);
|
||||
|
@@ -1,9 +1,13 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Orchard.Data.Migration.Interpreters;
|
||||
using Orchard.Data.Migration.Schema;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Features;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Tasks.Locking.Services;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Data.Migration {
|
||||
/// <summary>
|
||||
@@ -13,24 +17,35 @@ namespace Orchard.Data.Migration {
|
||||
private readonly IDataMigrationManager _dataMigrationManager;
|
||||
private readonly IFeatureManager _featureManager;
|
||||
private readonly IDistributedLockService _distributedLockService;
|
||||
private readonly IDataMigrationInterpreter _dataMigrationInterpreter;
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
|
||||
public AutomaticDataMigrations(
|
||||
IDataMigrationManager dataMigrationManager,
|
||||
IDataMigrationInterpreter dataMigrationInterpreter,
|
||||
IFeatureManager featureManager,
|
||||
IDistributedLockService distributedLockService) {
|
||||
IDistributedLockService distributedLockService,
|
||||
ITransactionManager transactionManager,
|
||||
ShellSettings shellSettings) {
|
||||
|
||||
_dataMigrationManager = dataMigrationManager;
|
||||
_featureManager = featureManager;
|
||||
_distributedLockService = distributedLockService;
|
||||
_shellSettings = shellSettings;
|
||||
_transactionManager = transactionManager;
|
||||
_dataMigrationInterpreter = dataMigrationInterpreter;
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void Activated() {
|
||||
EnsureDistributedLockSchemaExists();
|
||||
|
||||
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) {
|
||||
// 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[] {
|
||||
@@ -48,7 +63,10 @@ namespace Orchard.Data.Migration {
|
||||
_dataMigrationManager.Update(feature);
|
||||
}
|
||||
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() {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ using Orchard.Data.Migration.Schema;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Data.Migration {
|
||||
/// <summary>
|
||||
@@ -123,6 +124,9 @@ namespace Orchard.Data.Migration {
|
||||
current = (int)lookupTable[current].Invoke(migration, new object[0]);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "An unexpected error occurred while applying migration on {0} from version {1}.", feature, current);
|
||||
throw;
|
||||
}
|
||||
@@ -139,10 +143,13 @@ namespace Orchard.Data.Migration {
|
||||
dataMigrationRecord.Version = current;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Error while running migration version {0} for {1}.", current, feature);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Error while running migration version {0} for {1}.", current, feature);
|
||||
_transactionManager.Cancel();
|
||||
throw new OrchardException(T("Error while running migration version {0} for {1}.", current, feature), e);
|
||||
throw new OrchardException(T("Error while running migration version {0} for {1}.", current, feature), ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using Orchard.Data.Migration.Interpreters;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Data.Migration.Schema {
|
||||
public class SchemaBuilder {
|
||||
@@ -72,6 +73,9 @@ namespace Orchard.Data.Migration.Schema {
|
||||
Run(sqlStatmentCommand);
|
||||
return this;
|
||||
} catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
throw new OrchardException(T("An unexpected error occured while executing the SQL statement: {0}", sql), ex); // Add the sql to the nested exception information
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ using Orchard.Environment.ShellBuilders.Models;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Utility;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public class SessionConfigurationCache : ISessionConfigurationCache {
|
||||
@@ -80,11 +81,11 @@ namespace Orchard.Data {
|
||||
formatter.Serialize(stream, cache.Configuration);
|
||||
}
|
||||
}
|
||||
catch (SerializationException e) {
|
||||
catch (SerializationException ex) {
|
||||
//Note: This can happen when multiple processes/AppDomains try to save
|
||||
// the cached configuration at the same time. Only one concurrent
|
||||
// writer will win, and it's harmless for the other ones to fail.
|
||||
for (Exception scan = e; scan != null; scan = scan.InnerException)
|
||||
for (Exception scan = ex; scan != null; scan = scan.InnerException)
|
||||
Logger.Warning("Error storing new NHibernate cache configuration: {0}", scan.Message);
|
||||
}
|
||||
}
|
||||
@@ -118,8 +119,11 @@ namespace Orchard.Data {
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
for (var scan = e; scan != null; scan = scan.InnerException)
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
for (var scan = ex; scan != null; scan = scan.InnerException)
|
||||
Logger.Warning("Error reading the cached NHibernate configuration: {0}", scan.Message);
|
||||
Logger.Information("A new one will be re-generated.");
|
||||
return null;
|
||||
|
@@ -37,7 +37,7 @@ namespace Orchard.DisplayManagement.Descriptors {
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public ShapeTable GetShapeTable(string themeName) {
|
||||
return _cacheManager.Get(themeName ?? "", x => {
|
||||
return _cacheManager.Get(themeName ?? "", true, x => {
|
||||
Logger.Information("Start building shape table");
|
||||
|
||||
var alterationSets = _parallelCacheContext.RunInParallel(_bindingStrategies, bindingStrategy => {
|
||||
|
@@ -30,7 +30,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapePlacementStrategy {
|
||||
public bool DisableMonitoring { get; set; }
|
||||
|
||||
public PlacementFile Parse(string virtualPath) {
|
||||
return _cacheManager.Get(virtualPath, context => {
|
||||
return _cacheManager.Get(virtualPath, true, context => {
|
||||
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath);
|
||||
|
@@ -77,7 +77,7 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
|
||||
var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => {
|
||||
var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
|
||||
var virtualPath = Path.Combine(basePath, subPath).Replace(Path.DirectorySeparatorChar, '/');
|
||||
var fileNames = _cacheManager.Get(virtualPath, ctx => {
|
||||
var fileNames = _cacheManager.Get(virtualPath, true, ctx => {
|
||||
if (!_virtualPathProvider.DirectoryExists(virtualPath))
|
||||
return new List<string>();
|
||||
|
||||
|
@@ -14,6 +14,7 @@ using Orchard.Logging;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Mvc.Extensions;
|
||||
using Orchard.Utility.Extensions;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
// 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);
|
||||
ActivateShell(context);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "A tenant could not be started: " + settings.Name);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "A tenant could not be started: " + settings.Name);
|
||||
}
|
||||
while (_processingEngine.AreTasksPending()) {
|
||||
Logger.Debug("Processing pending task after activate Shell");
|
||||
|
@@ -11,6 +11,7 @@ using Orchard.Owin;
|
||||
using Orchard.Tasks;
|
||||
using Orchard.UI;
|
||||
using Orchard.WebApi.Routes;
|
||||
using Orchard.Exceptions;
|
||||
using IModelBinderProvider = Orchard.Mvc.ModelBinders.IModelBinderProvider;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
@@ -98,8 +99,12 @@ namespace Orchard.Environment {
|
||||
try {
|
||||
action();
|
||||
}
|
||||
catch(Exception e) {
|
||||
Logger.Error(e, "An unexcepted error occured while terminating the Shell");
|
||||
catch(Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
Logger.Error(ex, "An unexcepted error occured while terminating the Shell");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ using Orchard.FileSystems.Dependencies;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Compilers {
|
||||
/// <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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Compilers {
|
||||
public bool DisableMonitoring { get; set; }
|
||||
|
||||
public ProjectFileDescriptor Parse(string virtualPath) {
|
||||
return _cacheManager.Get(virtualPath,
|
||||
return _cacheManager.Get(virtualPath, true,
|
||||
ctx => {
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", virtualPath);
|
||||
|
@@ -9,6 +9,7 @@ using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Utility;
|
||||
using Orchard.Utility.Extensions;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Environment.Extensions {
|
||||
public class ExtensionManager : IExtensionManager {
|
||||
@@ -44,7 +45,7 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
|
||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||
return _cacheManager.Get("AvailableExtensions", ctx =>
|
||||
return _cacheManager.Get("AvailableExtensions", true, ctx =>
|
||||
_parallelCacheContext
|
||||
.RunInParallel(_folders, folder => folder.AvailableExtensions().ToList())
|
||||
.SelectMany(descriptors => descriptors)
|
||||
@@ -52,7 +53,7 @@ namespace Orchard.Environment.Extensions {
|
||||
}
|
||||
|
||||
public IEnumerable<FeatureDescriptor> AvailableFeatures() {
|
||||
return _cacheManager.Get("AvailableFeatures", ctx =>
|
||||
return _cacheManager.Get("AvailableFeatures", true, ctx =>
|
||||
AvailableExtensions()
|
||||
.SelectMany(ext => ext.Features)
|
||||
.OrderByDependenciesAndPriorities(HasDependency, GetPriority)
|
||||
@@ -92,7 +93,7 @@ namespace Orchard.Environment.Extensions {
|
||||
|
||||
var result =
|
||||
_parallelCacheContext
|
||||
.RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, ctx => LoadFeature(descriptor)))
|
||||
.RunInParallel(featureDescriptors, descriptor => _cacheManager.Get(descriptor.Id, true, ctx => LoadFeature(descriptor)))
|
||||
.ToArray();
|
||||
|
||||
Logger.Information("Done loading features");
|
||||
@@ -106,7 +107,7 @@ namespace Orchard.Environment.Extensions {
|
||||
|
||||
ExtensionEntry extensionEntry;
|
||||
try {
|
||||
extensionEntry = _cacheManager.Get(extensionId, ctx => {
|
||||
extensionEntry = _cacheManager.Get(extensionId, true, ctx => {
|
||||
var entry = BuildEntry(extensionDescriptor);
|
||||
if (entry != null) {
|
||||
ctx.Monitor(_asyncTokenProvider.GetToken(monitor => {
|
||||
@@ -119,6 +120,9 @@ namespace Orchard.Environment.Extensions {
|
||||
});
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Error loading extension '{0}'", extensionId);
|
||||
throw new OrchardException(T("Error while loading extension '{0}'.", extensionId), ex);
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ using Orchard.FileSystems.WebSite;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Utility.Extensions;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Environment.Extensions.Folders {
|
||||
public class ExtensionHarvester : IExtensionHarvester {
|
||||
@@ -57,7 +58,7 @@ namespace Orchard.Environment.Extensions.Folders {
|
||||
private IEnumerable<ExtensionDescriptor> HarvestExtensions(string path, string extensionType, string manifestName, bool manifestIsOptional) {
|
||||
string key = string.Format("{0}-{1}-{2}", path, manifestName, extensionType);
|
||||
|
||||
return _cacheManager.Get(key, ctx => {
|
||||
return _cacheManager.Get(key, true, ctx => {
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", path);
|
||||
ctx.Monitor(_webSiteFolder.WhenPathChanges(path));
|
||||
@@ -100,6 +101,9 @@ namespace Orchard.Environment.Extensions.Folders {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Ignore invalid module manifests
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "The module '{0}' could not be loaded. It was ignored.", extensionId);
|
||||
_criticalErrorProvider.RegisterErrorMessage(T("The extension '{0}' manifest could not be loaded. It was ignored.", extensionId));
|
||||
}
|
||||
@@ -134,7 +138,7 @@ namespace Orchard.Environment.Extensions.Folders {
|
||||
}
|
||||
|
||||
private ExtensionDescriptor GetExtensionDescriptor(string locationPath, string extensionId, string extensionType, string manifestPath, bool manifestIsOptional) {
|
||||
return _cacheManager.Get(manifestPath, context => {
|
||||
return _cacheManager.Get(manifestPath, true, context => {
|
||||
if (!DisableMonitoring) {
|
||||
Logger.Debug("Monitoring virtual path \"{0}\"", manifestPath);
|
||||
context.Monitor(_webSiteFolder.WhenPathChanges(manifestPath));
|
||||
|
@@ -4,6 +4,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IAssemblyLoader {
|
||||
@@ -25,8 +27,11 @@ namespace Orchard.Environment {
|
||||
try {
|
||||
return _loadedAssemblies.GetOrAdd(this.ExtractAssemblyShortName(assemblyName), shortName => LoadWorker(shortName, assemblyName));
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "Error loading assembly '{0}'", assemblyName);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "Error loading assembly '{0}'", assemblyName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ namespace Orchard.Environment {
|
||||
public string Resolve(string shortName) {
|
||||
// A few common .net framework assemblies are referenced by the Orchard.Framework assembly.
|
||||
// Look into those to see if we can find the assembly we are looking for.
|
||||
var orchardFrameworkReferences = _cacheManager.Get(typeof(IAssemblyLoader), ctx =>
|
||||
var orchardFrameworkReferences = _cacheManager.Get(typeof(IAssemblyLoader), true, ctx =>
|
||||
ctx.Key.Assembly
|
||||
.GetReferencedAssemblies()
|
||||
.GroupBy(n => AssemblyLoaderExtensions.ExtractAssemblyShortName(n.FullName), StringComparer.OrdinalIgnoreCase)
|
||||
|
@@ -53,8 +53,9 @@ namespace Orchard.Environment {
|
||||
return BuildManager.GetCompiledAssembly(virtualPath);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) throw;
|
||||
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Warning(ex, "Error when compiling assembly under {0}.", virtualPath);
|
||||
return null;
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ using Orchard.Environment.Descriptor;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IHostLocalRestart {
|
||||
@@ -45,8 +46,11 @@ namespace Orchard.Environment {
|
||||
try {
|
||||
_appDataFolder.CreateFile(fileName, "Host Restart");
|
||||
}
|
||||
catch(Exception e) {
|
||||
Logger.Warning(e, "Error updating file '{0}'", fileName);
|
||||
catch(Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Warning(ex, "Error updating file '{0}'", fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ using System.Timers;
|
||||
using System.Web.Compilation;
|
||||
using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Environment {
|
||||
public interface IViewsBackgroundCompilation {
|
||||
@@ -136,10 +137,13 @@ namespace Orchard.Environment {
|
||||
if (firstFile != null)
|
||||
BuildManager.GetCompiledAssembly(firstFile);
|
||||
}
|
||||
catch(Exception e) {
|
||||
catch(Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
// Some views might not compile, this is ok and harmless in this
|
||||
// context of pre-compiling views.
|
||||
Logger.Information(e, "Compilation of directory '{0}' skipped", viewDirectory);
|
||||
Logger.Information(ex, "Compilation of directory '{0}' skipped", viewDirectory);
|
||||
}
|
||||
stopwatch.Stop();
|
||||
Logger.Information("Directory '{0}' compiled in {1} msec", viewDirectory, stopwatch.ElapsedMilliseconds);
|
||||
|
@@ -53,6 +53,9 @@ namespace Orchard.Events {
|
||||
return TryInvoke(eventHandler, messageName, interfaceName, methodName, eventData, out returnValue);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
if (exception.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
if (!_exceptionPolicy.HandleException(this, exception)) {
|
||||
throw;
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Validation;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.FileSystems.AppData {
|
||||
public class AppDataFolder : IAppDataFolder {
|
||||
@@ -78,8 +79,11 @@ namespace Orchard.FileSystems.AppData {
|
||||
try {
|
||||
File.Delete(destinationFileName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new OrchardCoreException(T("Unable to make room for file \"{0}\" in \"App_Data\" folder", destinationFileName), e);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
throw new OrchardCoreException(T("Unable to make room for file \"{0}\" in \"App_Data\" folder", destinationFileName), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,7 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
}
|
||||
|
||||
public IEnumerable<DependencyDescriptor> LoadDescriptors() {
|
||||
return _cacheManager.Get(PersistencePath,
|
||||
return _cacheManager.Get(PersistencePath, true,
|
||||
ctx => {
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
|
||||
|
@@ -5,6 +5,7 @@ using System.Xml.Linq;
|
||||
using Orchard.Caching;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.FileSystems.Dependencies {
|
||||
/// <summary>
|
||||
@@ -64,7 +65,7 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
}
|
||||
|
||||
public IEnumerable<ActivatedExtensionDescriptor> LoadDescriptors() {
|
||||
return _cacheManager.Get(PersistencePath, ctx => {
|
||||
return _cacheManager.Get(PersistencePath, true, ctx => {
|
||||
_appDataFolder.CreateDirectory(BasePath);
|
||||
|
||||
if (!DisableMonitoring) {
|
||||
@@ -135,8 +136,11 @@ namespace Orchard.FileSystems.Dependencies {
|
||||
return XDocument.Load(stream);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Information(e, "Error reading file '{0}'. Assuming empty.", persistancePath);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Information(ex, "Error reading file '{0}'. Assuming empty.", persistancePath);
|
||||
return new XDocument();
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ using System.Web.Hosting;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Validation;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.FileSystems.Media {
|
||||
public class FileSystemStorageProvider : IStorageProvider {
|
||||
@@ -155,6 +156,9 @@ namespace Orchard.FileSystems.Media {
|
||||
directoryInfo.Create();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
throw new ArgumentException(T("The folder could not be created at path: {0}. {1}", path, ex).ToString());
|
||||
}
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.FileSystems.VirtualPath {
|
||||
public class DefaultVirtualPathProvider : IVirtualPathProvider {
|
||||
@@ -59,9 +60,12 @@ namespace Orchard.FileSystems.VirtualPath {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
// The initial path might have been invalid (e.g. path indicates a path outside the application root)
|
||||
Logger.Information(e, "Path '{0}' cannot be made app relative", virtualPath);
|
||||
Logger.Information(ex, "Path '{0}' cannot be made app relative", virtualPath);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -156,8 +160,11 @@ namespace Orchard.FileSystems.VirtualPath {
|
||||
try {
|
||||
return FileExists(virtualPath);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Information(e, "File '{0}' can not be checked for existence. Assuming doesn't exist.", virtualPath);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Information(ex, "File '{0}' can not be checked for existence. Assuming doesn't exist.", virtualPath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ namespace Orchard.Localization.Services {
|
||||
}
|
||||
|
||||
public IEnumerable<string> ListCultures() {
|
||||
return _cacheManager.Get("Cultures", context => {
|
||||
return _cacheManager.Get("Cultures", true, context => {
|
||||
context.Monitor(_signals.When("culturesChanged"));
|
||||
|
||||
return _cultureRepository.Table.Select(o => o.Culture).ToList();
|
||||
|
@@ -90,7 +90,7 @@ namespace Orchard.Localization.Services {
|
||||
// Cache entry will be invalidated any time the directories hosting
|
||||
// the .po files are modified.
|
||||
private CultureDictionary LoadCulture(string culture) {
|
||||
return _cacheManager.Get(culture, ctx => {
|
||||
return _cacheManager.Get(culture, true, ctx => {
|
||||
ctx.Monitor(_signals.When("culturesChanged"));
|
||||
return new CultureDictionary {
|
||||
CultureName = culture,
|
||||
|
@@ -5,6 +5,7 @@ using Orchard.Logging;
|
||||
using Orchard.Messaging.Events;
|
||||
using Orchard.Messaging.Models;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Messaging.Services {
|
||||
[Obsolete]
|
||||
@@ -40,8 +41,11 @@ namespace Orchard.Messaging.Services {
|
||||
|
||||
PrepareAndSend(type, properties, context);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
Logger.Error(e, "An error occured while sending the message {0}", type);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "An error occured while sending the message {0}", type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +64,11 @@ namespace Orchard.Messaging.Services {
|
||||
|
||||
PrepareAndSend(type, properties, context);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Logger.Error(e, "An error occured while sending the message {0}", type);
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "An error occured while sending the message {0}", type);
|
||||
}
|
||||
}
|
||||
|
||||
|
144
src/Orchard/Mvc/Html/LinkExtensions.cs
Normal file
144
src/Orchard/Mvc/Html/LinkExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,6 +11,7 @@ using System.Web.Routing;
|
||||
using Autofac;
|
||||
using Orchard.Mvc.Routes;
|
||||
using Orchard.Settings;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Mvc {
|
||||
public class MvcModule : Module {
|
||||
@@ -31,7 +32,11 @@ namespace Orchard.Mvc {
|
||||
// The "Request" property throws at application startup on IIS integrated pipeline mode.
|
||||
var req = HttpContext.Current.Request;
|
||||
}
|
||||
catch (Exception) {
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -188,6 +188,7 @@
|
||||
<Compile Include="Security\IMembershipValidationService.cs" />
|
||||
<Compile Include="Localization\Services\ILocalizationStreamParser.cs" />
|
||||
<Compile Include="Localization\Services\LocalizationStreamParser.cs" />
|
||||
<Compile Include="Mvc\Html\LinkExtensions.cs" />
|
||||
<Compile Include="Security\ISslSettingsProvider.cs" />
|
||||
<Compile Include="Security\NullMembershipService.cs" />
|
||||
<Compile Include="Security\Providers\DefaultSslSettingsProvider.cs" />
|
||||
@@ -401,7 +402,7 @@
|
||||
<Compile Include="Services\IJsonConverter.cs" />
|
||||
<Compile Include="Settings\CurrentSiteWorkContext.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\DistributedLock.cs" />
|
||||
<Compile Include="Tasks\Locking\Services\IDistributedLockService.cs" />
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using Orchard.Data;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Tasks {
|
||||
|
||||
@@ -39,9 +40,13 @@ namespace Orchard.Tasks {
|
||||
task.Sweep();
|
||||
Logger.Information("Finished processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName);
|
||||
}
|
||||
catch (Exception e) {
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
_transactionManager.Cancel();
|
||||
Logger.Error(e, "Error while processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName);
|
||||
Logger.Error(ex, "Error while processing background task \"{0}\" on tenant \"{1}\".", taskName, _shellName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -44,30 +44,30 @@ namespace Orchard.Tasks.Locking.Services {
|
||||
if (dLock != null) {
|
||||
Logger.Debug("Successfully acquired lock '{0}'.", name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Warning("Failed to acquire lock '{0}' within the specified timeout ({1}).", name, timeout);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
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?
|
||||
}
|
||||
}
|
||||
|
||||
dLock = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public IDistributedLock AcquireLock(string name, TimeSpan? maxValidFor, TimeSpan? timeout) {
|
||||
try {
|
||||
DistributedLock result = AcquireLockInternal(name, maxValidFor, timeout, throwOnTimeout: true);
|
||||
Logger.Debug("Successfully acquired lock '{0}'.", name);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while trying to acquire lock '{0}'.", name);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DistributedLock AcquireLockInternal(string name, TimeSpan? maxValidFor, TimeSpan? timeout, bool throwOnTimeout) {
|
||||
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));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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: () => {
|
||||
Monitor.Exit(monitorObj);
|
||||
DeleteDistributedLockRecord(internalName);
|
||||
});
|
||||
});
|
||||
|
||||
_locks.Add(monitorObj, dLock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
Logger.Debug("Record for lock '{0}' could not be created for current machine within the specified timeout ({1}).", internalName, timeout);
|
||||
|
||||
|
||||
if (throwOnTimeout)
|
||||
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) {
|
||||
Monitor.Exit(monitorObj);
|
||||
|
||||
Logger.Error(ex, "An error occurred while trying to acquire lock '{0}'.", internalName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool EnsureDistributedLockRecord(string internalName, TimeSpan? maxValidFor) {
|
||||
var localMachineName = _machineNameProvider.GetMachineName();
|
||||
@@ -145,7 +145,7 @@ namespace Orchard.Tasks.Locking.Services {
|
||||
if (record == null) {
|
||||
// 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);
|
||||
|
||||
|
||||
repository.Create(new DistributedLockRecord {
|
||||
Name = internalName,
|
||||
MachineName = localMachineName,
|
||||
@@ -163,7 +163,7 @@ namespace Orchard.Tasks.Locking.Services {
|
||||
});
|
||||
|
||||
return hasLockRecord;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteDistributedLockRecord(string internalName) {
|
||||
try {
|
||||
@@ -177,9 +177,9 @@ namespace Orchard.Tasks.Locking.Services {
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal())
|
||||
throw;
|
||||
throw;
|
||||
Logger.Warning(ex, "An error occurred while deleting record for lock '{0}'.", internalName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool RepeatUntilTimeout(TimeSpan? timeout, TimeSpan repeatInterval, Func<bool> action) {
|
||||
@@ -198,14 +198,14 @@ namespace Orchard.Tasks.Locking.Services {
|
||||
if (action == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
using (var childLifetimeScope = _lifetimeScope.BeginLifetimeScope()) {
|
||||
var repository = childLifetimeScope.Resolve<IRepository<DistributedLockRecord>>();
|
||||
var transactionManager = childLifetimeScope.Resolve<ITransactionManager>();
|
||||
transactionManager.RequireNew(IsolationLevel.ReadCommitted);
|
||||
action(repository);
|
||||
using (var childLifetimeScope = _lifetimeScope.BeginLifetimeScope()) {
|
||||
var repository = childLifetimeScope.Resolve<IRepository<DistributedLockRecord>>();
|
||||
var transactionManager = childLifetimeScope.Resolve<ITransactionManager>();
|
||||
transactionManager.RequireNew(IsolationLevel.ReadCommitted);
|
||||
action(repository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string GetInternalLockName(string name) {
|
||||
// Prefix the requested lock name by a constant and the tenant name.
|
||||
return String.Format("DistributedLock:{0}:{1}", _shellSettings.Name, name);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Timers;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Tasks {
|
||||
|
||||
@@ -51,6 +52,10 @@ namespace Orchard.Tasks {
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
Logger.Warning(ex, "Problem in background tasks");
|
||||
}
|
||||
finally {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.Time {
|
||||
/// <summary>
|
||||
@@ -31,8 +32,11 @@ namespace Orchard.Time {
|
||||
TimeZone = TimeZoneInfo.FindSystemTimeZoneById(siteTimeZoneId)
|
||||
};
|
||||
}
|
||||
catch(Exception e) {
|
||||
Logger.Error(e, "TimeZone could not be loaded");
|
||||
catch(Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error(ex, "TimeZone could not be loaded");
|
||||
|
||||
// if the database could not be updated in time, ignore this provider
|
||||
return null;
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Logging;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Exceptions;
|
||||
|
||||
namespace Orchard.UI.Admin.Notification {
|
||||
public class NotificationManager : INotificationManager {
|
||||
@@ -22,8 +23,11 @@ namespace Orchard.UI.Admin.Notification {
|
||||
try {
|
||||
return n.GetNotifications();
|
||||
}
|
||||
catch(Exception e) {
|
||||
Logger.Error("An unhandled exception was thrown while generating a notification: " + n.GetType(), e);
|
||||
catch(Exception ex) {
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
Logger.Error("An unhandled exception was thrown while generating a notification: " + n.GetType(), ex);
|
||||
return Enumerable.Empty<NotifyEntry>();
|
||||
}
|
||||
}).ToList();
|
||||
|
@@ -16,8 +16,7 @@ namespace Orchard.Utility.Extensions {
|
||||
var sb = new StringBuilder(camel);
|
||||
|
||||
for (int i = camel.Length-1; i>0; i--) {
|
||||
var current = sb[i];
|
||||
if('A' <= current && current <= 'Z') {
|
||||
if(char.IsUpper(sb[i])) {
|
||||
sb.Insert(i, ' ');
|
||||
}
|
||||
}
|
||||
@@ -357,4 +356,4 @@ namespace Orchard.Utility.Extensions {
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,8 @@
|
||||
"gulp-uglify": "^1.2.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-concat": "^2.5.2",
|
||||
"gulp-header": "^1.2.2"
|
||||
"gulp-header": "^1.2.2",
|
||||
"fs": "^0.0.2"
|
||||
},
|
||||
"dependencies": { }
|
||||
}
|
||||
|
Reference in New Issue
Block a user