November Happy Hour will be moved to Thursday December 5th.

Anders Hattestad
Feb 1, 2011
  8508
(13 votes)

Know your enemy; Sun Tzu's The Art of War

If you wan to be able to archive your goals in a EPiServer project you need to know the product. And EPiServer have (thanks heaven) open dll’s so we can use reflector to browse thru the inner workings of the product. Sometime I guess they regret that decision, but I honestly think that's one of the things that make EPiServer as a product great.

Then back to topic, who can we know our enemy

A twitter user posted a tweet some days ago where he said: “Ohhh, I SOOO want an event to trigger when dynamic properties change. Please! #EPiServer

But instead of begging he should have tried to know his enemy, an start the all mighty reflector :)

AFAIK there are only one place dynamic properties are saved and that's in the EditDynProp.aspx. And that page have one button, called ApplyButton….

image

Here we see that there is a method SaveCollection that is called

image

And that calls a method Save

image

Which calls PopulatePropertyCommand

image

image

And here we see that OnBeforeSavingProperty is called

image

And here it is. BeforeSavingProperty, that's an event that get called when a dynamic property is saved. Either if it’s empty or have values. This event is only called when you save a dynamic property.

Code Snippet
  1. public class AttachEvents : PlugInAttribute
  2. {
  3.     public static void Start()
  4.     {
  5.         PageDB.BeforeSavingProperty += new EventHandler<PropertyEventArgs>(PageDB_BeforeSavingProperty);
  6.     }
  7.  
  8.     static void PageDB_BeforeSavingProperty(object sender, PropertyEventArgs e)
  9.     {
  10.         int a = 0;
  11.     }

This opens up some nice things that can be done. For instance create a version list on dynamic property page. Which is one of the feature I miss most.

It this event was not there we could also used PageAdaptors to hook our self up to the ApplyButton click event and done it there.

This feature have been around since CMS 5 it seems. So happy coding and use your Reflector when you can :)

Feb 01, 2011

Comments

Feb 1, 2011 09:16 AM

Nice work Anders!

Feb 1, 2011 09:29 AM

There is a chance that the user (!) stopped looking when he saw the DynamicPropertiesDB class, which indicate a class in the EPiServer.DataAccess namespace. This namespace has traditionally been a "keep your dirty fingers away" kind of namespace.

However, it is now included in the SDK Reference (though documentation is missing.) This makes me wonder if we're actually allowed to use it now, which would have been nice for this particular feature at least.

Anyone care to pitch in?

Anders Hattestad
Anders Hattestad Feb 1, 2011 09:36 AM

It's probably true that the user in question stopped looking there :) (that lazy man :))
but events are public pr default, and if they exists they are usable.
If the founding fathers didn't want us to use them they could have used (Good forbid) protected internal delegates

Martin Helgesen
Martin Helgesen Feb 1, 2011 09:38 AM

Nice post Mr.Hattestad

smithsson68@gmail.com
smithsson68@gmail.com Feb 1, 2011 10:29 AM

If you look at the desciption for EPiServer.DataAccess namespace on sdk.episerver.com it says:

"The EPiServer.DataAccess namespace contains internal classes that is only intended for internal functions in EPiServer, you should not use these classes because you will break compability with future upgrades. There is though one important enumeration that comes to use when publishing content using EPiServer.DataFactory."

PageDB is not a publically supported API. Use the workaround at your own risk!!

Anders Hattestad
Anders Hattestad Feb 1, 2011 10:54 AM

It is actully marked with public. :)
public class PageDB : DataAccessBase

smithsson68@gmail.com
smithsson68@gmail.com Feb 1, 2011 11:04 AM

There is a BIG difference between a Type being marked public and it being part of the publically supported API of a product. That's where the documentation overrides.

Feb 1, 2011 11:58 AM

Yeah; I agree on that lazy part.

I like to think of APIs like a forest. This is not specific to EPiServer in any way. You're allowed to wonder about, exploring things. But if you wonder too far off the path, you're likely to get lost. Reflector is your GPS, so to speak, so you can explore more than you could without it, but the dark forest can be a dangerous place never the less. Suddenly someone puts up a fence, or cuts down the trees, and then getting back to the path gets more difficult.

Upgrades, new functionality, hotfixes; they will from time to time demand breaking changes, that is the life of software. The effort put into keeping the most used parts of the API backwards compatible will always be greater than on the less used ones.

Solving complicated problems sometimes demand complicated solutions, using undocumented parts of the API, or changing how the system works in ways that is not optimal. But as Joel so eloquently puts it - "If it's this hard, maybe we're doing something wrong":
http://joelabrahamsson.com/entry/if-its-this-hard-maybe-were-doing-something-wrong

In this particular case, when using that event, we discovered that the event argument class had a property called CurrentPage, of the type PageReference. This is the first warning that something is not quite right. In all (I think) other places, CurrentPage is a PageData object. Also, the event seems to be triggered for non-modified properties, so it is a little sharp around the edges.

All in all, we're opting on not using this event, it does not feel quite right, and we want to keep the upgrade path as clean as possible. I did no see that usage description on the namespace, which makes this an even clearer no-no.

Lesson learned: just because you can do it does not mean you should.

Anders Hattestad
Anders Hattestad Feb 1, 2011 12:27 PM

Have no trouble seeing that this stuff can change, but

Steve=>
When I see a solution so easy as to just attach myself to an event I feel that we are doing something right :)

but I have no trouble seeing your point on upgrades and hot fixes.

Paul=>
Why do you mark other classes with internal then? :)

smithsson68@gmail.com
smithsson68@gmail.com Feb 1, 2011 12:52 PM

Anders =>

So we can use them in other projects if we like.

Feb 1, 2011 01:56 PM

In the case of these DataAccess-types, there is a need to reference them across other EPiServer "core"-assemblies, so "internal" wont work leaving not much choice but to mark them as "public". (something like c++'s "friend" would be nice to have sometimes).

When *those* requirements aren't needed, we sure do use "internal" as you probably have noticed ;-)

/johan

Feb 1, 2011 02:26 PM

[InternalsVisibleTo] :)

Frederik Vig
Frederik Vig Feb 1, 2011 02:28 PM

@Johan why not use the assemblyinfo file to mark which assemblies should have access to the internal marked class by using the InternalsVisibleTo attribute (http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx)?

Frederik

Anders Hattestad
Anders Hattestad Feb 1, 2011 02:30 PM

stop Fredrik don't give away methods on how to
Mark stuff internal... :)

Magnus Rahl
Magnus Rahl Feb 1, 2011 03:21 PM

I'm not picking sides here, just IMHO: It is still possible to access internal/private/whatever and to "new" non-virtual members, even though it gets hairy and ugly. So the access modifiers are mainly about expressing the /intended/ use of a class - something which /can/ be expressed by other means (like documentation). Nobody can build a framework which is perfectly extensible everywhere, especially not without introducing breaking changes as the core features are improved. Just because you can you shouldn't, with great (reflector) power comes great responsibility, jada-jada, etc. Or along the lines of Joel's very popular blog post: "If it's this hard, maybe we shouln't do it at all."

Maybe classes should have a [FeatureStability(x)] or [Hackability(x)] attribute conveying the estimated risk of a breaking change in future versions.

Anders Hattestad
Anders Hattestad Feb 1, 2011 03:22 PM

I would like to point out that I started this post about how changeable EPiServer is. And by changeable I think all know that sometimes our changes will not survive an upgrade. That’s the name of the game.

I think that is one of the primary EPiServer strengths!, And I hope that the development team have the same attitude :) [Dont use private/internal]

smithsson68@gmail.com
smithsson68@gmail.com Feb 1, 2011 04:35 PM

We have a lot of legacy code to deal with or technical debt as we call it here.

We now have a policy where we err on the side of openess (i.e. make classes public), extendability (i.e. make methods virtual) and testability (i.e. use interfaces and DI techniques). It will be a long time before this is felt in any great strength and of course mistakes get made. Keep your constructive feedback coming!

Please login to comment.
Latest blogs
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog