6

To fix a bug in my application, I had to set the SecurityProtocolType of the ServicePointManager class found in the System.Net assembly like this:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

In .Net 4.5+ the SecurityProtocolType enum has four members:

public enum SecurityProtocolType
{
    Ssl3 48,    
    Tls 192,    
    Tls11 768,  
    Tls12 3072
}

However, in .Net 4.0 the SecurityProtocolType enum has only two members:

public enum SecurityProtocolType
{
    Ssl3 48,    
    Tls 192
}

Since, another project in my code also needed the same fix but that project was on .Net 4.0 which does not have Tls12 as a member for the enum, this answer suggested the following workaround (provided I have the .Net 4.5 installed on the same box):

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

May be I am missing smoething obvious, but my question is, how does (SecurityProtocolType)3072 get resolved to Tls12 when 3072 is not a valid value for the enum in .Net 4.0. I want to understand what magic is going on behind the scenes that makes this work.

Punit Vora
  • 5,052
  • 4
  • 35
  • 44
  • Enums are simply stored as an integer. I can't remember where I saw this, but an enum class is essentially just a static class with a bunch of public const int members for each enum value. That's why when you write a switch block, even if you cover every option in the enum you still need a default case. `ServicePointManager` probably just passes the enum value as an int on to an underlying system call, which recognizes the value `3072` even though it isn't defined in the enum – Andrew Williamson Oct 24 '18 at 19:51
  • 1
    https://stackoverflow.com/questions/6488884/what-happens-under-the-hood-when-you-cast-an-enum-to-an-int-in-c This might help a bit, under the hood it's just stored as an int and so the call is essentially a no-op – Reese De Wind Oct 24 '18 at 19:52
  • @ReeseDeWind Can you please elaborate about 'essentialy a no-op'? Am not familiar with Win32 programming if no-op is a reference to that – Punit Vora Oct 24 '18 at 20:42
  • No-op is just an instruction that does nothing. In your case, the compiler is basically emitting something like `int SecurityProtocol = (int)3072;` – Adam G Oct 24 '18 at 22:18
  • @AdamG Thanks, I get that now. That still does not explain though how .Net 4.0 is able to understand what to do with 3072 and how does it assign special meaning to it. – Punit Vora Oct 25 '18 at 20:21
  • If you dig down enough, you will find that the TLS stuff isn't actually written in .NET, most likely c or c++ calls wrapped in convenient .NET wrapper classes. Those APIs would take defined structs made up of primitive types. In other words, behind the scenes the API only cares about the int behind the enum. – Adam G Oct 25 '18 at 21:45

1 Answers1

9

From the documentation on enums in C# (MSDN)

A variable of type Day can be assigned any value in the range of the underlying type; the values are not limited to the named constants.

So the code certainly has no issue compiling. In addition:

Just as with any constant, all references to the individual values of an enum are converted to numeric literals at compile time. This can create potential versioning issues as described in Constants.

Assigning additional values to new versions of enums, or changing the values of the enum members in a new version, can cause problems for dependent source code.

You are actually taking advantage of this. Running on .NET 4.0 the framework doesn't know what to do with the 3072 value, but the .NET 4.5 framework does. You just don't have a convenient shortcut (the enum) to get to that value.

Community
  • 1
  • 1
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • Thanks. I get the first part that an int enum can be assigned any valid int value. But I still do not understand the interplay between 4.0 and 4.5. How does .Net 4.0 'understand' that 3072 means TLS 1.2 and starts using the setting for Http calls. May be it is the fact that the support for Tls 1.2 was present but not exposed via the API? So, 3072 may be an assignable value since the enum base type was int, but how does the framework 4.0 know what to do with the value? Hope this makes sense – Punit Vora Oct 24 '18 at 20:05
  • 1
    @PunitVora The comment on your question is likely correct, that the value is just passed onto a Win32 call straight, and as long as that call can recognize it its fine. Alternatively, I believe 4.5 will run 4.0 apps and it may just be using that version of the framework – BradleyDotNET Oct 24 '18 at 20:08
  • This is incorrect. This workaround only works if you install .Net 4.5. Without .Net4.5 installed this workaround does not work, so the framework is not simply passing the value to Win32, – bikeman868 Jan 24 '19 at 19:08