MatthewKing / DeviceId

A simple library providing functionality to generate a 'device ID' that can be used to uniquely identify a computer.
MIT License
722 stars 118 forks source link

Why generates different DeviceId's on different applications on same device? #42

Closed hasan-retrace closed 2 years ago

hasan-retrace commented 2 years ago

I'm generating device id as: new DeviceIdBuilder().AddMachineName().AddMacAddress().AddOsVersion().ToString();

I expect it generates same device id on same device even for different apps.

This statement generates DeviceId1 on App1 on Device1, however DeviceId2 on App2 (different app) on Device1 (same device).

I'm not including any app information in this statement, so app shouldn't matter if it's same device.

The things I include are:

MachineName: same MacAddress: same OsVersion: same

hasan-retrace commented 2 years ago

Sorry for being not sure.

I see it's same now, but sometimes it generates different.

At least I'm sure the one generated in windows form is different than the one generated in windows service.

hasan-retrace commented 2 years ago

I'm reopening issue since I met a case.

I realized that target framework matters! Every update of target framework, it will generate different one. That's the issue.

Both apps are WindowsForms, but using different pacakges one is .Net Core 3.1 the other is .Net 5.0

image

MatthewKing commented 2 years ago

Using the following code, I get the exact same Device ID for .NET Core 3.1 / .NET 5 / .NET 6:

// Returns the same value for .NET Core 3.1 / .NET 5 / .NET 6
var deviceId = new DeviceIdBuilder()
    .AddMachineName()
    .AddMacAddress()
    .AddOsVersion()
    .ToString();

HOWEVER, it will return a different value when used on .NET Framework (ie .NET 4 or lower). This is because .AddOSVersion uses Environment.OSVersion, which returns different values for some OS on the old .NET Framework versions when compared to the newer .NET Core and .NET 5/6.

hasan-retrace commented 2 years ago

Actually I have two project in my solution. The project where device id is generated is named Common and its target framework is, as you see in ss, .Net Framework 4.7.2 . Its Output Type is Class Library and I didn't see .Net 5 there so I couldn't upgrade that.

However the issue seems at the startup project. When I keep Common project as 4.7.2, that's withourt changing, and change the startup project's target framework from .Net core 3.1 to .Net 5.0 as you see below, generated device id changes.

.Net Core 3.1 => "T5GC..." .Net 5.0 => "VNQ2..."

image

MatthewKing commented 2 years ago

Yep, that's as expected. What matters is the framework of the project that is invoking the code.

Anyway, the answer to your question is that: The device ID is different because AddOsVersion uses Environment.OSVersion, which is different on the modern frameworks (core, 5, 6, etc.) as opposed to the old framework. Changing this could break backwards compatibility for users of the library, so it's going to stay as-is.

For new projects, it's pretty uncommon to need to target both framework and core/5/6 on the same machine. And on different machines it's fine for the device ID to differ most of the time. If it's really necessary to have this behaviour, you could add a custom component instead (example below) which would (probably) give the same OSVersion regardless of the platform you're targeting. Windows only, of course, and would require testing.

public class WmiOsDeviceIdComponent : IDeviceIdComponent
{
    public string GetValue()
    {
        try
        {
            using var mc = new ManagementClass("Win32_OperatingSystem");

            foreach (var mo in mc.GetInstances().OfType<ManagementObject>())
            {
                if (mo != null)
                {
                    if (mo["Version"] is string v)
                    {
                        return $"Microsoft Windows NT {v}";
                    }
                }
            }
        }
        catch { }

        return Environment.OSVersion.ToString();
    }
}
var deviceId = new DeviceIdBuilder()
    .AddMachineName()
    .AddMacAddress()
    .AddComponent("OSVersion", new WmiOsDeviceIdComponent())
    .ToString();