Compare commits

...

18 Commits

Author SHA1 Message Date
Sebastiaan Janssen 1e2598a3a3 Bumps version to 7.8.2 2018-04-12 16:36:41 +02:00
Sebastiaan Janssen 19241995e8 Cherry picked - Fix scope leaks caused by database messenger [U4-11207] #2580 2018-04-12 16:23:33 +02:00
Sebastiaan Jansssen 3097a46ab3 Merge remote-tracking branch 'origin/dev-v7' into dev-v7.8
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
2018-02-09 09:57:00 +01:00
Sebastiaan Jansssen c63156fcd8 Bump version to 7.7.11
(cherry picked from commit 0c25c36af0)
2018-02-09 09:53:52 +01:00
Stephan 84a90884e3 Merge pull request #2433 from umbraco/temp-U4-10947
Fix for not being able to save decimal value
2018-02-09 08:14:51 +01:00
Shannon d29b7311fa reverts the convertible2 back to what it was before 2018-02-09 10:08:25 +11:00
Shannon 17b59cc20f Updates the ObjectExtensions TryConvertTo code and moved all unit tests to ObjectExtensionsTests which now all pass 2018-02-09 10:02:51 +11:00
Robert 4423571eaa Added ConvertToNullableDecimalTest and check that fixes the decimal save issue 2018-02-08 16:21:09 +01:00
Sebastiaan Jansssen 28eb4ff03a Bump version to 7.8.1 2018-02-08 14:08:38 +01:00
Sebastiaan Jansssen 79517f171c Update UI.xml when upgrading 2018-02-08 14:07:54 +01:00
Stephan e76c42f874 Merge pull request #2434 from umbraco/temp-U4-U4-10950
Fix checkbox in nested content
2018-02-08 13:42:42 +01:00
Robert 151c35bc47 Moving check to TryToConvertValueToCrlType 2018-02-08 13:15:43 +01:00
Robert 84265a9716 Fix checkbox in nested content 2018-02-08 12:18:51 +01:00
Robert 6618388973 Fix for not being able to save decimal value 2018-02-08 12:10:57 +01:00
Warren Buckley b280bf73aa Merge pull request #2429 from umbraco/temp-U4-10937
U4-10937 Datepicker on Info tabe and dates on audit trail do not work…
2018-02-07 12:13:19 +00:00
Shannon a6d57a5f6d Updates the dateHelper when converting to a local date, we need to check if the current string format is in UTC format and ensure that it's loaded that way 2018-02-07 12:51:15 +11:00
Shannon 6b7a83c6c9 Updates logic for setting the scheduled publishing date/times to ensure that the local date/time is displayed but the server time is persisted 2018-02-07 11:17:02 +11:00
Sebastiaan Jansssen eb5f2e29a3 U4-10937 Datepicker on Info tabe and dates on audit trail do not work if server time needs offsetting 2018-02-06 19:15:15 +01:00
16 changed files with 827 additions and 652 deletions
+25
View File
@@ -118,6 +118,31 @@ if ($project) {
{
# Not a big problem if this fails, let it go
}
Try
{
$uiXmlConfigPath = Join-Path $umbracoFolder -ChildPath "Config" | Join-Path -ChildPath "create" | Join-Path -ChildPath "UI.xml"
$uiXmlFile = Join-Path $umbracoFolder -ChildPath "Config" | Join-Path -ChildPath "create" | Join-Path -ChildPath "UI.xml"
$uiXml = New-Object System.Xml.XmlDocument
$uiXml.PreserveWhitespace = $true
$uiXml.Load($uiXmlFile)
$createExists = $uiXml.SelectNodes("//nodeType[@alias='macros']/tasks/create")
if($createExists.Count -eq 0)
{
$macrosTasksNode = $uiXml.SelectNodes("//nodeType[@alias='macros']/tasks")
#Creating: <create assembly="umbraco" type="macroTasks" />
$createNode = $uiXml.CreateElement("create")
$createNode.SetAttribute("assembly", "umbraco")
$createNode.SetAttribute("type", "macroTasks")
$macrosTasksNode.AppendChild($createNode)
$uiXml.Save($uiXmlFile)
}
}
Catch { }
}
$installFolder = Join-Path $projectPath "Install"
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.8.0")]
[assembly: AssemblyInformationalVersion("7.8.0")]
[assembly: AssemblyFileVersion("7.8.2")]
[assembly: AssemblyInformationalVersion("7.8.2")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.8.0");
private static readonly Version Version = new Version("7.8.2");
/// <summary>
/// Gets the current version of Umbraco.
+12 -3
View File
@@ -143,6 +143,7 @@ namespace Umbraco.Core
var inputString = input as string;
if (inputString != null)
{
//TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null?
if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool)))
{
return Attempt<object>.Succeed(null);
@@ -208,6 +209,14 @@ namespace Umbraco.Core
return Attempt.Succeed(outputConverter.ConvertFrom(input));
}
if (target.IsGenericType && GetCachedGenericNullableType(target) != null)
{
// cannot Convert.ChangeType as that does not work with nullable
// input has already been converted to the underlying type - just
// return input, there's an implicit conversion from T to T? anyways
return Attempt.Succeed(input);
}
// Re-check convertables since we altered the input through recursion
var convertible2 = input as IConvertible;
if (convertible2 != null)
@@ -745,9 +754,9 @@ namespace Umbraco.Core
if (AssignableTypeCache.TryGetValue(key, out canConvert))
{
return canConvert;
}
// "object is" is faster than "Type.IsAssignableFrom.
}
// "object is" is faster than "Type.IsAssignableFrom.
// We can use it to very quickly determine whether true/false
if (input is IConvertible && target.IsAssignableFrom(source))
{
+7 -8
View File
@@ -402,7 +402,7 @@ namespace Umbraco.Core.Persistence
}
// Helper to handle named parameters from object properties
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
{
return rxParams.Replace(_sql, m =>
@@ -545,7 +545,7 @@ namespace Umbraco.Core.Persistence
}
// Create a command
static Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
static readonly Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args)
{
// Perform named argument replacements
@@ -666,8 +666,8 @@ namespace Umbraco.Core.Persistence
return ExecuteScalar<T>(sql.SQL, sql.Arguments);
}
Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string AddSelectClause<T>(string sql)
{
if (sql.StartsWith(";"))
@@ -701,9 +701,9 @@ namespace Umbraco.Core.Persistence
return Fetch<T>(sql.SQL, sql.Arguments);
}
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{
sqlSelectRemoved = null;
@@ -2546,5 +2546,4 @@ namespace Umbraco.Core.Persistence
}
}
}
}
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.Models;
@@ -176,6 +176,12 @@ namespace Umbraco.Core.PropertyEditors
/// <returns></returns>
internal Attempt<object> TryConvertValueToCrlType(object value)
{
var jv = value as JValue;
if (jv != null)
{
value = value.ToString();
}
//this is a custom check to avoid any errors, if it's a string and it's empty just make it null
var s = value as string;
if (s != null)
@@ -391,4 +397,4 @@ namespace Umbraco.Core.PropertyEditors
}
}
}
}
}
+3
View File
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Scoping
public NoScope(ScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
Timestamp = DateTime.Now;
#if DEBUG_SCOPES
_scopeProvider.RegisterScope(this);
#endif
@@ -28,6 +29,8 @@ namespace Umbraco.Core.Scoping
private readonly Guid _instanceId = Guid.NewGuid();
public Guid InstanceId { get { return _instanceId; } }
public DateTime Timestamp { get; }
/// <inheritdoc />
public bool CallContext { get { return false; } }
+1 -1
View File
@@ -374,7 +374,7 @@ namespace Umbraco.Core.Scoping
}
var parent = ParentScope;
_scopeProvider.AmbientScope = parent;
_scopeProvider.AmbientScope = parent; // might be null = this is how scopes are removed from context objects
#if DEBUG_SCOPES
_scopeProvider.Disposed(this);
+51 -6
View File
@@ -2,10 +2,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Web;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
#if DEBUG_SCOPES
using System.Linq;
@@ -66,22 +68,38 @@ namespace Umbraco.Core.Scoping
// tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
// but we don't want to make all of our objects serializable since they are *not* meant to be
// used in cross-AppDomain scenario anyways.
//
// in addition, whatever goes into the logical call context is serialized back and forth any
// time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
// "object" instance - and so we cannot use a random object as a key.
// time cross-AppDomain code executes, so if we put an "object" there, we'll get *another*
// "object" instance back - and so we cannot use a random object as a key.
//
// so what we do is: we register a guid in the call context, and we keep a table mapping those
// guids to the actual objects. the guid serializes back and forth without causing any issue,
// and we can retrieve the actual objects from the table.
// only issue: how are we supposed to clear the table? we can't, really. objects should take
// care of de-registering themselves from context.
// everything we use does, except the NoScope scope, which just stays there
//
// during tests, NoScope can to into call context... nothing much we can do about it
// so far, the only objects that go into this table are scopes (using ScopeItemKey) and
// scope contexts (using ContextItemKey).
private static readonly object StaticCallContextObjectsLock = new object();
private static readonly Dictionary<Guid, object> StaticCallContextObjects
= new Dictionary<Guid, object>();
// normal scopes and scope contexts take greate care removing themselves when disposed, so it
// is all safe. OTOH the NoScope *CANNOT* remove itself, this is by design, it *WILL* leak and
// there is little (nothing) we can do about it - NoScope exists for backward compatibility
// reasons and relying on it is greatly discouraged.
//
// however... we can *try* at protecting the app against memory leaks, by collecting NoScope
// instances that are too old. if anything actually *need* to retain a NoScope instance for
// a long time, it will break. but that's probably ok. so: the constants below define how
// long a NoScope instance can stay in the table before being removed, and how often we should
// collect the table - and collecting happens anytime SetCallContextObject is invoked
private static readonly TimeSpan StaticCallContextNoScopeLifeSpan = TimeSpan.FromMinutes(30);
private static readonly TimeSpan StaticCallContextCollectPeriod = TimeSpan.FromMinutes(4);
private static DateTime _staticCallContextLastCollect = DateTime.MinValue;
#if DEBUG_SCOPES
public Dictionary<Guid, object> CallContextObjects
{
@@ -156,6 +174,7 @@ namespace Umbraco.Core.Scoping
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Remove(objectKey);
CollectStaticCallContextObjectsLocked();
}
}
else
@@ -171,11 +190,37 @@ namespace Umbraco.Core.Scoping
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Add(objectKey, value);
CollectStaticCallContextObjectsLocked();
}
CallContext.LogicalSetData(key, objectKey);
}
}
private static void CollectStaticCallContextObjectsLocked()
{
// is it time to collect?
var now = DateTime.Now;
if (now - _staticCallContextLastCollect <= StaticCallContextCollectPeriod)
return;
// disable warning: this method is invoked from within a lock
// ReSharper disable InconsistentlySynchronizedField
var threshold = now.Add(-StaticCallContextNoScopeLifeSpan);
var guids = StaticCallContextObjects
.Where(x => x.Value is NoScope noScope && noScope.Timestamp < threshold)
.Select(x => x.Key)
.ToList();
if (guids.Count > 0)
{
LogHelper.Warn<ScopeProvider>($"Collected {guids.Count} NoScope instances from StaticCallContextObjects.");
foreach (var guid in guids)
StaticCallContextObjects.Remove(guid);
}
// ReSharper restore InconsistentlySynchronizedField
_staticCallContextLastCollect = now;
}
// this is for tests exclusively until we have a proper accessor in v8
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
+151 -9
View File
@@ -6,6 +6,10 @@ using System.Threading;
using System.Web.UI.WebControls;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests
{
@@ -155,7 +159,7 @@ namespace Umbraco.Tests
Assert.AreEqual("Hello world", result.Result);
}
[Test]
[Test]
public virtual void CanConvertObjectToSameObject()
{
var obj = new MyTestObject();
@@ -164,7 +168,142 @@ namespace Umbraco.Tests
Assert.AreEqual(obj, result.Result);
}
private CultureInfo savedCulture;
[Test]
public void ConvertToIntegerTest()
{
var conv = "100".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = "100.000".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = "100,000".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
// oops
conv = "100.001".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = 100m.TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = 100.000m.TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
// oops
conv = 100.001m.TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
}
[Test]
public void ConvertToDecimalTest()
{
var conv = "100".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100.000".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100,000".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100.001".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100.001m, conv.Result);
conv = 100m.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = 100.000m.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = 100.001m.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100.001m, conv.Result);
conv = 100.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
}
[Test]
public void ConvertToNullableDecimalTest()
{
var conv = "100".TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100.000".TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100,000".TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100.001".TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100.001m, conv.Result);
conv = 100m.TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = 100.000m.TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = 100.001m.TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100.001m, conv.Result);
conv = 100.TryConvertTo<decimal?>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
}
[Test]
public void ConvertToDateTimeTest()
{
var conv = "2016-06-07".TryConvertTo<DateTime?>();
Assert.IsTrue(conv);
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
}
[Test]
public void ConvertToNullableDateTimeTest()
{
var conv = "2016-06-07".TryConvertTo<DateTime>();
Assert.IsTrue(conv);
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
}
[Test]
public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type()
{
var valueEditor = new PropertyValueEditor
{
ValueType = PropertyEditorValueTypes.Decimal
};
var result = valueEditor.TryConvertValueToCrlType(12.34d);
Assert.IsTrue(result.Success);
Assert.AreEqual(12.34d, result.Result);
}
private CultureInfo _savedCulture;
/// <summary>
/// Run once before each test in derived test fixtures.
@@ -172,10 +311,13 @@ namespace Umbraco.Tests
[SetUp]
public void TestSetup()
{
savedCulture = Thread.CurrentThread.CurrentCulture;
_savedCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); // make sure the dates parse correctly
return;
}
var settings = SettingsForTests.GetDefault();
ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig());
Resolution.Freeze();
}
/// <summary>
/// Run once after each test in derived test fixtures.
@@ -183,9 +325,9 @@ namespace Umbraco.Tests
[TearDown]
public void TestTearDown()
{
Thread.CurrentThread.CurrentCulture = savedCulture;
return;
}
Thread.CurrentThread.CurrentCulture = _savedCulture;
ShortStringHelperResolver.Reset();
}
private class MyTestObject
{
@@ -195,4 +337,4 @@ namespace Umbraco.Tests
}
}
}
}
}
-105
View File
@@ -1,105 +0,0 @@
using System;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Strings;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests
{
[TestFixture]
public class TryConvertToTests
{
[SetUp]
public void SetUp()
{
var settings = SettingsForTests.GetDefault();
ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig());
Resolution.Freeze();
}
[TearDown]
public void TearDown()
{
ShortStringHelperResolver.Reset();
}
[Test]
public void ConvertToIntegerTest()
{
var conv = "100".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = "100.000".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = "100,000".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
// oops
conv = "100.001".TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = 100m.TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
conv = 100.000m.TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
// oops
conv = 100.001m.TryConvertTo<int>();
Assert.IsTrue(conv);
Assert.AreEqual(100, conv.Result);
}
[Test]
public void ConvertToDecimalTest()
{
var conv = "100".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100.000".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100,000".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = "100.001".TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100.001m, conv.Result);
conv = 100m.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = 100.000m.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
conv = 100.001m.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100.001m, conv.Result);
conv = 100.TryConvertTo<decimal>();
Assert.IsTrue(conv);
Assert.AreEqual(100m, conv.Result);
}
[Test]
public void ConvertToDateTimeTest()
{
var conv = "2016-06-07".TryConvertTo<DateTime>();
Assert.IsTrue(conv);
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
}
}
}
-1
View File
@@ -232,7 +232,6 @@
<Compile Include="Services\CachedDataTypeServiceTests.cs" />
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
<Compile Include="TestHelpers\Entities\MockedUserGroup.cs" />
<Compile Include="TryConvertToTests.cs" />
<Compile Include="UdiTests.cs" />
<Compile Include="UmbracoExamine\RandomIdRAMDirectory.cs" />
<Compile Include="UmbracoExamine\UmbracoContentIndexerTests.cs" />
@@ -149,8 +149,17 @@
function setPublishDate(date) {
if (!date) {
return;
}
//The date being passed in here is the user's local date/time that they have selected
//we need to convert this date back to the server date on the model.
var serverTime = dateHelper.convertToServerStringTime(moment(date), Umbraco.Sys.ServerVariables.application.serverTimeOffset);
// update publish value
scope.node.releaseDate = date;
scope.node.releaseDate = serverTime;
// make sure dates are formatted to the user's locale
formatDatesToLocal();
@@ -174,8 +183,17 @@
function setUnpublishDate(date) {
if (!date) {
return;
}
//The date being passed in here is the user's local date/time that they have selected
//we need to convert this date back to the server date on the model.
var serverTime = dateHelper.convertToServerStringTime(moment(date), Umbraco.Sys.ServerVariables.application.serverTimeOffset);
// update publish value
scope.node.removeDate = date;
scope.node.removeDate = serverTime;
// make sure dates are formatted to the user's locale
formatDatesToLocal();
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -1024,12 +1024,15 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7820</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7820</IISUrl>
<DevelopmentServerPort>7800</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7800</IISUrl>
<DevelopmentServerPort>7800</DevelopmentServerPort>
<DevelopmentServerPort>7711</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7800</IISUrl>
<IISUrl>http://localhost:7711</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -9,6 +9,7 @@ using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Sync;
using Umbraco.Web.Routing;
using Umbraco.Core.Logging;
using Umbraco.Core.Scoping;
using Umbraco.Web.Scheduling;
namespace Umbraco.Web
@@ -21,9 +22,12 @@ namespace Umbraco.Web
/// </remarks>
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
{
private readonly ApplicationContext _appContext;
public BatchedDatabaseServerMessenger(ApplicationContext appContext, bool enableDistCalls, DatabaseServerMessengerOptions options)
: base(appContext, enableDistCalls, options)
{
_appContext = appContext;
Scheduler.Initializing += Scheduler_Initializing;
}
@@ -42,7 +46,7 @@ namespace Umbraco.Web
//start the background task runner for processing instructions
const int delayMilliseconds = 60000;
var instructionProcessingRunner = new BackgroundTaskRunner<IBackgroundTask>("InstructionProcessing", ApplicationContext.ProfilingLogger.Logger);
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, delayMilliseconds, Options.ThrottleSeconds * 1000);
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, _appContext.ScopeProvider, delayMilliseconds, Options.ThrottleSeconds * 1000);
instructionProcessingRunner.TryAdd(instructionProcessingTask);
e.Add(instructionProcessingTask);
}
@@ -73,18 +77,31 @@ namespace Umbraco.Web
private class InstructionProcessing : RecurringTaskBase
{
private readonly DatabaseServerMessenger _messenger;
private readonly IScopeProvider _scopeProvider;
public InstructionProcessing(IBackgroundTaskRunner<RecurringTaskBase> runner,
DatabaseServerMessenger messenger,
IScopeProvider scopeProvider,
int delayMilliseconds, int periodMilliseconds)
: base(runner, delayMilliseconds, periodMilliseconds)
{
_messenger = messenger;
_scopeProvider = scopeProvider;
}
public override bool PerformRun()
{
_messenger.Sync();
// beware!
// DatabaseServerMessenger uses _appContext.DatabaseContext.Database without creating
// scopes, and since we are running in a background task, there will be no ambient
// scope (as would be the case within a web request), and so we would end up creating
// (and leaking) a NoScope instance, which is bad - better make sure we have a true
// scope here! - see U4-11207
using (var scope = _scopeProvider.CreateScope())
{
_messenger.Sync();
scope.Complete();
}
//return true to repeat
return true;
}
@@ -121,14 +138,17 @@ namespace Umbraco.Web
batch.Clear();
//Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
using (var scope = _appContext.ScopeProvider.CreateScope())
{
WriteInstructions(instructionsBatch);
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
{
WriteInstructions(scope, instructionsBatch);
}
scope.Complete();
}
}
private void WriteInstructions(IEnumerable<RefreshInstruction> instructions)
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
{
var dto = new CacheInstructionDto
{
@@ -137,8 +157,7 @@ namespace Umbraco.Web
OriginIdentity = LocalIdentity,
InstructionCount = instructions.Sum(x => x.JsonIdCount)
};
ApplicationContext.DatabaseContext.Database.Insert(dto);
scope.Database.Insert(dto);
}
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
@@ -179,16 +198,19 @@ namespace Umbraco.Web
if (batch == null)
{
//only write the json blob with a maximum count of the MaxProcessingInstructionCount
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
using (var scope = _appContext.ScopeProvider.CreateScope())
{
WriteInstructions(maxBatch);
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
{
WriteInstructions(scope, maxBatch);
}
scope.Complete();
}
}
else
{
batch.Add(new RefreshInstructionEnvelope(servers, refresher, instructions));
}
}
}
}
}
}