It is a fact of life that organizations have different applications using different versions of the same classes because they were developed at different points in time and are unable to keep up. It is also a fact of life that these applications often need to share data with each other.
You can do this through the database. However, that is slow and not scalable. What you really want is to share objects through a distributed cache that is fast and scalable. But, object sharing at runtime immediately raises the issue of version compatibility.
One way to do this is through XML in which you can transform one version of an object to another. But it is extremely slow. Another way is to implement your own custom transformation that takes one object version and transforms it to another version. But, you have to maintain this, which is a lot of effort for you.
Wouldn’t it be nice if the distributed cache somehow took care of version compatibility for you? Well, NCache does exactly that. NCache provides you a binary-level object transformation between different versions. You can map different versions through an XML configuration file and NCache understands how to transform from one version to another.
Additionally, since NCache stores all these different versions in a binary format (rather than XML), the data size stays very compact and small and therefore fast. In a high traffic environment, object size adds up to be a lot of extra bandwidth consumption, which has its own cost associated with it.
Here is an example of NCache config.ncconf with class version mapping:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<cache-config name="myInteropCache" inproc="False" config-id="0" last-modified="" type="clustered-cache" auto-start="False"> ... <data-sharing> <type id="1001" handle="Employee" portable="True"> <attribute-list> <attribute name="_Name" type="System.String" order="1"> <attribute name="_Age" type="System.Int32" order="2"> <attribute name="_Address" type="System.String" order="3"> <attribute name="_ID" type="System.String" order="4"> <attribute name="_PostalAddress" type="System.String" order="5"> </attribute></attribute></attribute></attribute></attribute></attribute-list> <class name="DataModel.Employee:1.0.0.0" handle-id="1" assembly="DataModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" type="net"> <attribute name="_Name" type="System.String" order="1"> <attribute name="_Age" type="System.Int32" order="2"> <attribute name="_Address" type="System.String" order="3"> </attribute></attribute></attribute></class> <class name="DataModel.Employee:2.0.0.0" handle-id="2" assembly="DataModel, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" type="net"> <attribute name="_ID" type="System.String" order="4"> <attribute name="_Name" type="System.String" order="1"> <attribute name="_Age" type="System.Int32" order="2"> <attribute name="_PostalAddress" type="System.String" order="3"> </attribute></attribute></attribute></attribute></class> </type> </data-sharing> ... </cache-config> |
How does NCache do it?
In the config.nconf file that you see above, you’ll notice that the Employee class has a set of attributes defined first. These are version independent attributes and appear in all versions. This is actually a superset of all attributes that appear in different versions. Below that, you specify version-specific attributes and map them to version-independent attributes above.
Let’s say that you saved Employee version 1.0.0.0, which had a subset of the Employee version 2.0.0.0. Now, when another application tries to fetch the same Employee, but it wants to see it as version 2.0.0.0, NCache knows which version 2.0.0.0 attributes to fill with data and which ones to leave blank.
Secondly, in above sample config you will notice that Employee version 2.0.0.0 does not have the Address field in it even though version 1.0.0.0 has it. So, in this case, when NCache tries to read Employee 1.0.0.0 stored in the cache and tries to transform it to Employee version 2.0.0.0, it knows not to copy the Address field because it is not there in this newer version.
There are many other scenarios that NCache handles seamlessly for you. Please read the online product documentation for more detail on this.
Finally, the best part in all of this is that you don’t have to write any serialization code or make any code changes to your application in order to use this NCache feature. NCache has implemented a runtime code generation mechanism, which generates in-memory serialization and deserialization code of your classes at runtime, and uses the compiled form which is very fast.
In summary, using NCache you can now share different object versions between your applications without even modifying your application code.