Model version for detecting fast serialization incompatibility

Posts   
 
    
yowl
User
Posts: 271
Joined: 11-Feb-2008
# Posted on: 09-Dec-2021 19:20:10   

Hi,

If you have a client/server set up using fast serialization, then you break compatibility by adding a field. If you don't get all the clients updated then you get a situation where the fast serializer on the client unpacks what it can but in offset fields resulting in runtime errors, for example in the field getters you can get

System.InvalidCastException: 'Unable to cast object of type 'System.String' to type 'System.Int32'.'

This is fine and expected behaviour, but would you consider adding a GUID or some other version indicator to the generated classes so that it would be possible to compare server and client side model versions?

E.g. At app startup you could call some method on the server, "what model version, or date generated, are you". If the client is different it could choose to exit or fall back to Xml serialization.

Thanks for reading.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39760
Joined: 17-Aug-2003
# Posted on: 10-Dec-2021 09:41:13   

I understand your requirement, but isn't that easy to add today with a custom class that simply pulls the Assembly fileversion ?

Frans Bouma | Lead developer LLBLGen Pro
yowl
User
Posts: 271
Joined: 11-Feb-2008
# Posted on: 10-Dec-2021 18:54:31   

That's ok, an MD5 hash of the source https://docs.microsoft.com/en-us/visualstudio/msbuild/getfilehash-task?view=vs-2022 is probably closer (as just a new build doesn't imply broken compatibility).

Better outside of LLBLGen then I think.

Thanks,

yowl
User
Posts: 271
Joined: 11-Feb-2008
# Posted on: 10-Dec-2021 20:14:42   

In case any one comes here. this is what I added to the generic project csproj. I just put the hash in the AssemblyTitle, probably there is somewhere better but Googling gets boring after a while.


    <UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup>
            <InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
            <DirHash ParameterType="System.String" Output="true" />
        </ParameterGroup>
        <Task>
            <Using Namespace="System.IO" />
            <Using Namespace="System.Linq" />
            <Using Namespace="System.Security.Cryptography" />
            <Code Type="Fragment" Language="cs">
                <![CDATA[
                using (var ms = new MemoryStream())
                using (var md5 = MD5.Create())
                {                
                    foreach (var item in InputFiles)
                    {
                        string path = item.ItemSpec;
                        using (FileStream stream = new FileStream(path, FileMode.Open))
                        {
                            var fileHash = md5.ComputeHash(stream);
                            ms.Write(fileHash, 0, fileHash.Length);
                        }
                    }
                    ms.Flush();
                    ms.Position = 0;
                    var dirHash = md5.ComputeHash(ms);
                    DirHash = string.Join("", dirHash.Select(b => b.ToString("x2")));
                }
            ]]>
            </Code>
        </Task>
    </UsingTask>

    <ItemGroup>
        <FilesToHash Include="$(MSBuildThisFileDirectory)\*" />
    </ItemGroup>

    <Target Name="CreateHash" BeforeTargets="BeforeBuild">
        <GenerateHash InputFiles="@(FilesToHash)" >
            <Output TaskParameter="DirHash" PropertyName="AssemblyTitle" />
        </GenerateHash>
        <Message Text="$(AssemblyTitle)"/>
    </Target>