Does .NET Standard normalize HResult values across every platform it supports?
Asked Answered
O

1

8

I am creating a simple function that creates a random file. To be thread safe, it creates the file in a retry loop and if the file exists it tries again.

while (true)
{
    fileName = NewTempFileName(prefix, suffix, directory);

    if (File.Exists(fileName))
    {
        continue;
    }

    try
    {
        // Create the file, and close it immediately
        using (var stream = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read))
        {
            break;
        }
    }
    catch (IOException e)
    {
        // If the error was because the file exists, try again
        if ((e.HResult & 0xFFFF) == 0x00000050)
        {
            continue;
        }

        // else rethrow it
        throw;
    }
}

According to MSDN, the HResult value is derived from COM which would seem to indicate it will only work on Windows, and it specifically lists them as "Win32 codes". But this is in a library which targets .NET Standard and ideally it should work on every platform .NET Standard supports.

What I am wondering is whether I can rely on the above approach that uses the value from HResult to be cross-platform? The documentation is not clear on this point.

If not, how do I determine what HResult values to expect on other platforms?

NOTE: There is a similar question Does .NET define common HRESULT values?, but it was asked before .NET Standard (and cross-platform support for .NET) existed, so I cannot rely on that answer for this purpose.

For now, our codebase only uses:

  1. 0x00000020 - ERROR_SHARING_VIOLATION
  2. 0x00000021 - ERROR_LOCK_VIOLATION
  3. 0x00000050 - ERROR_FILE_EXISTS

We are targeting .NET Standard 1.5.

NOTE: While the accepted answer does satisfy what I asked here, I have a follow-up question How do I make catching generic IOExceptions reliably portable across platforms?

Ormuz answered 23/9, 2017 at 14:10 Comment(6)
I guess you have to be more specific about the scenario or specific error codes you want to rely on.. There are many places were lists of predefined codes are used (you can search for hresults.cs in both CoreCLR and fullfx reference source code) and for some cases there are normalisation functions like this one for file errors.Indeterminable
Thanks Martin. I added the 3 errors I am currently interested in. Was kinda hoping for a more general answer, though. Generally, we are only interested in file IO errors though.Ormuz
You might want to link to this documentation instead of the msdn one as it is the official .net standard 1.5 API docs. (Fairly sure it is a copy and paste of the MSDN, but it is good to point at the right spot)Ezequieleziechiele
I updated the link. I have also asked a follow up question stackoverflow.com/questions/46382637Ormuz
@MartinUllrich - Could you please answer specifically whether the ERROR_SHARING_VIOLATION and ERROR_LOCK_VIOLATION are cross platform? I tried analyzing the code you linked, but I can't seem to find the actual location where those constants are defined. We have a less-efficient fallback implementation, but I would prefer not to use it or at least limit it to less popular platforms.Ormuz
@Ormuz I believe Jan Kotas who answered is more qualified to correctly answer this. I'd only go through the same code like you did now.Indeterminable
H
7

Exception.HResult values are not standardized across platforms.

For I/O errors, .NET Core will return platform specific error code as HResult. The value of HResult property for file already exist in your example is going be 17 on Linux, and it may be different value for other Unix systems.

The relevant code that maps IO errors to exceptions on Unix is here: https://github.com/dotnet/corefx/blob/master/src/Common/src/Interop/Unix/Interop.IOErrors.cs

Hoopen answered 23/9, 2017 at 16:22 Comment(2)
Thanks. Unfortunately, the link you provided shows only the code, but not the resources file that provides the values. There doesn't seem to be a corresponding file for other platforms in that directory. Am I to take away from this that the above approach cannot be made reliable? Or is there some way to obtain all of the values I need for all of the platforms? Do note I only need the 3 errors in my question for each platform .NET Standard 1.5 supports.Ormuz
This approach cannot be made reliably portable. HResult in this case is what the underlying operating system returns. It can differ between Linux, macOS, FreeBSD, ... . I will edit the post to make it clear.Hoopen

© 2022 - 2024 — McMap. All rights reserved.