Professional Documents
Culture Documents
IDeliverable - LazyField< T>
IDeliverable - LazyField< T>
LazyField<;T>;
LazyField<T>
orchard (/Tags/orchard)
class LazyField<T> {
T Value { get; set; }
void Loader(Func<T, T> loader);
void Setter(Func<T, T> setter);
}
If LazyField is used without configuring a loader and / or setter delegate, it will simply act as a
backing field.
When to use it
Sometimes, when developing content parts, you may come across the need to load related data,
for example one or more content items.
Or perhaps you want to expose a service from your content part, or implement a computed
property that requires some service class.
Because you cannot inject dependencies into content parts using the constructor, you will have
to do so manually.
For example, you could write a content handler and handle the Activated event to manually set
some properties on the activated content item.
Although that would work, this means that on each request and when each content item is
activated, the related data is loaded. This may impact the performance negatively.
So instead, you will want to load the related data in a lazy manner.
http://www.ideliverable.com/blog/lazyfieldt 1/9
4/10/2015 IDeliverable LazyField<;T>;
1. Create a public or internal member on your class (for example your own content part) of
type LazyField<T>, where T is the type of the object to be loaded in a lazy manner.
2. Configure the lazy field member by providing a getter and optionally a setter delegate.
public class CustomerPart : ContentPart<CustomerPartRecord> {
}
public class CustomerPartRecord : ContentPartRecord {
public virtual int InvoiceAddressId { get; set; }
}
public class AddressPart : ContentPart { }
Note that I didn't create the InvoiceAddressId property on the CustomerPart. Although I could
have done so, what I want to do instead is create a property called InvoiceAddress of type
Address.
This enables use to access the related Address content item without having to use the
ContentManager ourselves everytime we need to load it. Also, the LazyField<T> instance will
hold a reference to the loaded object, so we don't have to worry about loading the Address
multipel times during the same request.
Let's start by implementing the lazy field as the backing store and a property that leverages the
field:
http://www.ideliverable.com/blog/lazyfieldt 2/9
4/10/2015 IDeliverable LazyField<;T>;
public class CustomerPart : ContentPart<CustomerPartRecord> {
// Define the lazy field that will act as the backing store for the Address content item
.
// Note that we defined it as a internal because we need to access this field from the o
utside
// in order to configure the setter and getter.
internal readonly LazyField<AddressPart> InvoiceAddressField = new LazyField<AddressPart
>();
// Define a property that provides access to the lazy field value
public AddressPart InvoiceAdddress {
get { return InvoiceAddressField.Value; }
set { InvoiceAddress.Value = value; }
}
Now that we have the lazy field in place, the next thing we need to do is configure it as soon as
our CustomerPart is loaded / activated.
We'll do this from a content handler:
public class CustomerPartHandler : ContentPartHandler {
private IContentManager _contentManager;
public CustomerHandler( IContentManager contentManager ){
_contentManager = contentManager;
OnActivated<CustomerPart>(SetupCustomerPart);
}
private void SetupCustomerPart(ActivatedContentContext context, CustomerPart part){
// Setup the getter of the lazy field
part.InvoiceAddressField.Loader( addressPart => _contentManager.Get<AddressPart>(p
art.Record.InvoiceAddressId));
// Setup the setter of the lazy field
part.InvoiceAddressField.Setter( addressPart => {
part.Record.InvoiceAddressId = addressPart != null ? addressPart.Id : 0;
return addressPart;
});
}
}
http://www.ideliverable.com/blog/lazyfieldt 3/9
4/10/2015 IDeliverable LazyField<;T>;
Essentially, we are passing in a delegate to the loader that in turn uses the injected
ContentManager to load the Address item when the LazyField is first accessed.
The setter delegate simply gets the ID of the specified Address item and stores it in the record's
InvoiceAddressId property.
Alternative approach
In the previous example, we showed how to use LazyField<T> to load related content using the
ContentManager. The primary reasons to use the LazyField were:
1. To load the related content using a service class (ContentManager) in a lazy manner
2. To load the related content only once, on first access.
However, because all content parts have access to the ContentItem of which they're part of, we
actually do have access to the ContentManager from within our part.
So alternatively, we could have implemented the InvoiceAddress property as follows:
public class CustomerPart : ContentPart<CustomerPartRecord> {
private AddressPart _invoiceAddress;
public AddressPart InvoiceAdddress {
get { return _invoiceAddress ?? (_invoiceAddress = ContentItem.ContentManager.Get<Add
ressPart>(Record.InvoiceAddressId)); }
set {
_invoiceAddress = value;
Record.InvoiceAddressId = value != null ? value.Id : 0;
}
}
This code will work as well and doesn't require configuring a LazyField from the content handler.
However, I think this is less elegant than the LazyField approach, since we now have data access
logic inside of the content part.
Source code
Download source code: https://lazyfielddemo.codeplex.com/releases/view/95579
(https://lazyfielddemo.codeplex.com/releases/view/95579)
Related Articles
http://www.ideliverable.com/blog/lazyfieldt 4/9
4/10/2015 IDeliverable LazyField<;T>;
5 comments
SciencApp 10/01/2012 09:19 AM
The post has been updated with a link to a sample module. If you install this
module you should see a working demo where you will be able to create
customers and addresses: https://lazyfielddemo.codeplex...
(https://lazyfielddemo.codeplex.com/releases/view/95579)
http://www.ideliverable.com/blog/lazyfieldt 5/9
4/10/2015 IDeliverable LazyField<;T>;
Just a heads up on this that caught me out. When you resolve the namespace
for LazyField in your containing part, make sure it resolves to
Orchard.ContentManagement.Utilities.LazyField and not
Orchard.Core.Common.Utilities.LazyField. This is a very similar class except
for a different in the number of params in the Loader() func. I wonder why
they both exist?
This was my problem too, maybe the author (who has done a wonderful job)
could put something in the main article about this, I was struggling until I
finally looked in comments.
Leave a comment
Name:
Email address:
URL:
Comment:
How to Format
http://www.ideliverable.com/blog/lazyfieldt 6/9
4/10/2015 IDeliverable LazyField<;T>;
Type the text
Privacy & Terms
(http://www.google.com/intl/en/policies/)
Submit
Topics
autofac (1) (/Tags/autofac) azure (2) (/Tags/azure) cloud services (2) (/Tags/cloud%20services)
powershell (2) (/Tags/powershell) ssl (1) (/Tags/ssl) startup tasks (2) (/Tags/startup%20tasks)
Authors
http://www.ideliverable.com/blog/lazyfieldt 7/9
4/10/2015 IDeliverable LazyField<;T>;
(/blog/author/daniel)
(/blog/author/sipke)
Archive
2014 2013 2012
November (6) December (2) October (1)
(/blog/archive/2014/11) (/blog/archive/2013/12) (/blog/archive/2012/10)
September (3) June (5) September (3)
(/blog/archive/2014/9) (/blog/archive/2013/6) (/blog/archive/2012/9)
March (9) August (1)
(/blog/archive/2013/3) (/blog/archive/2012/8)
January (1) April (7)
(/blog/archive/2013/1) (/blog/archive/2012/4)
February (4)
(/blog/archive/2012/2)
January (18)
(/blog/archive/2012/1)
http://www.ideliverable.com/blog/lazyfieldt 8/9
4/10/2015 IDeliverable LazyField<;T>;
Postal address:
IDeliverable, Ltd.
PO Box 58341
3733 Limassol
CYPRUS
Visiting address:
IDeliverable, Ltd.
Sotiri Tofini 4, 2nd floor
Agios Athanasios
4102 Limassol
CYPRUS
http://www.ideliverable.com/blog/lazyfieldt 9/9