Standard.Licensing
Standard.Licensing copied to clipboard
Proposed change to decouple License from XML
Currently the License class is tied to XML as everything is being performed internally on an XML string.
This proposal is to abstract away this dependency either through making License an abstract base class and then creating an XmlLicense class, or to create an interface ILicense, which contains the same properties/methods necessary. This would leave License intact without breaking any existing code, but allow then the ability to create other license storage mechanisms such as JSON, or ProtoBuf, etc.
Actually with some further thought on this, it seems like a nice way to refactor this would be to make the License class just a simple DTO (i.e. a Record), and then how it is saved/loaded/streamed would be agnostic of the underlying storage technology:
public record License
{
public Guid Id {get; init;} = Guid.NewGuid();
public LicenseType Type {get; init;} = LicenseType.Standard;
public int Quantity {get; init;} = 0;
public IReadOnlyDictionary<string, string> ProductFeatures {get; init;} = new Dictionary<string, string>();
// removed for brevity
// This would be a change, but as a DTO, this can just be an array, or an ImmutableArray if that is more desired
public byte[] Signature {get; init;} = [];
}
We can of course add some helper methods like "Sign" and "Verify" to the DTO, but the saving and loading should be responsibilities outside of this class. Honestly, even the Sign and Verify would probably be better placed in a Utilities class of some kind. Then instead of having the License itself manage how it is represented (i.e. XML, JSON, etc), a collection of utility methods could be added to handle the serialization.
What is the advantage of this change? Nothing besides License needs to read/write the XML, so it should not matter what format it is. License can save the license to a string and already provides a few ways to load it back (e.g., string, Stream, etc.). That string can be stored or transmitted any way you like. Am I missing something?
@skst - for me, the advantage is mainly related to performance. The current implementation manages an XML DOM for all license operations. Any property getter called first parses the XML. Even things that have enumerations, first look up the XML property, then convert the string to an enum, which is a lot of work for a simple property lookup.
Secondly, related to loading and saving, while it is true you can save/load to/from a Stream, the underlying data is still being streamed as XML. Sure, we can then pass that through a compression algorithm to shrink it, but that is an extra step. By moving to a standard DTO that is representation agnostic, now we can stream the data directly to something like a proto-buf, or JSON, or whatever.
To me it seems that decoupling would allow more flexibility and performance for the library.
I see your point now. I still wonder if the license library is where one would see meaningful performance gains in an application. How many times does an application access the license that improving the access time to its underlying representation would have a significant impact? Just my 2¢. 🙂
Hi @skst, the performance side matters when you are generating licenses on customer requests on a license server, so both minimizing the memory footprint along with processing time can make a difference. That also leads to the secondary issue of the ultimate format that it is streamed into, as there is a big difference between a binary serialization such as protobuf vs. a binary stream generated from an XML string.
So my thoughts are just in allowing a decoupling of the license object from a seralization format.
Secondarily back on the performance side, in my desktop app there are repeated calls into the license object to query information out of it. As a security measure, we periodically (at a random interval) reload the license object and revalidate it. It prevents someone using a debugger, finding the spot at app startup where the license is loaded and bridging around it. It doesn't remove the possibility completely, but by having multiple points in the code checking the license it adds some complexity.
I can see how it could make a difference in those situations. It would definitely be interesting to benchmark how much of the overall processing time is consumed by the XML generation and processing.