I'm working on an Umbraco package and I need to do something a bit tricky.
My project discovers events that follow the sender, eventArgs pattern (using reflection).
For the sender I want to be able to store information about the object - specifically it's type, plus how to - (re)construct it - It could be any object at all though I am happy to assume that it will always have a single arg constructor that can be called using one of it's own property values.
For example the for the Umbraco Document.AfterPublish event the sender is a Document and can be instantiated using new Document(id);
So in my config i'd need to store something like:
type = umbraco.businesslogic.cms.web.Document
constructor-property = .Id
constructor val = 10
The reason behind this is that I need to persist details of an event triggering object to disc for use at a later point. It must be able to survive app recycles etc. In the example of an Umbraco document properties may change in the time period that it is persisted so it must be constructed when processing happens.
Why don't you just serialize the object? I'm not sure if they are marked as serializable, and if they aren't you can use the JavaScript serializer, or JSON.Net to serialize them.
But I think you'd be much better persisting a DTO to disk, not the event arguments.
Just want to ensure I understand properly. You mention that you're discovering all the events following that pattern via reflection. However you then mention that you want to store information about the sender and how to re-construct it. By my understanding you are referring to specific instances of the sender, since it wouldn't be possible to infer the value of Id via reflection alone against the type without having an instance of it.
If I understand correctly, you want to be able to re-fire events on particular instance objects after the fact, is that right? Possibly in another environment against the same Documents.
The JSON Serializer would serialize anything - in fact i could just use the BinaryFormatter. The bit I am having a problem with is how to store the constrcutor info and the Id property.
Taking an Umbraco document as an example - when the serialized object is retrieved I want the current property values not the values that were serialized.
so when I retrieve from disc I want to re-instantiate using the constructor....
@alex - By my understanding you are referring to specific instances of the sender.
Yes, the sender will always be an instance.
At any given point I'd like to be able to recreate the instance.
It isn't about moving across environments - more that in the time between the event and me wanting to do the processing any number of object properties may have changed (so serialization is out).
The real world scenario is a workflow - A document can't be published without apporval so the original publish event is cancelled. The workflow then remains inactive until a user intervention (which could be weeks or months after the orginal event). The workflow then goes on to do further logic against the document dependent on its current properties.
In the scenario above my workflow would need to know how to do new Document(id) . But it isn't necessarily a document it could be any object. DocumentType, Macro, Stylesheet etc.
I guess it may not be able to be completely generic - so rather than any object I'd have a limited set of "Umbraco" objects that my system knows how to construct....
Trying to reconstruct the Document class from Umbraco would be a bad idea IMO.
I think you're going to hit major hurdles by the fact that the Document object is little more than a custom implementation of IDictionary (although it doesn't implement it), so the majority of the properties you have to deal with are not helpful.
A custom LINQ to Umbraco provider may make your life easier, as then the type your serializing is a proper representation of the properties of the object. My LINQ to Umbraco extensions contains a CRUD enabled one - http://www.aaron-powell.com/linq-to-umbraco-extensions
"so when I retrieve from disc I want to re-instantiate using the constructor...."
I can understand the desire for the approach, but asking the object to re-populate itself with the latest values based on an Id passed into the constructor is reliant upon the fact that the objects in 4.x are intertwined with all kinds of db logic and are able to populate themselves.
Instead, is it possible you could just de-serialize the whole thing, and then pass the hydrated object into an Update(object target) method on a DAL somewhere which knows how to re-populate that object from the database based on the value of the property? Then you can fire the event with the updated data.
The reason I ask is that you won't be able to get via reflection precisely which Property of the object is then a candidate for passing into the constructor of a new instance in order to load the same / updated data. For this scenario I think you might be looking at writing a big switch statement for a pre-determined list of known types. Caveat: you could get the value itself at least, if running in Debug mode and programatically walking up the Call Stack, but I think those constraints aren't feasible for a production env.
Could you use some kind of Dependency Injection container to pass in the args on the constructor automatically for you? You could then gather the type, and request an instance from the DI container and it'll do all the setup for you?
I'm thinking that what i'll probably do is have a mapping of Type -> Construcor property and use Activator.Createinstance.
I'm thinking for the majority of objects in Umbraco there is a constructor that takes an Id so i could just try to use the Id property of the original object if it exists.
For unknown/unmapped object types i'll just use BinaryFormatter to serialize the whole thing to disc.
c# help - reflection
Hi All,
I'm working on an Umbraco package and I need to do something a bit tricky.
My project discovers events that follow the sender, eventArgs pattern (using reflection).
For the sender I want to be able to store information about the object - specifically it's type, plus how to - (re)construct it - It could be any object at all though I am happy to assume that it will always have a single arg constructor that can be called using one of it's own property values.
For example the for the Umbraco Document.AfterPublish event the sender is a Document and can be instantiated using new Document(id);
So in my config i'd need to store something like:
type = umbraco.businesslogic.cms.web.Document
constructor-property = .Id
constructor val = 10
The reason behind this is that I need to persist details of an event triggering object to disc for use at a later point. It must be able to survive app recycles etc. In the example of an Umbraco document properties may change in the time period that it is persisted so it must be constructed when processing happens.
Anyone?
Why don't you just serialize the object? I'm not sure if they are marked as serializable, and if they aren't you can use the JavaScript serializer, or JSON.Net to serialize them.
But I think you'd be much better persisting a DTO to disk, not the event arguments.
Hey Darren!
Just want to ensure I understand properly. You mention that you're discovering all the events following that pattern via reflection. However you then mention that you want to store information about the sender and how to re-construct it. By my understanding you are referring to specific instances of the sender, since it wouldn't be possible to infer the value of Id via reflection alone against the type without having an instance of it.
If I understand correctly, you want to be able to re-fire events on particular instance objects after the fact, is that right? Possibly in another environment against the same Documents.
Cheers
Alex
The JSON Serializer would serialize anything - in fact i could just use the BinaryFormatter. The bit I am having a problem with is how to store the constrcutor info and the Id property.
Taking an Umbraco document as an example - when the serialized object is retrieved I want the current property values not the values that were serialized.
so when I retrieve from disc I want to re-instantiate using the constructor....
@alex - By my understanding you are referring to specific instances of the sender.
Yes, the sender will always be an instance.
At any given point I'd like to be able to recreate the instance.
It isn't about moving across environments - more that in the time between the event and me wanting to do the processing any number of object properties may have changed (so serialization is out).
The real world scenario is a workflow - A document can't be published without apporval so the original publish event is cancelled. The workflow then remains inactive until a user intervention (which could be weeks or months after the orginal event). The workflow then goes on to do further logic against the document dependent on its current properties.
In the scenario above my workflow would need to know how to do new Document(id) . But it isn't necessarily a document it could be any object. DocumentType, Macro, Stylesheet etc.
I guess it may not be able to be completely generic - so rather than any object I'd have a limited set of "Umbraco" objects that my system knows how to construct....
Trying to reconstruct the Document class from Umbraco would be a bad idea IMO.
I think you're going to hit major hurdles by the fact that the Document object is little more than a custom implementation of IDictionary (although it doesn't implement it), so the majority of the properties you have to deal with are not helpful.
A custom LINQ to Umbraco provider may make your life easier, as then the type your serializing is a proper representation of the properties of the object. My LINQ to Umbraco extensions contains a CRUD enabled one - http://www.aaron-powell.com/linq-to-umbraco-extensions
I can understand the desire for the approach, but asking the object to re-populate itself with the latest values based on an Id passed into the constructor is reliant upon the fact that the objects in 4.x are intertwined with all kinds of db logic and are able to populate themselves.
Instead, is it possible you could just de-serialize the whole thing, and then pass the hydrated object into an Update(object target) method on a DAL somewhere which knows how to re-populate that object from the database based on the value of the property? Then you can fire the event with the updated data.
The reason I ask is that you won't be able to get via reflection precisely which Property of the object is then a candidate for passing into the constructor of a new instance in order to load the same / updated data. For this scenario I think you might be looking at writing a big switch statement for a pre-determined list of known types. Caveat: you could get the value itself at least, if running in Debug mode and programatically walking up the Call Stack, but I think those constraints aren't feasible for a production env.
Hey Darren
Could you use some kind of Dependency Injection container to pass in the args on the constructor automatically for you? You could then gather the type, and request an instance from the DI container and it'll do all the setup for you?
Matt
Thanks guys - all helpful.
I'm thinking that what i'll probably do is have a mapping of Type -> Construcor property and use Activator.Createinstance.
I'm thinking for the majority of objects in Umbraco there is a constructor that takes an Id so i could just try to use the Id property of the original object if it exists.
For unknown/unmapped object types i'll just use BinaryFormatter to serialize the whole thing to disc.
is working on a reply...