Creating .NET Framework 4.7 Apps with Visual Studio 2017

.NET Framework

Not everyone has been as fortunate as I to work with the .NET Framework from its beginning. So, here’s just a quick recap and introduction to the .NET Framework.

The .NET Framework is a computing platform that aids in application development. The purpose of the .NET Framework is to provide a code-execution environment:

  • That minimizes software deployment and versioning conflicts.
  • That guarantees safe execution of your code, as well as code created by a third party.
  • That eliminates the performance problems of scripted environments.

The .NET Framework consists mainly of these two components:

  • The Common Language Runtime (CLR)
  • The .NET Framework class library

CLR (Common Language Runtime)

The Common Language Runtime (CLR) manages the execution of .NET programs. With the Common Language Runtime, it is easy to design components and applications whose objects interact across different languages. Objects written in different languages can communicate with each other, and their behaviors can be tightly integrated.

.NET Framework Class Library (FCL)

The FCL (.NET Framework Class Library) is a library of classes and other types that developers use to make their lives easier. The .NET Framework class library is a collection of reusable types that tightly integrate with the common language runtime (CLR).

I have spoken about the .NET Framework before on several occasions. These articles list some .NET Framework related topics I have covered:

.NET Framework 4.7

In April 2017, Microsoft announced that .NET Framework 4.7 would be integrated into Windows 10 Creators Update. A standalone installer for other Windows versions was also released soon after, as well as an update for Visual Studio 2017 that added support for targeting .NET Framework 4.7.

New features in .NET Framework 4.7 include:

  • Improved serialization by the DataContractJsonSerializer
  • Improved Transport Layer Security (TLS) support
  • Enhanced cryptography with elliptic curve cryptography
  • Support for High-DPI awareness support in Windows Forms

DataContractJsonSerializer

The DataContractJsonSerializer class serializes objects to the JavaScript Object Notation (JSON) and deserializes JSON data to objects. Here is small example for Visual Studio 2017:

Serialize

To define the data contract for a Student

Define the data contract for Student by adding the DataContractAttribute to the class and adding the DataMemberAttribute attribute to the members that you want serialized. Create a class and enter the following:

C#

[DataContract]
   internal class Student
   {
      [DataMember]
      internal string StudentName;
      [DataMember]
      internal string StudentSurname;
      [DataMember]
      internal int StudentNumber;
      [DataMember]
      internal int StudentCourse;
   }

VB.NET

<DataContract> _
Friend Class Student
   <DataMember> _
   Friend StudentName As String
   <DataMember> _
   Friend StudentSurname As String
   <DataMember> _
   Friend StudentNumber As Integer
   <DataMember> _
   Friend StudentCourse As Integer
End Class

Create an instance of the Student type.

C#

Student s = new Student();
s.StudentName = "Hannes";
s.StudentSurname = "du Preez";
s.StudentNumber = 123;
s.StudentCourse = 5;

VB.NET

Student s = New Student()
s.StudentName = "Hannes"
s.StudentSurname = "du Preez"
s.StudentNumber = 123
s.StudentCourse = 5

Use DataContractJsonSerializer to serialize the Student object to a memory stream.

C#

MemoryStream streamStudent = new MemoryStream();
DataContractJsonSerializer ser = new
   DataContractJsonSerializer(typeof(Student));

VB.NET

Dim streamStudent As New MemoryStream()
Dim ser As New DataContractJsonSerializer(GetType(Student))

Write JSON data to the stream.

C#

ser.WriteObject(stream1, s);

VB.NET

ser.WriteObject(stream1, s)

Show output.

C#

streamStudent.Position = 0;
StreamReader sr = new StreamReader(streamStudent);
Console.WriteLine(sr.ReadToEnd());

VB.NET

streamStudent.Position = 0
StreamReader sr = New StreamReader(streamStudent)
Console.WriteLine(sr.ReadToEnd())

Deserialize.

Use the ReadObject method of the DataContractJsonSerializer to deserialize the Student object.

C#

streamStudent.Position = 0;
Student s2 = (Student)ser.ReadObject(streamStudent);

VB.NET

streamStudent.Position = 0
Student s2 = (Student)ser.ReadObject(streamStudent)

Show the results.

C#

Console.Write(s2.StudentName);
Console.Write(s2.StudentSurname);
Console.WriteLine(p2.StudentNumber);
Console.WriteLine(p2.StudentCourse);

VB.NET

Console.Write(s2.StudentName)
Console.Write(s2.StudentSurname)
Console.WriteLine(p2.StudentNumber)
Console.WriteLine(p2.StudentCourse)

Transport Layer Security (TLS) Support

Transport Layer Security (TLS) and its predecessor, Secure Sockets Layer (SSL), are cryptographic protocols that provide communications security over a computer network.

Create a new Console app in Visual Studio 2017 and enter the following. I am providing both C# and VB.NET versions:

C#

using System;
using System.Collections;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;
namespace Examples.System.Net
{
   public class TCPClient
   {
      private static Hashtable CertErrs = new Hashtable();
      public static bool Validate(object sender,
         X509Certificate certificate, X509Chain chain,
         SslPolicyErrors PolicyErrs)
      {
         if (PolicyErrs == SslPolicyErrors.None)
            return true;
            Console.WriteLine("Error: {0}", PolicyErrs);
            return false;
      }
      public static void CreateClient(string strMachineName,
         string strServerName)
      {
         // Create a TCP/IP client socket//
         TcpClient client = new TcpClient(strMachineName, 443);

         Console.WriteLine("Connected.");
         // Close the client's stream//
         SslStream sslStream = new SslStream(client.GetStream(),
            false, new RemoteCertificateValidationCallback
            (Validate), null);

         try
         {
            sslStream.AuthenticateAsClient(strServerName);
         }
         catch (AuthenticationException e)
         {
            Console.WriteLine("Error: {0}", e.Message);
            Console.WriteLine ("Authentication failed.");
            client.Close();
            return;
         }
         // Encode a test message into a byte array//
         byte[] bytArrMessage = Encoding.UTF8.GetBytes("Hello
            Hannes<END>");

         sslStream.Write(bytArrMessage);
         sslStream.Flush();
         string serverMessage = Read(sslStream);
         Console.WriteLine("Message: {0}", serverMessage);
         client.Close();
      }

      static string Read(SslStream sslStream)
      {
         // Read the  message//
         byte [] buffer = new byte[2048];
         StringBuilder sbMessage = new StringBuilder();
         int bytes = -1;
         do
         {

            bRead = sslStream.Read(buffer, 0, buffer.Length);
            Decoder decoder = Encoding.UTF8.GetDecoder();
            char[] chars = new char[decoder.GetCharCount(buffer,
               0, bRead)];

            decoder.GetChars(buffer, 0, bytes, chars,0);
            sbMessage.Append (chars);
            if (sbMessage.ToString().IndexOf("<END>") != -1)
            {
               break;
            }
         } while (bytes != 0);

            return sbMessage.ToString();
         }
         private static void Start()
         {
            Console.WriteLine("Enter Machine Name ");
            Environment.Exit(1);
      }
      public static int Main(string[] args)
      {
         string strServerCertName = null;
         string strMachineName = null;
         if (args == null || args.Length < 1 )
         {
            Start();
         }
         strMachineName = args[0];
         if (args.Length < 2 )
         {
            strServerCertName = strMachineName;
         }
         else
         {
            strServerCertName = args[1];
         }
         TCPClient.CreateClient (strMachineName,
            strServerCertName);
         return 0;

      }
   }
}

VB.NET

Imports System.Collections
Imports System.Net
Imports System.Net.Security
Imports System.Net.Sockets
Imports System.Security.Authentication
Imports System.Text
Imports System.Security.Cryptography.X509Certificates
Imports System.IO

   Public Module TCPClient
      Private Shared CertErrs As New Hashtable()
      Public Shared Function Validate(sender As Object, _
            certificate As X509Certificate, chain As X509Chain, _
            PolicyErrs As SslPolicyErrors) As Boolean
         If PolicyErrs = SslPolicyErrors.None Then
            Return True
         End If
         Console.WriteLine("Error: {0}", PolicyErrs)
         Return False
      End Function
      Public Shared Sub CreateClient(strMachineName As String, _
            strServerName As String)
         ' Create a TCP/IP client socket'
         Dim client As New TcpClient(strMachineName, 443)
         Console.WriteLine("Connected.")
         ' Close the clients stream'
         Dim sslStream As New SslStream(client.GetStream(), _
            False, New RemoteCertificateValidationCallback _
            (AddressOf Validate), Nothing)
         Try
            sslStream.AuthenticateAsClient(strServerName)
         Catch e As AuthenticationException
            Console.WriteLine("Error: {0}", e.Message)
            Console.WriteLine("Authentication failed.")
            client.Close()
            Return
         End Try
         ' Encode a test message into a byte array'
         Dim bytArrMessage As Byte() = Encoding.UTF8.GetBytes _
            ("Hello Hannes<END>")
         sslStream.Write(bytArrMessage)
         sslStream.Flush()
         Dim serverMessage As String = Read(sslStream)
         Console.WriteLine("Message: {0}", serverMessage)
         client.Close()
      End Sub
      Private Shared Function Read(sslStream As SslStream) _
            As String
         ' Read the  message'
         Dim buffer As Byte() = New Byte(2047) {}
         Dim sbMessage As New StringBuilder()
         Dim bytes As Integer = -1
         Do
            bRead = sslStream.Read(buffer, 0, buffer.Length)
            Dim decoder As Decoder = Encoding.UTF8.GetDecoder()
            Dim chars As Char() = New Char(decoder.GetCharCount _
               (buffer, 0, bRead) - 1) {}
            decoder.GetChars(buffer, 0, bytes, chars, 0)
            sbMessage.Append(chars)
            If sbMessage.ToString().IndexOf("<END>") _
                  <> -1 Then
               Exit Do
            End If
         Loop While bytes <> 0
         Return sbMessage.ToString()
      End Function

      Private Shared Sub Start()
         Console.WriteLine("Enter Machine Name ")
         Environment.[Exit](1)
      End Sub

      Public Shared Sub Main(args As String())
         Dim strServerCertName As String = Nothing
         Dim strMachineName As String = Nothing
         If args Is Nothing OrElse args.Length < 1 Then
            Start()
         End If
         strMachineName = args(0)
         If args.Length < 2 Then
            strServerCertName = strMachineName
         Else
            strServerCertName = args(1)
         End If
         TCPClient.CreateClient(strMachineName, strServerCertName)
         Return 0
      End Function
   End Module

Elliptic Curve Cryptography

Elliptic Curve Cryptography (ECC) is an extension to public key cryptography. In public key cryptography, two keys are used:

  • A public key that everyone knows
  • A private key that only you know

To encrypt, the public key is applied to the target by using a predefined operation that produces a pseudo-random number. To decrypt, the private key is applied to the pseudo-random number by using a different predefined operation. Usually, these operations are performed several times. The strength of public key cryptography lies in the fact that its algorithm knows that encryption is easy, and decryption is hard, thus making decryption impractical without the key.

With today’s technology and computers getting faster and more powerful by the day, there will come a time where the pseudo-prime cannot be made large enough to thwart an attack. That is where elliptic curve cryptography comes in. Elliptic curve cryptography uses the properties of an elliptical curve, the same pair of keys, and math to encrypt and decrypt the target information.

An elliptic curve is a graph that represents the points generated by the following equation:

y2 = x3 + ax + b

ImportParameters() methods were added to the ECDsa and ECDiffieHellman classes to allow for an object to represent an already established key. An ExportParameters() method also was added for exporting the key using explicit curve parameters.

Support for High-DPI Awareness Support in Windows Forms

High DPI (dots per inch) support improves the layout and appearance of forms and controls on high DPI monitors. You need to configure High DPI in your app’s Configuration file and you also need to add support for Windows 10 Compatibility in the Manifest file. High DPI (dots per inch) support is available only in applications that target the .NET Framework 4.7 as well as running on Windows 10 Creators Update onwards.

Add Windows 10 compatibility

Add the following code to your Manifest file:

<compatibility >
   <application>
      <!-- Windows 10 compatibility -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-
         48fd50a15a9a}" />
   </application>
</compatibility>

Add the High DPI support:

<System.Windows.Forms.ApplicationConfigurationSection>
   <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>

Lastly, call EnableVisualStyles in your program

C#

static void Main()
{
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.Run(new Form1());
}

VB.NET

Private Shared Sub Main()
   Application.EnableVisualStyles()
   Application.SetCompatibleTextRenderingDefault(False)
   Application.Run(New Form1())
End Sub

Conclusion

As time progresses, more and handier tricks to work with .NET Framework 4.7 come out. Now, let’s wait for the next .NET Framework!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read