Refactoring shifts using reflection based accessors

This commit is contained in:
Sebastien Ros
2013-10-29 18:03:43 -07:00
parent d4e3664b76
commit 70af583078
19 changed files with 1092 additions and 152 deletions

View File

@@ -0,0 +1,30 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
using Orchard.ContentManagement.Records;
namespace Orchard.Tests.ContentManagement {
public class ContentHelpers {
public static ContentItem PreparePart<TPart, TRecord>(TPart part, string contentType, int id = -1)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord, new() {
part.Record = new TRecord();
return PreparePart(part, contentType, id);
}
public static ContentItem PreparePart<TPart>(TPart part, string contentType, int id = -1)
where TPart : ContentPart {
var contentItem = part.ContentItem = new ContentItem {
VersionRecord = new ContentItemVersionRecord {
ContentItemRecord = new ContentItemRecord()
},
ContentType = contentType
};
contentItem.Record.Id = id;
contentItem.Weld(part);
contentItem.Weld(new InfosetPart());
return contentItem;
}
}
}

View File

@@ -0,0 +1,58 @@
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
using Orchard.ContentManagement.Records;
namespace Orchard.Tests.ContentManagement {
public class InfosetHelperTests {
[Test]
public void StoreByNameSavesIntoInfoset() {
var part = new TestPart();
ContentHelpers.PreparePart(part, "Test");
part.Foo = 42;
var infosetXml = part.As<InfosetPart>().Infoset.Element;
var testPartElement = infosetXml.Element(typeof (TestPart).Name);
Assert.That(testPartElement, Is.Not.Null);
var fooAttribute = testPartElement.Attr<int>("Foo");
Assert.That(part.Foo, Is.EqualTo(42));
Assert.That(fooAttribute, Is.EqualTo(42));
}
[Test]
public void RetrieveSavesIntoInfoset() {
var part = new TestPartWithRecord();
ContentHelpers.PreparePart<TestPartWithRecord, TestPartWithRecordRecord>(part, "Test");
part.Record.Foo = 42;
var infosetXml = part.As<InfosetPart>().Infoset.Element;
var testPartElement = infosetXml.Element(typeof (TestPartWithRecord).Name);
Assert.That(testPartElement, Is.Null);
var foo = part.Foo;
testPartElement = infosetXml.Element(typeof(TestPartWithRecord).Name);
Assert.That(testPartElement, Is.Not.Null);
var fooAttribute = testPartElement.Attr<int>("Foo");
Assert.That(foo, Is.EqualTo(42));
Assert.That(fooAttribute, Is.EqualTo(42));
}
public class TestPart : ContentPart {
public int Foo {
get { return this.Retrieve<int>("Foo"); }
set { this.Store("Foo", value); }
}
}
public class TestPartWithRecordRecord : ContentPartRecord {
public virtual int Foo { get; set; }
}
public class TestPartWithRecord : ContentPart<TestPartWithRecordRecord> {
public int Foo {
get { return Retrieve(r => r.Foo); }
set { Store(r => r.Foo, value); }
}
}
}
}

View File

@@ -0,0 +1,395 @@
using System;
using System.Linq;
using System.Xml.Linq;
using NUnit.Framework;
using Orchard.ContentManagement;
namespace Orchard.Tests.ContentManagement {
[TestFixture]
public class XmlHelperTests {
[Test]
public void AddEl() {
var el = new XElement("data");
el
.AddEl(new XElement("node1"), new XElement("node2"))
.AddEl(new XElement("node3"));
Assert.That(el.Descendants().Count(), Is.EqualTo(3));
Assert.That(el.Descendants().First().Name.ToString(), Is.EqualTo("node1"));
Assert.That(el.Descendants().ElementAt(1).Name.ToString(), Is.EqualTo("node2"));
Assert.That(el.Descendants().ElementAt(2).Name.ToString(), Is.EqualTo("node3"));
}
[Test]
public void Val() {
var el = new XElement("data");
el = el.Val(123);
var val = el.Val<int>();
Assert.That(val, Is.EqualTo(123));
Assert.That(el.ToString(SaveOptions.DisableFormatting),
Is.EqualTo("<data>123</data>"));
}
[Test]
public void Infinities() {
var el = new XElement("data")
.Attr("doubleplus", double.PositiveInfinity)
.Attr("doubleminus", double.NegativeInfinity)
.Attr("floatplus", float.PositiveInfinity)
.Attr("floatminus", float.NegativeInfinity);
Assert.That(el.Attr<string>("doubleplus"), Is.EqualTo("infinity"));
Assert.That(el.Attr<string>("doubleminus"), Is.EqualTo("-infinity"));
Assert.That(el.Attr<string>("floatplus"), Is.EqualTo("infinity"));
Assert.That(el.Attr<string>("floatminus"), Is.EqualTo("-infinity"));
Assert.That(double.IsPositiveInfinity(el.Attr<double>("doubleplus")), Is.True);
Assert.That(double.IsNegativeInfinity(el.Attr<double>("doubleminus")), Is.True);
Assert.That(double.IsPositiveInfinity(el.Attr<float>("floatplus")), Is.True);
Assert.That(double.IsNegativeInfinity(el.Attr<float>("floatminus")), Is.True);
}
[Test]
public void StringToAttribute() {
var el = new XElement("data");
el.Attr("foo", "bar");
Assert.That(el.Attribute("foo").Value, Is.EqualTo("bar"));
}
[Test]
public void IntToAttribute() {
var el = new XElement("data");
el.Attr("foo", 42);
Assert.That(el.Attribute("foo").Value, Is.EqualTo("42"));
}
[Test]
public void BoolToAttribute() {
var el = new XElement("data");
el.Attr("foo", true);
el.Attr("bar", false);
Assert.That(el.Attribute("foo").Value, Is.EqualTo("true"));
Assert.That(el.Attribute("bar").Value, Is.EqualTo("false"));
}
[Test]
public void DateTimeToAttribute() {
var el = new XElement("data");
el.Attr("foo", new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc));
Assert.That(el.Attribute("foo").Value, Is.EqualTo("1970-05-21T13:55:21.934Z"));
}
[Test]
public void DoubleFloatDecimalToAttribute() {
var el = new XElement("data");
el.Attr("double", 12.456D);
el.Attr("float", 12.457F);
el.Attr("decimal", 12.458M);
Assert.That(el.Attribute("double").Value, Is.EqualTo("12.456"));
Assert.That(el.Attribute("float").Value, Is.EqualTo("12.457"));
Assert.That(el.Attribute("decimal").Value, Is.EqualTo("12.458"));
}
[Test]
public void ReadAttribute() {
var el = XElement.Parse("<data foo=\"bar\"/>");
Assert.That(el.Attr("foo"), Is.EqualTo("bar"));
Assert.That(el.Attr("bar"), Is.Null);
}
[Test]
public void StringToElement() {
var el = new XElement("data");
el.El("foo", "bar");
Assert.That(el.Element("foo").Value, Is.EqualTo("bar"));
}
[Test]
public void IntToElement() {
var el = new XElement("data");
el.El("foo", 42);
Assert.That(el.Element("foo").Value, Is.EqualTo("42"));
}
[Test]
public void BoolToElement() {
var el = new XElement("data");
el.El("foo", true);
el.El("bar", false);
Assert.That(el.Element("foo").Value, Is.EqualTo("true"));
Assert.That(el.Element("bar").Value, Is.EqualTo("false"));
}
[Test]
public void DateTimeToElement() {
var el = new XElement("data");
el.El("foo", new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc));
Assert.That(el.Element("foo").Value, Is.EqualTo("1970-05-21T13:55:21.934Z"));
}
[Test]
public void DoubleFloatDecimalToElement() {
var el = new XElement("data");
el.El("double", 12.456D);
el.El("float", 12.457F);
el.El("decimal", 12.458M);
Assert.That(el.Element("double").Value, Is.EqualTo("12.456"));
Assert.That(el.Element("float").Value, Is.EqualTo("12.457"));
Assert.That(el.Element("decimal").Value, Is.EqualTo("12.458"));
}
[Test]
public void ReadElement() {
var el = XElement.Parse("<data><foo>bar</foo></data>");
Assert.That(el.El("foo"), Is.EqualTo("bar"));
Assert.That(el.El("bar"), Is.Null);
}
[Test]
public void SerializeObject() {
var target = new Target {
AString = "foo",
AnInt = 42,
ABoolean = true,
ADate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
ADouble = 12.345D,
AFloat = 23.456F,
ADecimal = 34.567M,
ANullableInt = 42,
ANullableBoolean = true,
ANullableDate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
ANullableDouble = 12.345D,
ANullableFloat = 23.456F,
ANullableDecimal = 34.567M
};
var el = new XElement("data");
el.With(target)
.ToAttr(t => t.AString)
.ToAttr(t => t.AnInt)
.ToAttr(t => t.ABoolean)
.ToAttr(t => t.ADate)
.ToAttr(t => t.ADouble)
.ToAttr(t => t.AFloat)
.ToAttr(t => t.ADecimal)
.ToAttr(t => t.ANullableInt)
.ToAttr(t => t.ANullableBoolean)
.ToAttr(t => t.ANullableDate)
.ToAttr(t => t.ANullableDouble)
.ToAttr(t => t.ANullableFloat)
.ToAttr(t => t.ANullableDecimal);
Assert.That(el.Attr("AString"), Is.EqualTo("foo"));
Assert.That(el.Attr("AnInt"), Is.EqualTo("42"));
Assert.That(el.Attr("ABoolean"), Is.EqualTo("true"));
Assert.That(el.Attr("ADate"), Is.EqualTo("1970-05-21T13:55:21.934Z"));
Assert.That(el.Attr("ADouble"), Is.EqualTo("12.345"));
Assert.That(el.Attr("AFloat"), Is.EqualTo("23.456"));
Assert.That(el.Attr("ADecimal"), Is.EqualTo("34.567"));
Assert.That(el.Attr("ANullableInt"), Is.EqualTo("42"));
Assert.That(el.Attr("ANullableBoolean"), Is.EqualTo("true"));
Assert.That(el.Attr("ANullableDate"), Is.EqualTo("1970-05-21T13:55:21.934Z"));
Assert.That(el.Attr("ANullableDouble"), Is.EqualTo("12.345"));
Assert.That(el.Attr("ANullableFloat"), Is.EqualTo("23.456"));
Assert.That(el.Attr("ANullableDecimal"), Is.EqualTo("34.567"));
}
[Test]
public void DeSerializeObject() {
var target = new Target();
var el =
XElement.Parse(
"<data AString=\"foo\" AnInt=\"42\" ABoolean=\"true\" " +
"ADate=\"1970-05-21T13:55:21.934Z\" ADouble=\"12.345\" " +
"AFloat=\"23.456\" ADecimal=\"34.567\" " +
"ANullableInt=\"42\" ANullableBoolean=\"true\" " +
"ANullableDate=\"1970-05-21T13:55:21.934Z\" ANullableDouble=\"12.345\" " +
"ANullableFloat=\"23.456\" ANullableDecimal=\"34.567\"/>");
el.With(target)
.FromAttr(t => t.AString)
.FromAttr(t => t.AnInt)
.FromAttr(t => t.ABoolean)
.FromAttr(t => t.ADate)
.FromAttr(t => t.ADouble)
.FromAttr(t => t.AFloat)
.FromAttr(t => t.ADecimal)
.FromAttr(t => t.ANullableInt)
.FromAttr(t => t.ANullableBoolean)
.FromAttr(t => t.ANullableDate)
.FromAttr(t => t.ANullableDouble)
.FromAttr(t => t.ANullableFloat)
.FromAttr(t => t.ANullableDecimal);
Assert.That(target.AString, Is.EqualTo("foo"));
Assert.That(target.AnInt, Is.EqualTo(42));
Assert.That(target.ABoolean, Is.True);
Assert.That(target.ADate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
Assert.That(target.ADouble, Is.EqualTo(12.345D));
Assert.That(target.AFloat, Is.EqualTo(23.456F));
Assert.That(target.ADecimal, Is.EqualTo(34.567M));
Assert.That(target.ANullableInt, Is.EqualTo(42));
Assert.That(target.ANullableBoolean, Is.True);
Assert.That(target.ANullableDate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
Assert.That(target.ANullableDouble, Is.EqualTo(12.345D));
Assert.That(target.ANullableFloat, Is.EqualTo(23.456F));
Assert.That(target.ANullableDecimal, Is.EqualTo(34.567M));
}
[Test]
public void DeSerializeFromMissingAttributeLeavesValueIntact() {
var target = new Target {
AString = "foo",
AnInt = 42,
ABoolean = true,
ADate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
ADouble = 12.345D,
AFloat = 23.456F,
ADecimal = 34.567M,
ANullableInt = 42,
ANullableBoolean = true,
ANullableDate = new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc),
ANullableDouble = 12.345D,
ANullableFloat = 23.456F,
ANullableDecimal = 34.567M
};
var el = new XElement("data");
el.With(target)
.FromAttr(t => t.AString)
.FromAttr(t => t.AnInt)
.FromAttr(t => t.ABoolean)
.FromAttr(t => t.ADate)
.FromAttr(t => t.ADouble)
.FromAttr(t => t.AFloat)
.FromAttr(t => t.ADecimal)
.FromAttr(t => t.ANullableInt)
.FromAttr(t => t.ANullableBoolean)
.FromAttr(t => t.ANullableDate)
.FromAttr(t => t.ANullableDouble)
.FromAttr(t => t.ANullableFloat)
.FromAttr(t => t.ANullableDecimal);
Assert.That(target.AString, Is.EqualTo("foo"));
Assert.That(target.AnInt, Is.EqualTo(42));
Assert.That(target.ABoolean, Is.True);
Assert.That(target.ADate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
Assert.That(target.ADouble, Is.EqualTo(12.345D));
Assert.That(target.AFloat, Is.EqualTo(23.456F));
Assert.That(target.ADecimal, Is.EqualTo(34.567M));
Assert.That(target.ANullableInt, Is.EqualTo(42));
Assert.That(target.ANullableBoolean, Is.True);
Assert.That(target.ANullableDate, Is.EqualTo(new DateTime(1970, 5, 21, 13, 55, 21, 934, DateTimeKind.Utc)));
Assert.That(target.ANullableDouble, Is.EqualTo(12.345D));
Assert.That(target.ANullableFloat, Is.EqualTo(23.456F));
Assert.That(target.ANullableDecimal, Is.EqualTo(34.567M));
}
[Test]
public void AttrWithContext() {
var el = new XElement("data")
.With(new {foo = 123})
.ToAttr(o => o.foo);
var val = el.Attr(o => o.foo);
Assert.That(val, Is.EqualTo(123));
}
[Test]
public void ContextSwitch() {
var el = new XElement("data");
el.With(new {foo = "bar"})
.ToAttr(o => o.foo)
.With(new {bar = "baz"})
.ToAttr(o => o.bar);
Assert.That(el.Attr<string>("foo"), Is.EqualTo("bar"));
Assert.That(el.Attr<string>("bar"), Is.EqualTo("baz"));
}
[Test]
public void ImplicitConversion() {
var el = new XElement("data")
.With(new {foo = "bar"})
.ToAttr(o => o.foo);
Func<XElement, string> func = e => e.Attr<string>("foo");
Assert.That(func(el), Is.EqualTo("bar"));
}
[Test]
public void NullSerializes() {
var target = new Target();
var el = new XElement("data");
el.With(target)
.ToAttr(t => t.AString)
.ToAttr(t => t.ANullableInt)
.ToAttr(t => t.ANullableBoolean)
.ToAttr(t => t.ANullableDate)
.ToAttr(t => t.ANullableDouble)
.ToAttr(t => t.ANullableFloat)
.ToAttr(t => t.ANullableDecimal);
Assert.That(el.Attr("AString"), Is.EqualTo(""));
Assert.That(el.Attr("ANullableInt"), Is.EqualTo("null"));
Assert.That(el.Attr("ANullableBoolean"), Is.EqualTo("null"));
Assert.That(el.Attr("ANullableDate"), Is.EqualTo("null"));
Assert.That(el.Attr("ANullableDouble"), Is.EqualTo("null"));
Assert.That(el.Attr("ANullableFloat"), Is.EqualTo("null"));
Assert.That(el.Attr("ANullableDecimal"), Is.EqualTo("null"));
}
[Test]
public void DeSerializeNull() {
var target = new Target();
var el =
XElement.Parse(
"<data AString=\"null\" ANullableInt=\"null\" ANullableBoolean=\"null\" " +
"ANullableDate=\"null\" ANullableDouble=\"null\" " +
"ANullableFloat=\"null\" ANullableDecimal=\"null\"/>");
el.With(target)
.FromAttr(t => t.AString)
.FromAttr(t => t.ANullableInt)
.FromAttr(t => t.ANullableBoolean)
.FromAttr(t => t.ANullableDate)
.FromAttr(t => t.ANullableDouble)
.FromAttr(t => t.ANullableFloat)
.FromAttr(t => t.ANullableDecimal);
Assert.That(target.AString, Is.EqualTo("null"));
Assert.That(target.ANullableInt, Is.Null);
Assert.That(target.ANullableBoolean, Is.Null);
Assert.That(target.ANullableDate, Is.Null);
Assert.That(target.ANullableDouble, Is.Null);
Assert.That(target.ANullableFloat, Is.Null);
Assert.That(target.ANullableDecimal, Is.Null);
}
private class Target {
public string AString { get; set; }
public int AnInt { get; set; }
public bool ABoolean { get; set; }
public DateTime ADate { get; set; }
public double ADouble { get; set; }
public float AFloat { get; set; }
public decimal ADecimal { get; set; }
public int? ANullableInt { get; set; }
public bool? ANullableBoolean { get; set; }
public DateTime? ANullableDate { get; set; }
public double? ANullableDouble { get; set; }
public float? ANullableFloat { get; set; }
public decimal? ANullableDecimal { get; set; }
}
}
}

View File

@@ -161,6 +161,7 @@
<Compile Include="Commands\CommandHandlerDescriptorBuilderTests.cs" />
<Compile Include="Commands\CommandHandlerTests.cs" />
<Compile Include="Commands\CommandManagerTests.cs" />
<Compile Include="ContentManagement\ContentHelpers.cs" />
<Compile Include="ContentManagement\ContentIdentityTests.cs">
<SubType>Code</SubType>
</Compile>
@@ -180,6 +181,7 @@
<Compile Include="ContentManagement\Handlers\GammaPartHandler.cs" />
<Compile Include="ContentManagement\Handlers\ModelBuilderTests.cs" />
<Compile Include="ContentManagement\ImportContentSessionTests.cs" />
<Compile Include="ContentManagement\InfosetHelperTests.cs" />
<Compile Include="ContentManagement\MetaData\Builders\ContentTypeDefinitionBuilderTests.cs" />
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionReaderTests.cs" />
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriterTests.cs" />
@@ -210,6 +212,7 @@
<Compile Include="ContentManagement\Records\GammaRecord.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\XmlHelperTests.cs" />
<Compile Include="DatabaseEnabledTestsBase.cs" />
<Compile Include="DataMigration\SchemaBuilderTests.cs" />
<Compile Include="DataMigration\DataMigrationTests.cs" />

View File

@@ -3,11 +3,8 @@ using Orchard.ContentManagement;
namespace Orchard.Core.Common.Models {
public class BodyPart : ContentPart<BodyPartRecord> {
public string Text {
get { return Get("Text"); }
set {
Set("Text", value);
Record.Text = value;
}
get { return Retrieve(x => x.Text); }
set { Store(x => x.Text, value); }
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Xml;
using Orchard.Core.Common.Utilities;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
@@ -23,73 +22,56 @@ namespace Orchard.Core.Common.Models {
get { return _container.Value; }
set { _container.Value = value; }
}
public DateTime? CreatedUtc {
get {
var dateTime = Get("CreatedUtc");
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
}
set {
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
Set("CreatedUtc", dateTime);
Record.CreatedUtc = value;
}
get { return Retrieve(x => x.CreatedUtc); }
set { Store(x => x.CreatedUtc, value); }
}
public DateTime? PublishedUtc {
get {
var dateTime = Get("PublishedUtc");
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
}
set {
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
Set("PublishedUtc", dateTime);
Record.PublishedUtc = value;
}
get { return Retrieve(x => x.PublishedUtc); }
set { Store(x => x.PublishedUtc, value); }
}
public DateTime? ModifiedUtc {
get { return Retrieve(x => x.ModifiedUtc); }
set { Store(x => x.ModifiedUtc, value); }
}
CommonPartVersionRecord PartVersionRecord {
get {
var dateTime = Get("ModifiedUtc");
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
}
set {
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
Set("ModifiedUtc", dateTime);
Record.ModifiedUtc = value;
var versionPart = this.As<ContentPart<CommonPartVersionRecord>>();
return versionPart == null ? null : versionPart.Record;
}
}
public DateTime? VersionCreatedUtc {
get {
var dateTime = this.As<ContentPart<CommonPartVersionRecord>>().Get("CreatedUtc");
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
return PartVersionRecord == null ? CreatedUtc : PartVersionRecord.CreatedUtc;
}
set {
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
this.As<ContentPart<CommonPartVersionRecord>>().Set("CreatedUtc", dateTime);
if (PartVersionRecord != null)
PartVersionRecord.CreatedUtc = value;
}
}
public DateTime? VersionPublishedUtc {
get {
var dateTime = this.As<ContentPart<CommonPartVersionRecord>>().Get("PublishedUtc");
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
return PartVersionRecord == null ? PublishedUtc : PartVersionRecord.PublishedUtc;
}
set {
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
this.As<ContentPart<CommonPartVersionRecord>>().Set("PublishedUtc", dateTime);
if (PartVersionRecord != null)
PartVersionRecord.PublishedUtc = value;
}
}
public DateTime? VersionModifiedUtc {
get {
var dateTime = this.As<ContentPart<CommonPartVersionRecord>>().Get("ModifiedUtc");
return String.IsNullOrEmpty(dateTime) ? (DateTime?)null : XmlConvert.ToDateTime(dateTime, XmlDateTimeSerializationMode.Utc);
return PartVersionRecord == null ? ModifiedUtc : PartVersionRecord.ModifiedUtc;
}
set {
string dateTime = value.HasValue ? XmlConvert.ToString(value.Value, XmlDateTimeSerializationMode.Utc) : "";
this.As<ContentPart<CommonPartVersionRecord>>().Set("ModifiedUtc", dateTime);
if (PartVersionRecord != null)
PartVersionRecord.ModifiedUtc = value;
}
}
}

View File

@@ -3,11 +3,8 @@ using Orchard.ContentManagement;
namespace Orchard.Core.Common.Models {
public class IdentityPart : ContentPart<IdentityPartRecord> {
public string Identifier {
get { return Get("Identifier"); }
set {
Set("Identifier", value);
Record.Identifier = value;
}
get { return Retrieve(x => x.Identifier); }
set { Store(x => x.Identifier, value); }
}
}
}

View File

@@ -1,48 +1,32 @@
using System.Globalization;
using Orchard.ContentManagement;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Navigation.Models {
public class MenuWidgetPart : ContentPart<MenuWidgetPartRecord> {
public int StartLevel {
get { return int.Parse(Get("StartLevel") ?? "0", CultureInfo.InvariantCulture); }
set {
Set("StartLevel", value.ToString(CultureInfo.InvariantCulture));
Record.StartLevel = value;
}
get { return Retrieve(x => x.StartLevel); }
set { Store(x => x.StartLevel, value); }
}
public int Levels {
get { return int.Parse(Get("Levels") ?? "0", CultureInfo.InvariantCulture); }
set {
Set("Levels", value.ToString(CultureInfo.InvariantCulture));
Record.Levels = value;
}
get { return Retrieve(x => x.Levels); }
set { Store(x => x.Levels, value); }
}
public bool Breadcrumb {
get { return bool.Parse(Get("Breadcrumb") ?? "false"); }
set {
Set("Breadcrumb", value.ToString());
Record.Breadcrumb = value;
}
get { return Retrieve(x => x.Breadcrumb); }
set { Store(x => x.Breadcrumb, value); }
}
public bool AddHomePage {
get { return bool.Parse(Get("AddHomePage") ?? "false"); }
set {
Set("AddHomePage", value.ToString());
Record.AddHomePage = value;
}
get { return Retrieve(x => x.AddHomePage); }
set { Store(x => x.AddHomePage, value); }
}
public bool AddCurrentPage {
get { return bool.Parse(Get("AddCurrentPage") ?? "false"); }
set {
Set("AddCurrentPage", value.ToString());
Record.AddCurrentPage = value;
}
get { return Retrieve(x => x.AddCurrentPage); }
set { Store(x => x.AddCurrentPage, value); }
}
public ContentItemRecord Menu {

View File

@@ -1,6 +1,4 @@
using System;
using System.Globalization;
using Orchard.ContentManagement;
using Orchard.ContentManagement;
using Orchard.Settings;
namespace Orchard.Core.Settings.Models {
@@ -8,55 +6,52 @@ namespace Orchard.Core.Settings.Models {
public const int DefaultPageSize = 10;
public string PageTitleSeparator {
get { return Get("PageTitleSeparator"); }
set { Set("PageTitleSeparator", value); }
get { return this.Retrieve(x => x.PageTitleSeparator); }
set { this.Store(x => x.PageTitleSeparator, value); }
}
public string SiteName {
get { return Get("SiteName"); }
set { Set("SiteName", value); }
get { return this.Retrieve(x => x.SiteName); }
set { this.Store(x => x.SiteName, value); }
}
public string SiteSalt {
get { return Get("SiteSalt"); }
set { Set("SiteSalt", value); }
get { return this.Retrieve(x => x.SiteSalt); }
set { this.Store(x => x.SiteSalt, value); }
}
public string SuperUser {
get { return Get("SuperUser"); }
set { Set("SuperUser", value); }
get { return this.Retrieve(x => x.SuperUser); }
set { this.Store(x => x.SuperUser, value); }
}
public string HomePage {
get { return Get("HomePage"); }
set { Set("HomePage", value); }
get { return this.Retrieve(x => x.HomePage); }
set { this.Store(x => x.HomePage, value); }
}
public string SiteCulture {
get { return Get("SiteCulture"); }
set { Set("SiteCulture", value); }
get { return this.Retrieve(x => x.SiteCulture); }
set { this.Store(x => x.SiteCulture, value); }
}
public ResourceDebugMode ResourceDebugMode {
get {
var value = Get("ResourceDebugMode");
return String.IsNullOrEmpty(value) ? ResourceDebugMode.Disabled : (ResourceDebugMode)Enum.Parse(typeof(ResourceDebugMode), value);
}
set { Set("ResourceDebugMode", value.ToString()); }
get { return this.Retrieve(x => x.ResourceDebugMode); }
set { this.Store(x => x.ResourceDebugMode, value); }
}
public int PageSize {
get { return int.Parse(Get("PageSize") ?? "0", CultureInfo.InvariantCulture); }
set { Set("PageSize", value.ToString(CultureInfo.InvariantCulture)); }
get { return this.Retrieve(x => x.PageSize); }
set { this.Store(x => x.PageSize, value); }
}
public string SiteTimeZone {
get { return Get("SiteTimeZone"); }
set { Set("SiteTimeZone", value); }
get { return this.Retrieve(x => x.SiteTimeZone); }
set { this.Store(x => x.SiteTimeZone, value); }
}
public string BaseUrl {
get { return Get("BaseUrl"); }
set { Set("BaseUrl", value); }
get { return this.Retrieve(x => x.BaseUrl); }
set { this.Store(x => x.BaseUrl, value); }
}
}
}

View File

@@ -6,13 +6,8 @@ namespace Orchard.Core.Title.Models {
public class TitlePart : ContentPart<TitlePartRecord>, ITitleAspect {
[Required]
public string Title {
get {
return Get("Title");
}
set {
Set("Title", value);
Record.Title = value;
}
get { return Retrieve(x => x.Title); }
set { Store(x => x.Title, value); }
}
}
}

View File

@@ -83,13 +83,6 @@ namespace Orchard.AntiSpam {
public class AkismetMigrations : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("AkismetSettingsPartRecord",
table => table.ContentPartVersionRecord()
.Column<bool>("TrustAuthenticatedUsers")
.Column<string>("ApiKey")
);
return 1;
}
}

View File

@@ -3,13 +3,13 @@
namespace Orchard.AntiSpam.Models {
public class AkismetSettingsPart : ContentPart {
public bool TrustAuthenticatedUsers {
get { return bool.Parse(Get("TrustAuthenticatedUsers") ?? "false"); }
set { Set("TrustAuthenticatedUsers", value.ToString()); }
get { return this.Retrieve(x => x.TrustAuthenticatedUsers); }
set { this.Store(x => x.TrustAuthenticatedUsers, value); }
}
public string ApiKey {
get { return Get("ApiKey"); }
set { Set("ApiKey", value); }
get { return this.Retrieve(x => x.ApiKey); }
set { this.Store(x => x.ApiKey, value); }
}
}
}

View File

@@ -5,27 +5,16 @@ namespace Orchard.Autoroute.Models {
public class AutoroutePart : ContentPart<AutoroutePartRecord>, IAliasAspect {
public string CustomPattern {
get { return Get("CustomPattern"); }
set {
Set("CustomPattern", value);
Record.CustomPattern = value;
}
get { return Retrieve(x => x.CustomPattern); }
set { Store(x => x.CustomPattern, value); }
}
public bool UseCustomPattern {
get { return bool.Parse(Get("UseCustomPattern")); }
set {
Set("UseCustomPattern", value.ToString());
Record.UseCustomPattern = value;
}
get { return Retrieve(x => x.UseCustomPattern); }
set { Store(x => x.UseCustomPattern, value); }
}
public string DisplayAlias {
get { return Get("DisplayAlias"); }
set {
Set("DisplayAlias", value);
Record.DisplayAlias = value;
}
get { return Retrieve(x => x.DisplayAlias); }
set { Store(x => x.DisplayAlias, value); }
}
public string Path {

View File

@@ -3,8 +3,8 @@
namespace Orchard.Themes.Models {
public class ThemeSiteSettingsPart : ContentPart {
public string CurrentThemeName {
get { return Get("CurrentThemeName"); }
set { Set("CurrentThemeName", value); }
get { return this.Retrieve(x => x.CurrentThemeName); }
set { this.Store(x => x.CurrentThemeName, value); }
}
}
}

View File

@@ -2,9 +2,9 @@ using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using Autofac;
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Records;
using Orchard.ContentManagement.Utilities;
@@ -79,33 +79,49 @@ namespace Orchard.ContentManagement {
return true;
}
public virtual string Get(string fieldName) {
return this.As<InfosetPart>().Get(GetType().Name, fieldName, null, false);
public T Retrieve<T>(string fieldName) {
return InfosetHelper.Retrieve<T>(this, fieldName);
}
public string GetVersioned(string fieldName) {
return this.As<InfosetPart>().Get(GetType().Name, fieldName, null, true);
public T RetrieveVersioned<T>(string fieldName) {
return this.Retrieve<T>(fieldName, true);
}
public virtual void Set(string fieldName, string value) {
this.As<InfosetPart>().Set(GetType().Name, fieldName, null, value, false);
public virtual void Store<T>(string fieldName, T value) {
InfosetHelper.Store(this, fieldName, value);
}
public void SetVersionned(string fieldName, string value) {
this.As<InfosetPart>().Set(GetType().Name, fieldName, null, value, true);
public virtual void StoreVersioned<T>(string fieldName, T value) {
this.Store(fieldName, value, true);
}
}
public class ContentPart<TRecord> : ContentPart {
static protected bool IsVersionableRecord { get; private set;}
static ContentPart() {
IsVersionableRecord = typeof (TRecord).IsAssignableTo<ContentItemVersionRecord>();
}
public override string Get(string fieldName) {
return this.As<InfosetPart>().Get(GetType().Name, fieldName, null, IsVersionableRecord);
protected TProperty Retrieve<TProperty>(Expression<Func<TRecord, TProperty>> targetExpression) {
return InfosetHelper.Retrieve(this, targetExpression);
}
public override void Set(string fieldName, string value) {
this.As<InfosetPart>().Set(GetType().Name, fieldName, null, value, IsVersionableRecord);
protected TProperty Retrieve<TProperty>(
Expression<Func<TRecord, TProperty>> targetExpression,
Func<TRecord, TProperty> defaultExpression) {
return InfosetHelper.Retrieve(this, targetExpression, defaultExpression);
}
protected ContentPart<TRecord> Store<TProperty>(
Expression<Func<TRecord, TProperty>> targetExpression,
TProperty value) {
InfosetHelper.Store(this, targetExpression, value);
return this;
}
public readonly LazyField<TRecord> _record = new LazyField<TRecord>();

View File

@@ -0,0 +1,112 @@
using System;
using System.Linq.Expressions;
using System.Xml.Linq;
using Orchard.ContentManagement.FieldStorage.InfosetStorage;
using Orchard.Utility;
namespace Orchard.ContentManagement {
public static class InfosetHelper {
public static TProperty Retrieve<TPart, TProperty>(this TPart contentPart,
Expression<Func<TPart, TProperty>> targetExpression,
bool versioned = false) where TPart : ContentPart {
var propertyInfo = ReflectionHelper<TPart>.GetPropertyInfo(targetExpression);
var name = propertyInfo.Name;
var infosetPart = contentPart.As<InfosetPart>();
var el = infosetPart == null
? null
: (versioned ? infosetPart.VersionInfoset.Element : infosetPart.Infoset.Element)
.Element(contentPart.GetType().Name);
return el == null ? default(TProperty) : el.Attr<TProperty>(name);
}
public static TProperty Retrieve<TProperty>(this ContentPart contentPart, string name,
bool versioned = false) {
var infosetPart = contentPart.As<InfosetPart>();
var el = infosetPart == null
? null
: (versioned ? infosetPart.VersionInfoset.Element : infosetPart.Infoset.Element)
.Element(contentPart.GetType().Name);
return el == null ? default(TProperty) : el.Attr<TProperty>(name);
}
public static void Store<TPart, TProperty>(this TPart contentPart,
Expression<Func<TPart, TProperty>> targetExpression,
TProperty value, bool versioned = false) where TPart : ContentPart {
var partName = contentPart.GetType().Name;
var infosetPart = contentPart.As<InfosetPart>();
var infoset = (versioned ? infosetPart.VersionInfoset : infosetPart.Infoset);
var partElement = infoset.Element.Element(partName);
if (partElement == null) {
partElement = new XElement(partName);
infoset.Element.Add(partElement);
}
var propertyInfo = ReflectionHelper<TPart>.GetPropertyInfo(targetExpression);
var name = propertyInfo.Name;
partElement.Attr(name, value);
}
public static void Store<TProperty>(this ContentPart contentPart, string name,
TProperty value, bool versioned = false) {
var partName = contentPart.GetType().Name;
var infosetPart = contentPart.As<InfosetPart>();
var infoset = (versioned ? infosetPart.VersionInfoset : infosetPart.Infoset);
var partElement = infoset.Element.Element(partName);
if (partElement == null) {
partElement = new XElement(partName);
infoset.Element.Add(partElement);
}
partElement.Attr(name, value);
}
public static TProperty Retrieve<TPart, TRecord, TProperty>(this TPart contentPart,
Expression<Func<TRecord, TProperty>> targetExpression)
where TPart : ContentPart<TRecord> {
var getter = ReflectionHelper<TRecord>.GetGetter(targetExpression);
return contentPart.Retrieve(targetExpression, getter);
}
public static TProperty Retrieve<TPart, TRecord, TProperty>(this TPart contentPart,
Expression<Func<TRecord, TProperty>> targetExpression,
Delegate defaultExpression)
where TPart : ContentPart<TRecord> {
var propertyInfo = ReflectionHelper<TRecord>.GetPropertyInfo(targetExpression);
var name = propertyInfo.Name;
var infosetPart = contentPart.As<InfosetPart>();
var el = infosetPart == null
? null
: infosetPart.Infoset.Element.Element(contentPart.GetType().Name);
if (el == null || el.Attribute(name) == null) {
// Property has never been stored. Get it from the default expression and store that.
var defaultValue = defaultExpression == null
? default(TProperty)
: (TProperty)defaultExpression.DynamicInvoke(contentPart.Record);
contentPart.Store(name, defaultValue);
return defaultValue;
}
return el.Attr<TProperty>(name);
}
public static void Store<TPart, TRecord, TProperty>(this TPart contentPart,
Expression<Func<TRecord, TProperty>> targetExpression,
TProperty value)
where TPart : ContentPart<TRecord> {
var propertyInfo = ReflectionHelper<TRecord>.GetPropertyInfo(targetExpression);
var name = propertyInfo.Name;
propertyInfo.SetValue(contentPart.Record, value, null);
contentPart.Store(name, value);
}
}
}

View File

@@ -0,0 +1,345 @@
using System;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Xml;
using System.Xml.Linq;
using Orchard.Utility;
namespace Orchard.ContentManagement {
public static class XmlHelper {
/// <summary>
/// Like Add, but chainable.
/// </summary>
/// <param name="el">The parent element.</param>
/// <param name="children">The elements to add.</param>
/// <returns>Itself</returns>
public static XElement AddEl(this XElement el, params XElement[] children) {
el.Add(children.Cast<object>());
return el;
}
/// <summary>
/// Gets the string value of an attribute, and null if the attribute doesn't exist.
/// </summary>
/// <param name="el">The element.</param>
/// <param name="name">The name of the attribute.</param>
/// <returns>The string value of the attribute if it exists, null otherwise.</returns>
public static string Attr(this XElement el, string name) {
var attr = el.Attribute(name);
return attr == null ? null : attr.Value;
}
/// <summary>
/// Gets a typed value from an attribute.
/// </summary>
/// <typeparam name="T">The type of the value</typeparam>
/// <param name="el">The element.</param>
/// <param name="name">The name of the attribute.</param>
/// <returns>The attribute value</returns>
public static T Attr<T>(this XElement el, string name) {
var attr = el.Attribute(name);
return attr == null ? default(T) : Parse<T>(attr.Value);
}
/// <summary>
/// Sets an attribute value. This is chainable.
/// </summary>
/// <typeparam name="T">The type of the value.</typeparam>
/// <param name="el">The element.</param>
/// <param name="name">The attribute name.</param>
/// <param name="value">The value to set.</param>
/// <returns>Itself</returns>
public static XElement Attr<T>(this XElement el, string name, T value) {
el.SetAttributeValue(name, ToString(value));
return el;
}
/// <summary>
/// Returns the text contents of a child element.
/// </summary>
/// <param name="el">The parent element.</param>
/// <param name="name">The name of the child element.</param>
/// <returns>The text for the child element, and null if it doesn't exist.</returns>
public static string El(this XElement el, string name) {
var childElement = el.Element(name);
return childElement == null ? null : childElement.Value;
}
/// <summary>
/// Creates and sets the value of a child element. This is chainable.
/// </summary>
/// <typeparam name="T">The type of the value.</typeparam>
/// <param name="el">The parent element.</param>
/// <param name="name">The name of the child element.</param>
/// <param name="value">The value to set.</param>
/// <returns>Itself</returns>
public static XElement El<T>(this XElement el, string name, T value) {
el.SetElementValue(name, value);
return el;
}
/// <summary>
/// Sets a property value from an attribute of the same name.
/// </summary>
/// <typeparam name="TTarget">The type of the target object.</typeparam>
/// <typeparam name="TProperty">The type of the target property</typeparam>
/// <param name="el">The element.</param>
/// <param name="target">The target object.</param>
/// <param name="targetExpression">The property expression.</param>
/// <returns>Itself</returns>
public static XElement FromAttr<TTarget, TProperty>(this XElement el, TTarget target,
Expression<Func<TTarget, TProperty>> targetExpression) {
if (target == null) return el;
var propertyInfo = ReflectionHelper<TTarget>.GetPropertyInfo(targetExpression);
var name = propertyInfo.Name;
var attr = el.Attribute(name);
if (attr == null) return el;
propertyInfo.SetValue(target, el.Attr<TProperty>(name), null);
return el;
}
/// <summary>
/// Sets an attribute with the value of a property of the same name.
/// </summary>
/// <typeparam name="TTarget">The type of the object.</typeparam>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="el">The element.</param>
/// <param name="target">The object.</param>
/// <param name="targetExpression">The property expression.</param>
/// <returns>Itself</returns>
public static XElement ToAttr<TTarget, TProperty>(this XElement el, TTarget target,
Expression<Func<TTarget, TProperty>> targetExpression) {
if (target == null) return el;
var propertyInfo = ReflectionHelper<TTarget>.GetPropertyInfo(targetExpression);
var name = propertyInfo.Name;
var val = (TProperty)propertyInfo.GetValue(target, null);
el.Attr(name, ToString(val));
return el;
}
/// <summary>
/// Gets the text value of an element as the specified type.
/// </summary>
/// <typeparam name="TValue">The type to parse the element as.</typeparam>
/// <param name="el">The element.</param>
/// <returns>The value of the element as type TValue.</returns>
public static TValue Val<TValue>(this XElement el) {
return Parse<TValue>(el.Value);
}
/// <summary>
/// Sets the value of an element.
/// </summary>
/// <typeparam name="TValue">The type of the value to set.</typeparam>
/// <param name="el">The element.</param>
/// <param name="value">The value.</param>
/// <returns>The element.</returns>
public static XElement Val<TValue>(this XElement el, TValue value) {
el.SetValue(ToString(value));
return el;
}
/// <summary>
/// Serializes the provided value as a string.
/// </summary>
/// <typeparam name="T">The type of the value.</typeparam>
/// <param name="value">The value.</param>
/// <returns>The string representation of the value.</returns>
public static string ToString<T>(T value) {
var type = typeof(T);
if (type == typeof(string)) {
return Convert.ToString(value);
}
if ((!type.IsValueType || Nullable.GetUnderlyingType(type) != null) &&
value == null &&
type != typeof(string)) {
return "null";
}
if (type == typeof(DateTime) || type == typeof(DateTime?)) {
return XmlConvert.ToString(Convert.ToDateTime(value),
XmlDateTimeSerializationMode.Utc);
}
if (type == typeof(bool) ||
type == typeof(bool?)) {
return Convert.ToBoolean(value) ? "true" : "false";
}
if (type == typeof(int) ||
type == typeof(int?)) {
return Convert.ToInt64(value).ToString(CultureInfo.InvariantCulture);
}
if (type == typeof(double) ||
type == typeof(double?)) {
var doubleValue = (double)(object)value;
if (double.IsPositiveInfinity(doubleValue)) {
return "infinity";
}
if (double.IsNegativeInfinity(doubleValue)) {
return "-infinity";
}
return doubleValue.ToString(CultureInfo.InvariantCulture);
}
if (type == typeof(float) ||
type == typeof(float?)) {
var floatValue = (float)(object)value;
if (float.IsPositiveInfinity(floatValue)) {
return "infinity";
}
if (float.IsNegativeInfinity(floatValue)) {
return "-infinity";
}
return floatValue.ToString(CultureInfo.InvariantCulture);
}
if (type == typeof(decimal) ||
type == typeof(decimal?)) {
var decimalValue = Convert.ToDecimal(value);
return decimalValue.ToString(CultureInfo.InvariantCulture);
}
throw new NotSupportedException(String.Format("Could not handle type {0}", type.Name));
}
/// <summary>
/// Parses a string value as the provided type.
/// </summary>
/// <typeparam name="T">The destination type</typeparam>
/// <param name="value">The string representation of the value to parse.</param>
/// <returns>The parsed value with type T.</returns>
public static T Parse<T>(string value) {
var type = typeof(T);
if (type == typeof(string)) {
return (T)(object)value;
}
if (value == null ||
"null".Equals(value, StringComparison.Ordinal) &&
((!type.IsValueType || Nullable.GetUnderlyingType(type) != null))) {
return default(T);
}
if ("infinity".Equals(value, StringComparison.Ordinal)) {
if (type == typeof(float) || type == typeof(float?)) return (T)(object)float.PositiveInfinity;
if (type == typeof(double) || type == typeof(double?)) return (T)(object)double.PositiveInfinity;
throw new NotSupportedException(String.Format("Infinity not supported for type {0}", type.Name));
}
if ("-infinity".Equals(value, StringComparison.Ordinal)) {
if (type == typeof(float)) return (T)(object)float.NegativeInfinity;
if (type == typeof(double)) return (T)(object)double.NegativeInfinity;
throw new NotSupportedException(String.Format("Infinity not supported for type {0}", type.Name));
}
if (type == typeof(int) || type == typeof(int?)) {
return (T)(object)int.Parse(value, CultureInfo.InvariantCulture);
}
if (type == typeof(bool) || type == typeof(bool?)) {
return (T)(object)value.Equals("true", StringComparison.Ordinal);
}
if (type == typeof(DateTime) || type == typeof(DateTime?)) {
return (T)(object)XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc);
}
if (type == typeof(double) || type == typeof(double?)) {
return (T)(object)double.Parse(value, CultureInfo.InvariantCulture);
}
if (type == typeof(float) || type == typeof(float?)) {
return (T)(object)float.Parse(value, CultureInfo.InvariantCulture);
}
if (type == typeof(decimal) || type == typeof(decimal?)) {
return (T)(object)decimal.Parse(value, CultureInfo.InvariantCulture);
}
throw new NotSupportedException(String.Format("Could not handle type {0}", type.Name));
}
/// <summary>
/// Gives context to an XElement, enabling chained property operations.
/// </summary>
/// <typeparam name="TContext">The type of the context.</typeparam>
/// <param name="el">The element.</param>
/// <param name="context">The context.</param>
/// <returns>The element with context.</returns>
public static XElementWithContext<TContext> With<TContext>(this XElement el, TContext context) {
return new XElementWithContext<TContext>(el, context);
}
/// <summary>
/// A wrapper for XElement, with context, for strongly-typed manipulation
/// of an XElement.
/// </summary>
/// <typeparam name="TContext">The type of the context.</typeparam>
public class XElementWithContext<TContext> {
public XElementWithContext(XElement element, TContext context) {
Element = element;
Context = context;
}
public XElement Element { get; private set; }
public TContext Context { get; private set; }
public static implicit operator XElement(XElementWithContext<TContext> elementWithContext) {
return elementWithContext.Element;
}
/// <summary>
/// Replaces the current context with a new one, enabling chained action on different objects.
/// </summary>
/// <typeparam name="TNewContext">The type of the new context.</typeparam>
/// <param name="context">The new context.</param>
/// <returns>A new XElementWithContext, that has the new context.</returns>
public XElementWithContext<TNewContext> With<TNewContext>(TNewContext context) {
return new XElementWithContext<TNewContext>(Element, context);
}
/// <summary>
/// Sets the value of a context property as an attribute of the same name on the element.
/// </summary>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="targetExpression">The property expression.</param>
/// <returns>Itself</returns>
public XElementWithContext<TContext> ToAttr<TProperty>(
Expression<Func<TContext, TProperty>> targetExpression) {
Element.ToAttr(Context, targetExpression);
return this;
}
/// <summary>
/// Gets an attribute on the element and sets the property of the same name on the context with its value.
/// </summary>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="targetExpression">The property expression.</param>
/// <returns>Itself</returns>
public XElementWithContext<TContext> FromAttr<TProperty>(
Expression<Func<TContext, TProperty>> targetExpression) {
Element.FromAttr(Context, targetExpression);
return this;
}
/// <summary>
/// Evaluates an attribute from an expression.
/// It's a nice strongly-typed way to read attributes.
/// </summary>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="expression">The property expression.</param>
/// <returns>The attribute, ready to be cast.</returns>
public TProperty Attr<TProperty>(Expression<Func<TContext, TProperty>> expression) {
var propertyInfo = ReflectionHelper<TContext>.GetPropertyInfo(expression);
var name = propertyInfo.Name;
return Element.Attr<TProperty>(name);
}
}
}
}

View File

@@ -159,6 +159,8 @@
<Compile Include="ContentManagement\Aspects\ILocalizableAspect.cs" />
<Compile Include="ContentManagement\ContentIdentity.cs" />
<Compile Include="ContentManagement\DefaultHqlQuery.cs" />
<Compile Include="ContentManagement\InfosetHelper.cs" />
<Compile Include="ContentManagement\XmlHelper.cs" />
<Compile Include="ContentManagement\Handlers\TemplateFilterForPart.cs" />
<Compile Include="ContentManagement\Handlers\UpdateContentContext.cs" />
<Compile Include="ContentManagement\IHqlExpression.cs" />
@@ -577,6 +579,7 @@
<Compile Include="Messaging\Services\IMessagingChannel.cs" />
<Compile Include="IWorkContextAccessor.cs" />
<Compile Include="Utility\Extensions\VirtualPathProviderExtensions.cs" />
<Compile Include="Utility\ReflectionHelper.cs" />
<Compile Include="Validation\PathValidation.cs" />
<Compile Include="Wcf\OrchardDependencyInjectionServiceBehavior.cs" />
<Compile Include="Wcf\OrchardInstanceContext.cs" />

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
namespace Orchard.Utility {
public class ReflectionHelper<T> {
private static readonly ConcurrentDictionary<string, Delegate> _getterCache =
new ConcurrentDictionary<string, Delegate>();
public delegate TProperty PropertyGetterDelegate<out TProperty>(T target);
/// <summary>
/// Gets property info out of a Lambda.
/// </summary>
/// <typeparam name="TProperty">The return type of the Lambda.</typeparam>
/// <param name="expression">The Lambda expression.</param>
/// <returns>The property info.</returns>
public static PropertyInfo GetPropertyInfo<TProperty>(Expression<Func<T, TProperty>> expression) {
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null) {
throw new InvalidOperationException("Expression is not a member expression.");
}
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null) {
throw new InvalidOperationException("Expression is not for a property.");
}
return propertyInfo;
}
/// <summary>
/// Gets a delegate from a property expression.
/// </summary>
/// <typeparam name="TProperty">The type of the property.</typeparam>
/// <param name="targetExpression">The property expression.</param>
/// <returns>The delegate.</returns>
public static PropertyGetterDelegate<TProperty> GetGetter<TProperty>(
Expression<Func<T, TProperty>> targetExpression) {
var propertyInfo = GetPropertyInfo(targetExpression);
return (PropertyGetterDelegate<TProperty>)_getterCache
.GetOrAdd(propertyInfo.Name,
s => Delegate.CreateDelegate(typeof(PropertyGetterDelegate<TProperty>), propertyInfo.GetGetMethod()));
}
}
}