Repository navigation
Architecture : using compositions and resolvers? #1
Description
Activity
First question: nope,
TypeLoad.GetTypesdoes not support getting an open generic interface such asISyncSerializer<>- we could probably enhance it to support that case, though, but I'd rather first discuss the use case.You want to get a collection of serializers. Let's forget about DI, v8, etc for a while. You're going to handle that collection as an enumerable of something, right? C# will not let you have an
IEnumerable<ISyncSerializer<>>becauseISyncSerializer<>is not a concrete type. So, what should it be? It has to be something that all serializers would share, and it has to be a concrete C# type.You could do:
public interface ISyncSerializer { } public interface ISyncSerializer<T> : ISyncSerializer { ... }So then, all your serializers could fit in an
IEnumerable<ISyncSerializer>. And then I assume you'll want... to pick the right serializer for the object you're serializing (for instance, pick a/theISyncSerializer<IContent>to serialize anIContentobject?Again, I don't think this has to do with DI or v8 and more with C# code and handling generics.
What would your serialization loop look like?
Thanks for the reply 👍
I think you are right - I might have been thinking about it the wrong way round.
The serializers are in the most part called by 'handlers' that are the things listening for the internal umbraco events on items (save, delete etc). So they (the handlers) just need to be able to call the serializer for the type they are listening to.
So super simple that looks a bit like :
Save(IContentType item) { var xml = serializer.Serialize(item); xml.Save(path); }In that sense a handler only need be initialized with the serializer it cares about ?
So that might be ..
public class ContentTypeHandler : ISyncHandler { private ISyncSerializer<IContentType> serializer; public ContentTypeHandler(ContentTypeSerializer serializer) { this.serializer = serializer; } }Going this way do I just register each serializer in the composition, or can i still load them as a collection?
But: (and i think this is where i got caught up in my head) I do want a bit of flexibility, because we might want to swap a serializer out (so have a different ContentTypeSerializer loaded at runtime). - So Ideally don't want to construct the Handlers with Specific Serializers hardwired.
(I might just be trying to build to much flexibility in here, and if the need arises later on, i could refactor the code for this)Handlers
I think the Handlers are simpler
they are a collection - (& they can have a concrete type), so can be loaded into a collection quite easily.Then for example they are initialized to listen to all the events in a Component :
public void Initialize() { foreach(var syncHandler in syncHandlers) { syncHandler.InitializeEvents(); } }There are other things like when a user asks for a full export - but it's the same loop, so i think i understand that bit.
You can define
public interface ISerializer {} public interface ISerializer<T> : ISerializer { XmlElement Serialize(T item); }Then, you can implement a serializer for content types
public class ContentTypeSerializer : ISerializer<IContentType> { XElement Serialize(IContentType item) { ... } }and/but inject the interface
public class ContentTypeHandler : ISyncHandler { private ISyncSerializer<IContentType> _serializer; public ContentTypeHandler(ISerializer<IContentType> serializer) { _serializer = serializer; } }Now you would register:
composition.Register<ISerializer<IContentType>, ContentTypeSerializer>();So we're injecting the interface, your handler does not know about
ContentTypeSerializer, and you can register a different implementation if needed. Making sense?Hi,
Yet again you are right 😄 - I was getting tied up in dependency stuff and forgot about the interfaceness of it all.
Aha happy to help, ping me if you have more questions. We're supposed to make things simpler, not horribly complex ;-)
thanks, for the record i think you are- I am loving the Composition / Component stuff it makes loads of sense.
at its heart uSync has a collection of Serializers, that are responsible for getting bits of Umbraco in and out of XML. In the current version these are loaded by a singleton at start up and then accessed when needed.
Looking at Umbraco 8 and the best way to do this I think using Compositions and A Collectionbuilder is the way to go - so then we can build a collection like so:
Then in theory when we need to we can go off and get the serializer we require - and this is where it gets funky.
each serializer will serialize a type of umbraco object (e.g IContentType) and so the return type of the functions in the Interface will change based on the type.
Ideally we want to do this with generics - so each serializer would impliment the Serializer class based on their type.
So for example...
Except ...
there are few issues i haven't resolved yet ...
composition.TypeLoader.GetTypesto load a generic interface ??LazyCollectionBuilderBaseI am not sure we can load a generic type their either.TypeLoader.GetAttributedTypesbut insider our collectionBuilder ? what do we say the type is because that needs a non-generic type?At the moment - this is all that is in this repo - see : https://github.com/KevinJump/uSync8/tree/master/uSync8.Core/Serialization for details so far