Ver código fonte

Removes MessageAttribute in favor of properties on Message class (#1270)

* Exludes the test projects from code coverage reports

* Removes MessageAttribute in favor of properties on Message class

* Benchmark for removal of MessageAttribute
Jacob Slusser 1 ano atrás
pai
commit
f172ac587c
52 arquivos alterados com 755 adições e 138 exclusões
  1. 18 1
      src/Renci.SshNet/Messages/Authentication/BannerMessage.cs
  2. 18 1
      src/Renci.SshNet/Messages/Authentication/FailureMessage.cs
  3. 18 1
      src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs
  4. 18 1
      src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs
  5. 18 1
      src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs
  6. 18 1
      src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs
  7. 18 1
      src/Renci.SshNet/Messages/Authentication/RequestMessage.cs
  8. 18 1
      src/Renci.SshNet/Messages/Authentication/SuccessMessage.cs
  9. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs
  10. 17 2
      src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs
  11. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs
  12. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelExtendedDataMessage.cs
  13. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs
  14. 18 3
      src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs
  15. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelOpenConfirmationMessage.cs
  16. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs
  17. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs
  18. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs
  19. 18 1
      src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs
  20. 18 1
      src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs
  21. 18 1
      src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs
  22. 18 1
      src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs
  23. 15 41
      src/Renci.SshNet/Messages/Message.cs
  24. 0 38
      src/Renci.SshNet/Messages/MessageAttribute.cs
  25. 18 1
      src/Renci.SshNet/Messages/Transport/DebugMessage.cs
  26. 18 1
      src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs
  27. 17 2
      src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs
  28. 18 3
      src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs
  29. 18 1
      src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs
  30. 17 2
      src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs
  31. 17 2
      src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs
  32. 18 1
      src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs
  33. 18 1
      src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs
  34. 18 1
      src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs
  35. 18 1
      src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs
  36. 18 1
      src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs
  37. 18 1
      src/Renci.SshNet/Messages/Transport/NewKeysMessage.cs
  38. 17 2
      src/Renci.SshNet/Messages/Transport/ServiceAcceptMessage.cs
  39. 18 1
      src/Renci.SshNet/Messages/Transport/ServiceRequestMessage.cs
  40. 18 1
      src/Renci.SshNet/Messages/Transport/UnimplementedMessage.cs
  41. 35 0
      test/Renci.SshNet.Benchmarks/Messages/MessageBenchmarks.cs
  42. 2 2
      test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj
  43. 5 0
      test/Renci.SshNet.IntegrationTests/Properties/AssemblyInfo.cs
  44. 1 1
      test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs
  45. 3 3
      test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs
  46. 1 1
      test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs
  47. 2 1
      test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs
  48. 2 1
      test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs
  49. 1 1
      test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs
  50. 2 1
      test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs
  51. 2 1
      test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs
  52. 5 0
      test/Renci.SshNet.Tests/Properties/AssemblyInfo.cs

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/BannerMessage.cs

@@ -3,12 +3,29 @@
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_BANNER message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_BANNER", 53)]
     public class BannerMessage : Message
     {
         private byte[] _message;
         private byte[] _language;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_BANNER";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 53;
+            }
+        }
+
         /// <summary>
         /// Gets banner message.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/FailureMessage.cs

@@ -5,9 +5,26 @@ namespace Renci.SshNet.Messages.Authentication
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_FAILURE message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_FAILURE", 51)]
     public class FailureMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_FAILURE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 51;
+            }
+        }
+
         /// <summary>
         /// Gets or sets the allowed authentications if available.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs

@@ -8,9 +8,26 @@ namespace Renci.SshNet.Messages.Authentication
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_INFO_REQUEST message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_INFO_REQUEST", 60)]
     internal sealed class InformationRequestMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_INFO_REQUEST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 60;
+            }
+        }
+
         /// <summary>
         /// Gets information request name.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs

@@ -6,9 +6,26 @@ namespace Renci.SshNet.Messages.Authentication
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_INFO_RESPONSE message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_INFO_RESPONSE", 61)]
     internal sealed class InformationResponseMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_INFO_RESPONSE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 61;
+            }
+        }
+
         /// <summary>
         /// Gets authentication responses.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_PASSWD_CHANGEREQ message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60)]
     internal sealed class PasswordChangeRequiredMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 60;
+            }
+        }
+
         /// <summary>
         /// Gets password change request message as UTF-8 encoded byte array.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_PK_OK message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_PK_OK", 60)]
     internal sealed class PublicKeyMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_PK_OK";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 60;
+            }
+        }
+
         /// <summary>
         /// Gets the name of the public key algorithm as ASCII encoded byte array.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/RequestMessage.cs

@@ -6,9 +6,26 @@ namespace Renci.SshNet.Messages.Authentication
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_REQUEST message. Server as a base message for other user authentication requests.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_REQUEST", AuthenticationMessageCode)]
     public abstract class RequestMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_REQUEST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return AuthenticationMessageCode;
+            }
+        }
+
         /// <summary>
         /// Returns the authentication message code for <c>SSH_MSG_USERAUTH_REQUEST</c>.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Authentication/SuccessMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_USERAUTH_SUCCESS message.
     /// </summary>
-    [Message("SSH_MSG_USERAUTH_SUCCESS", 52)]
     public class SuccessMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_USERAUTH_SUCCESS";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 52;
+            }
+        }
+
         /// <summary>
         /// Called when type specific data need to be loaded.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_CLOSE message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_CLOSE", 97)]
     public class ChannelCloseMessage : ChannelMessage
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_CLOSE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 97;
+            }
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ChannelCloseMessage"/> class.
         /// </summary>

+ 17 - 2
src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs

@@ -5,10 +5,25 @@ namespace Renci.SshNet.Messages.Connection
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_DATA message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_DATA", MessageNumber)]
     public class ChannelDataMessage : ChannelMessage
     {
-        internal const byte MessageNumber = 94;
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_DATA";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 94;
+            }
+        }
 
         /// <summary>
         /// Gets the message data.

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_EOF message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_EOF", 96)]
     public class ChannelEofMessage : ChannelMessage
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_EOF";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 96;
+            }
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ChannelEofMessage"/> class.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelExtendedDataMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_EXTENDED_DATA message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_EXTENDED_DATA", 95)]
     public class ChannelExtendedDataMessage : ChannelMessage
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_EXTENDED_DATA";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 95;
+            }
+        }
+
         /// <summary>
         /// Gets message data type code.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_FAILURE message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_FAILURE", 100)]
     public class ChannelFailureMessage : ChannelMessage
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_FAILURE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 100;
+            }
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ChannelFailureMessage"/> class.
         /// </summary>

+ 18 - 3
src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs

@@ -6,13 +6,28 @@ namespace Renci.SshNet.Messages.Connection
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_OPEN message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_OPEN", MessageNumber)]
     public class ChannelOpenMessage : Message
     {
-        internal const byte MessageNumber = 90;
-
         private byte[] _infoBytes;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_OPEN";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 90;
+            }
+        }
+
         /// <summary>
         /// Gets the type of the channel as ASCII encoded byte array.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelOpenConfirmationMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_OPEN_CONFIRMATION message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91)]
     public class ChannelOpenConfirmationMessage : ChannelMessage
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_OPEN_CONFIRMATION";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 91;
+            }
+        }
+
         /// <summary>
         /// Gets the remote channel number.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs

@@ -3,7 +3,6 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_OPEN_FAILURE message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_OPEN_FAILURE", 92)]
     public class ChannelOpenFailureMessage : ChannelMessage
     {
         internal const uint AdministrativelyProhibited = 1;
@@ -14,6 +13,24 @@
         private byte[] _description;
         private byte[] _language;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_OPEN_FAILURE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 92;
+            }
+        }
+
         /// <summary>
         /// Gets failure reason code.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs

@@ -3,12 +3,29 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_REQUEST message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_REQUEST", 98)]
     public class ChannelRequestMessage : ChannelMessage
     {
         private string _requestName;
         private byte[] _requestNameBytes;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_REQUEST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 98;
+            }
+        }
+
         /// <summary>
         /// Gets the name of the request.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs

@@ -3,7 +3,6 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_SUCCESS message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_SUCCESS", 99)]
     public class ChannelSuccessMessage : ChannelMessage
     {
         /// <summary>
@@ -22,6 +21,24 @@
         {
         }
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_SUCCESS";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 99;
+            }
+        }
+
         internal override void Process(Session session)
         {
             session.OnChannelSuccessReceived(this);

+ 18 - 1
src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_CHANNEL_SUCCESS message.
     /// </summary>
-    [Message("SSH_MSG_CHANNEL_WINDOW_ADJUST", 93)]
     public class ChannelWindowAdjustMessage : ChannelMessage
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_CHANNEL_WINDOW_ADJUST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 93;
+            }
+        }
+
         /// <summary>
         /// Gets number of bytes to add to the window.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs

@@ -3,11 +3,28 @@
     /// <summary>
     /// Represents SSH_MSG_GLOBAL_REQUEST message.
     /// </summary>
-    [Message("SSH_MSG_GLOBAL_REQUEST", 80)]
     public class GlobalRequestMessage : Message
     {
         private byte[] _requestName;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_GLOBAL_REQUEST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 80;
+            }
+        }
+
         /// <summary>
         /// Gets the name of the request.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_REQUEST_FAILURE message.
     /// </summary>
-    [Message("SSH_MSG_REQUEST_FAILURE", 82)]
     public class RequestFailureMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_REQUEST_FAILURE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 82;
+            }
+        }
+
         /// <summary>
         /// Called when type specific data need to be loaded.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_REQUEST_SUCCESS message.
     /// </summary>
-    [Message("SSH_MSG_REQUEST_SUCCESS", 81)]
     public class RequestSuccessMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_REQUEST_SUCCESS";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 81;
+            }
+        }
+
         /// <summary>
         /// Gets the bound port.
         /// </summary>

+ 15 - 41
src/Renci.SshNet/Messages/Message.cs

@@ -1,5 +1,4 @@
-using System.Globalization;
-using System.IO;
+using System.IO;
 
 using Renci.SshNet.Abstractions;
 using Renci.SshNet.Common;
@@ -13,11 +12,16 @@ namespace Renci.SshNet.Messages
     public abstract class Message : SshData
     {
         /// <summary>
-        /// Gets the size of the message in bytes.
+        /// Gets the message name as defined in RFC 4250.
         /// </summary>
-        /// <value>
-        /// The size of the messages in bytes.
-        /// </value>
+        public abstract string MessageName { get; }
+
+        /// <summary>
+        /// Gets the message number as defined in RFC 4250.
+        /// </summary>
+        public abstract byte MessageNumber { get; }
+
+        /// <inheritdoc />
         protected override int BufferCapacity
         {
             get
@@ -26,28 +30,11 @@ namespace Renci.SshNet.Messages
             }
         }
 
-        /// <summary>
-        /// Writes the message to the specified <see cref="SshDataStream"/>.
-        /// </summary>
-        /// <param name="stream">The <see cref="SshDataStream"/> to write the message to.</param>
+        /// <inheritdoc />
         protected override void WriteBytes(SshDataStream stream)
         {
-            var enumerator = GetType().GetCustomAttributes<MessageAttribute>(inherit: true).GetEnumerator();
-            try
-            {
-                if (!enumerator.MoveNext())
-                {
-                    throw new SshException(string.Format(CultureInfo.CurrentCulture, "Type '{0}' is not a valid message type.", GetType().AssemblyQualifiedName));
-                }
-
-                var messageAttribute = enumerator.Current;
-                stream.WriteByte(messageAttribute.Number);
-                base.WriteBytes(stream);
-            }
-            finally
-            {
-                enumerator.Dispose();
-            }
+            stream.WriteByte(MessageNumber);
+            base.WriteBytes(stream);
         }
 
         internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor)
@@ -163,23 +150,10 @@ namespace Renci.SshNet.Messages
             return paddingLength;
         }
 
-        /// <summary>
-        /// Returns a <see cref="string"/> that represents this instance.
-        /// </summary>
-        /// <returns>
-        /// A <see cref="string"/> that represents this instance.
-        /// </returns>
+        /// <inheritdoc />
         public override string ToString()
         {
-            using (var enumerator = GetType().GetCustomAttributes<MessageAttribute>(inherit: true).GetEnumerator())
-            {
-                if (!enumerator.MoveNext())
-                {
-                    return string.Format(CultureInfo.CurrentCulture, "'{0}' without Message attribute.", GetType().FullName);
-                }
-
-                return enumerator.Current.Name;
-            }
+            return MessageName;
         }
 
         /// <summary>

+ 0 - 38
src/Renci.SshNet/Messages/MessageAttribute.cs

@@ -1,38 +0,0 @@
-using System;
-
-namespace Renci.SshNet.Messages
-{
-    /// <summary>
-    /// Indicates that a class represents SSH message. This class cannot be inherited.
-    /// </summary>
-    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
-    public sealed class MessageAttribute : Attribute
-    {
-        /// <summary>
-        /// Gets the message name as defined in RFC 4250.
-        /// </summary>
-        /// <value>
-        /// The name.
-        /// </value>
-        public string Name { get; }
-
-        /// <summary>
-        /// Gets the message number as defined in RFC 4250.
-        /// </summary>
-        /// <value>
-        /// The number.
-        /// </value>
-        public byte Number { get; }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="MessageAttribute"/> class.
-        /// </summary>
-        /// <param name="name">The name.</param>
-        /// <param name="number">The number.</param>
-        public MessageAttribute(string name, byte number)
-        {
-            Name = name;
-            Number = number;
-        }
-    }
-}

+ 18 - 1
src/Renci.SshNet/Messages/Transport/DebugMessage.cs

@@ -3,12 +3,29 @@
     /// <summary>
     /// Represents SSH_MSG_DEBUG message.
     /// </summary>
-    [Message("SSH_MSG_DEBUG", 4)]
     public class DebugMessage : Message
     {
         private byte[] _message;
         private byte[] _language;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_DEBUG";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 4;
+            }
+        }
+
         /// <summary>
         /// Gets a value indicating whether the message to be always displayed.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs

@@ -3,12 +3,29 @@
     /// <summary>
     /// Represents SSH_MSG_DISCONNECT message.
     /// </summary>
-    [Message("SSH_MSG_DISCONNECT", 1)]
     public class DisconnectMessage : Message, IKeyExchangedAllowed
     {
         private byte[] _description;
         private byte[] _language;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_DISCONNECT";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 1;
+            }
+        }
+
         /// <summary>
         /// Gets disconnect reason code.
         /// </summary>

+ 17 - 2
src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs

@@ -5,10 +5,25 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_IGNORE message.
     /// </summary>
-    [Message("SSH_MSG_IGNORE", MessageNumber)]
     public class IgnoreMessage : Message
     {
-        internal const byte MessageNumber = 2;
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_IGNORE";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 2;
+            }
+        }
 
         /// <summary>
         /// Gets ignore message data if this message has been initialised

+ 18 - 3
src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs

@@ -5,14 +5,29 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_KEX_DH_GEX_GROUP message.
     /// </summary>
-    [Message("SSH_MSG_KEX_DH_GEX_GROUP", MessageNumber)]
     public class KeyExchangeDhGroupExchangeGroup : Message
     {
-        internal const byte MessageNumber = 31;
-
         private byte[] _safePrime;
         private byte[] _subGroup;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEX_DH_GEX_GROUP";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 31;
+            }
+        }
+
         /// <summary>
         /// Gets the safe prime.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_KEX_DH_GEX_INIT message.
     /// </summary>
-    [Message("SSH_MSG_KEX_DH_GEX_INIT", 32)]
     internal sealed class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEX_DH_GEX_INIT";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 32;
+            }
+        }
+
         /// <summary>
         /// Gets the E value.
         /// </summary>

+ 17 - 2
src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs

@@ -3,10 +3,25 @@
     /// <summary>
     /// Represents SSH_MSG_KEX_DH_GEX_REPLY message.
     /// </summary>
-    [Message("SSH_MSG_KEX_DH_GEX_REPLY", MessageNumber)]
     internal sealed class KeyExchangeDhGroupExchangeReply : Message
     {
-        internal const byte MessageNumber = 33;
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEX_DH_GEX_REPLY";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 33;
+            }
+        }
 
         /// <summary>
         /// Gets server public host key and certificates.

+ 17 - 2
src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs

@@ -3,10 +3,25 @@
     /// <summary>
     /// Represents SSH_MSG_KEX_DH_GEX_REQUEST message.
     /// </summary>
-    [Message("SSH_MSG_KEX_DH_GEX_REQUEST", MessageNumber)]
     internal sealed class KeyExchangeDhGroupExchangeRequest : Message, IKeyExchangedAllowed
     {
-        internal const byte MessageNumber = 34;
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEX_DH_GEX_REQUEST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 34;
+            }
+        }
 
         /// <summary>
         /// Gets the minimum size, in bits, of an acceptable group.

+ 18 - 1
src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_KEXDH_INIT message.
     /// </summary>
-    [Message("SSH_MSG_KEXDH_INIT", 30)]
     internal sealed class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEXDH_INIT";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 30;
+            }
+        }
+
         /// <summary>
         /// Gets the E value.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_KEXDH_REPLY message.
     /// </summary>
-    [Message("SSH_MSG_KEXDH_REPLY", 31)]
     public class KeyExchangeDhReplyMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEXDH_REPLY";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 31;
+            }
+        }
+
         /// <summary>
         /// Gets server public host key and certificates.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs

@@ -6,9 +6,26 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_KEXECDH_INIT message.
     /// </summary>
-    [Message("SSH_MSG_KEX_ECDH_INIT", 30)]
     internal sealed class KeyExchangeEcdhInitMessage : Message, IKeyExchangedAllowed
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEX_ECDH_INIT";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 30;
+            }
+        }
+
         /// <summary>
         /// Gets the client's ephemeral contribution to the ECDH exchange, encoded as an octet string.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_KEXECDH_REPLY message.
     /// </summary>
-    [Message("SSH_MSG_KEX_ECDH_REPLY", 31)]
     public class KeyExchangeEcdhReplyMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEX_ECDH_REPLY";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 31;
+            }
+        }
+
         /// <summary>
         /// Gets a string encoding an X.509v3 certificate containing the server's ECDSA public host key.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs

@@ -5,7 +5,6 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_KEXINIT message.
     /// </summary>
-    [Message("SSH_MSG_KEXINIT", 20)]
     public class KeyExchangeInitMessage : Message, IKeyExchangedAllowed
     {
         /// <summary>
@@ -20,6 +19,24 @@ namespace Renci.SshNet.Messages.Transport
 
         #region Message Properties
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_KEXINIT";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 20;
+            }
+        }
+
         /// <summary>
         /// Gets session cookie.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/NewKeysMessage.cs

@@ -3,9 +3,26 @@
     /// <summary>
     /// Represents SSH_MSG_NEWKEYS message.
     /// </summary>
-    [Message("SSH_MSG_NEWKEYS", 21)]
     public class NewKeysMessage : Message, IKeyExchangedAllowed
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_NEWKEYS";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 21;
+            }
+        }
+
         /// <summary>
         /// Called when type specific data need to be loaded.
         /// </summary>

+ 17 - 2
src/Renci.SshNet/Messages/Transport/ServiceAcceptMessage.cs

@@ -6,10 +6,25 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_SERVICE_ACCEPT message.
     /// </summary>
-    [Message("SSH_MSG_SERVICE_ACCEPT", MessageNumber)]
     public class ServiceAcceptMessage : Message
     {
-        internal const byte MessageNumber = 6;
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_SERVICE_ACCEPT";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 6;
+            }
+        }
 
         /// <summary>
         /// Gets the name of the service.

+ 18 - 1
src/Renci.SshNet/Messages/Transport/ServiceRequestMessage.cs

@@ -6,11 +6,28 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_SERVICE_REQUEST message.
     /// </summary>
-    [Message("SSH_MSG_SERVICE_REQUEST", 5)]
     public class ServiceRequestMessage : Message
     {
         private readonly byte[] _serviceName;
 
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_SERVICE_REQUEST";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 5;
+            }
+        }
+
         /// <summary>
         /// Gets the name of the service.
         /// </summary>

+ 18 - 1
src/Renci.SshNet/Messages/Transport/UnimplementedMessage.cs

@@ -5,9 +5,26 @@ namespace Renci.SshNet.Messages.Transport
     /// <summary>
     /// Represents SSH_MSG_UNIMPLEMENTED message.
     /// </summary>
-    [Message("SSH_MSG_UNIMPLEMENTED", 3)]
     public class UnimplementedMessage : Message
     {
+        /// <inheritdoc />
+        public override string MessageName
+        {
+            get
+            {
+                return "SSH_MSG_UNIMPLEMENTED";
+            }
+        }
+
+        /// <inheritdoc />
+        public override byte MessageNumber
+        {
+            get
+            {
+                return 3;
+            }
+        }
+
         /// <summary>
         /// Called when type specific data need to be loaded.
         /// </summary>

+ 35 - 0
test/Renci.SshNet.Benchmarks/Messages/MessageBenchmarks.cs

@@ -0,0 +1,35 @@
+using BenchmarkDotNet.Attributes;
+
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages;
+using Renci.SshNet.Messages.Transport;
+
+namespace Renci.SshNet.Benchmarks.Messages
+{
+    [MemoryDiagnoser]
+    public class MessageBenchmarks
+    {
+        [Benchmark]
+        public Message WriteBytes()
+        {
+            using var sshDataStream = new SshDataStream(SshData.DefaultCapacity);
+            var bannerMessage = new WritableDisconnectMessage(DisconnectReason.ServiceNotAvailable, "Goodbye");
+            bannerMessage.WritePrivateBytes(sshDataStream);
+
+            return bannerMessage; // Avoid JIT elimination
+        }
+
+        private sealed class WritableDisconnectMessage : DisconnectMessage
+        {
+            public WritableDisconnectMessage(DisconnectReason reasonCode, string message)
+                : base(reasonCode, message)
+            {
+            }
+
+            public void WritePrivateBytes(SshDataStream sshDataStream)
+            {
+                WriteBytes(sshDataStream);
+            }
+        }
+    }
+}

+ 2 - 2
test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <OutputType>Exe</OutputType>
     <TargetFramework>net8.0</TargetFramework>
@@ -7,7 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="BenchmarkDotNet" Version="0.13.9" />
+    <PackageReference Include="BenchmarkDotNet" Version="0.13.11" />
   </ItemGroup>
 
   <ItemGroup>

+ 5 - 0
test/Renci.SshNet.IntegrationTests/Properties/AssemblyInfo.cs

@@ -0,0 +1,5 @@
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: ExcludeFromCodeCoverage]
+#endif // NET6_0_OR_GREATER

+ 1 - 1
test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs

@@ -116,7 +116,7 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection
 
             var sshDataStream = new SshDataStream(bytes);
 
-            Assert.AreEqual(ChannelDataMessage.MessageNumber, sshDataStream.ReadByte());
+            Assert.AreEqual(target.MessageNumber, sshDataStream.ReadByte());
             Assert.AreEqual(localChannelNumber, sshDataStream.ReadUInt32());
             Assert.AreEqual((uint) size, sshDataStream.ReadUInt32());
 

+ 3 - 3
test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs

@@ -94,7 +94,7 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection
 
             var sshDataStream = new SshDataStream(bytes);
 
-            Assert.AreEqual(ChannelOpenMessage.MessageNumber, sshDataStream.ReadByte());
+            Assert.AreEqual(target.MessageNumber, sshDataStream.ReadByte());
 
             var actualChannelTypeLength = sshDataStream.ReadUInt32();
             Assert.AreEqual((uint) target.ChannelType.Length, actualChannelTypeLength);
@@ -225,16 +225,16 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection
             var maximumPacketSize = (uint)_random.Next(0, int.MaxValue);
             var channelName = "dunno_" + _random.Next().ToString(CultureInfo.InvariantCulture);
             var channelType = _ascii.GetBytes(channelName);
+            var target = new ChannelOpenMessage();
 
             var sshDataStream = new SshDataStream(1 + 4 + channelType.Length + 4 + 4 + 4);
-            sshDataStream.WriteByte(ChannelOpenMessage.MessageNumber);
+            sshDataStream.WriteByte(target.MessageNumber);
             sshDataStream.Write((uint) channelType.Length);
             sshDataStream.Write(channelType, 0, channelType.Length);
             sshDataStream.Write(localChannelNumber);
             sshDataStream.Write(initialWindowSize);
             sshDataStream.Write(maximumPacketSize);
             var bytes = sshDataStream.ToArray();
-            var target = new ChannelOpenMessage();
 
             try
             {

+ 1 - 1
test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs

@@ -68,7 +68,7 @@ namespace Renci.SshNet.Tests.Classes.Messages.Transport
 
             var sshDataStream = new SshDataStream(bytes);
 
-            Assert.AreEqual(IgnoreMessage.MessageNumber, sshDataStream.ReadByte());
+            Assert.AreEqual(request.MessageNumber, sshDataStream.ReadByte());
             Assert.AreEqual((uint) _data.Length, sshDataStream.ReadUInt32());
 
             var actualData = new byte[_data.Length];

+ 2 - 1
test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs

@@ -23,7 +23,8 @@ namespace Renci.SshNet.Tests.Classes.Messages.Transport
         public byte[] Build()
         {
             var sshDataStream = new SshDataStream(0);
-            sshDataStream.WriteByte(KeyExchangeDhGroupExchangeGroup.MessageNumber);
+            var target = new KeyExchangeDhGroupExchangeGroup();
+            sshDataStream.WriteByte(target.MessageNumber);
             sshDataStream.Write(_safePrime);
             sshDataStream.Write(_subGroup);
             return sshDataStream.ToArray();

+ 2 - 1
test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs

@@ -41,7 +41,8 @@ namespace Renci.SshNet.Tests.Classes.Messages.Transport
         public byte[] Build()
         {
             var sshDataStream = new SshDataStream(0);
-            sshDataStream.WriteByte(KeyExchangeDhGroupExchangeReply.MessageNumber);
+            var target = new KeyExchangeDhGroupExchangeReply();
+            sshDataStream.WriteByte(target.MessageNumber);
             sshDataStream.Write((uint)(4 + _hostKeyAlgorithm.Length + _hostKeys.Length));
             sshDataStream.Write((uint) _hostKeyAlgorithm.Length);
             sshDataStream.Write(_hostKeyAlgorithm, 0, _hostKeyAlgorithm.Length);

+ 1 - 1
test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs

@@ -46,7 +46,7 @@ namespace Renci.SshNet.Tests.Classes.Messages.Transport
 
             var sshDataStream = new SshDataStream(bytes);
 
-            Assert.AreEqual(KeyExchangeDhGroupExchangeRequest.MessageNumber, sshDataStream.ReadByte());
+            Assert.AreEqual(request.MessageNumber, sshDataStream.ReadByte());
             Assert.AreEqual(_minimum, sshDataStream.ReadUInt32());
             Assert.AreEqual(_preferred, sshDataStream.ReadUInt32());
             Assert.AreEqual(_maximum, sshDataStream.ReadUInt32());

+ 2 - 1
test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs

@@ -244,11 +244,12 @@ namespace Renci.SshNet.Tests.Classes
             public byte[] Build()
             {
                 var serviceName = _serviceName.ToArray();
+                var target = new ServiceAcceptMessage();
 
                 var sshDataStream = new SshDataStream(4 + 1 + 1 + 4 + serviceName.Length);
                 sshDataStream.Write((uint)(sshDataStream.Capacity - 4)); // packet length
                 sshDataStream.WriteByte(0); // padding length
-                sshDataStream.WriteByte(ServiceAcceptMessage.MessageNumber);
+                sshDataStream.WriteByte(target.MessageNumber);
                 sshDataStream.WriteBinary(serviceName);
                 return sshDataStream.ToArray();
             }

+ 2 - 1
test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs

@@ -222,11 +222,12 @@ namespace Renci.SshNet.Tests.Classes
             public byte[] Build()
             {
                 var serviceName = _serviceName.ToArray();
+                var target = new ServiceAcceptMessage();
 
                 var sshDataStream = new SshDataStream(4 + 1 + 1 + 4 + serviceName.Length);
                 sshDataStream.Write((uint)(sshDataStream.Capacity - 4)); // packet length
                 sshDataStream.WriteByte(0); // padding length
-                sshDataStream.WriteByte(ServiceAcceptMessage.MessageNumber);
+                sshDataStream.WriteByte(target.MessageNumber);
                 sshDataStream.WriteBinary(serviceName);
                 return sshDataStream.ToArray();
             }

+ 5 - 0
test/Renci.SshNet.Tests/Properties/AssemblyInfo.cs

@@ -0,0 +1,5 @@
+#if NET6_0_OR_GREATER
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: ExcludeFromCodeCoverage]
+#endif // NET6_0_OR_GREATER