diff --git a/QuickFIXn/AcceptorSocketDescriptor.cs b/QuickFIXn/AcceptorSocketDescriptor.cs index 4ebaa2640..9779ad096 100644 --- a/QuickFIXn/AcceptorSocketDescriptor.cs +++ b/QuickFIXn/AcceptorSocketDescriptor.cs @@ -3,58 +3,50 @@ using System.Net; using QuickFix.Logger; -namespace QuickFix -{ - internal class AcceptorSocketDescriptor - { - public ThreadedSocketReactor SocketReactor { get; } - public IPEndPoint Address { get; } +namespace QuickFix; - private readonly Dictionary _acceptedSessions = new (); +internal class AcceptorSocketDescriptor +{ + public ThreadedSocketReactor SocketReactor { get; } + public IPEndPoint Address { get; } - internal AcceptorSocketDescriptor( - IPEndPoint socketEndPoint, - SocketSettings socketSettings, - IQuickFixLoggerFactory loggerFactory) - { - Address = socketEndPoint; - SocketReactor = new ThreadedSocketReactor(Address, socketSettings, this, loggerFactory); - } + private readonly Dictionary _acceptedSessions = new (); - internal AcceptorSocketDescriptor( - IPEndPoint socketEndPoint, - SocketSettings socketSettings, - SettingsDictionary sessionDict, - IQuickFixLoggerFactory nonSessionLog) : this(socketEndPoint, socketSettings, nonSessionLog) - { } + internal AcceptorSocketDescriptor( + IPEndPoint socketEndPoint, + SocketSettings socketSettings, + IQuickFixLoggerFactory loggerFactory) + { + Address = socketEndPoint; + SocketReactor = new ThreadedSocketReactor(Address, socketSettings, this, loggerFactory); + } - internal void AcceptSession(Session session) + internal void AcceptSession(Session session) + { + lock (_acceptedSessions) { - lock (_acceptedSessions) - { - _acceptedSessions[session.SessionID] = session; - } + _acceptedSessions[session.SessionID] = session; } + } - /// - /// Remove a session from those tied to this socket. - /// - /// ID of session to be removed - /// true if session removed, false if not found - internal bool RemoveSession(SessionID sessionId) + /// + /// Remove a session from those tied to this socket. + /// + /// ID of session to be removed + /// true if session removed, false if not found + internal bool RemoveSession(SessionID sessionId) + { + lock (_acceptedSessions) { - lock (_acceptedSessions) - { - return _acceptedSessions.Remove(sessionId); - } + return _acceptedSessions.Remove(sessionId); } + } - internal Dictionary GetAcceptedSessions() + internal Dictionary GetAcceptedSessions() + { + lock (_acceptedSessions) { - lock (_acceptedSessions) - { - return new Dictionary(_acceptedSessions); - } + return new Dictionary(_acceptedSessions); } } } diff --git a/QuickFIXn/DefaultMessageFactory.cs b/QuickFIXn/DefaultMessageFactory.cs index 6d0688ac6..76a8e2dc0 100644 --- a/QuickFIXn/DefaultMessageFactory.cs +++ b/QuickFIXn/DefaultMessageFactory.cs @@ -5,187 +5,186 @@ using System.Reflection; using QuickFix.Fields; -namespace QuickFix +namespace QuickFix; + +/// +/// The default factory for creating FIX message instances. (In the v2.0 release, this class should be made sealed.) +/// +public class DefaultMessageFactory : IMessageFactory { /// - /// The default factory for creating FIX message instances. (In the v2.0 release, this class should be made sealed.) + /// key is BeginString (including the fake FIX50 beginstrings) /// - public class DefaultMessageFactory : IMessageFactory - { - /// - /// key is BeginString (including the fake FIX50 beginstrings) - /// - private readonly IReadOnlyDictionary _factories; - - private readonly QuickFix.Fields.ApplVerID _defaultApplVerId; - - /// - /// This constructor will - /// 1. Dynamically load all QuickFix.*.dll assemblies into the current appdomain - /// 2. Find all IMessageFactory implementations in these assemblies (must have parameterless constructor) - /// 3. Use them based on begin strings they support - /// - /// ApplVerID value used by default in Create methods that don't explicitly specify it (only relevant for FIX5+) - public DefaultMessageFactory(string defaultApplVerId = QuickFix.FixValues.ApplVerID.FIX50SP2) - { - _defaultApplVerId = new ApplVerID(defaultApplVerId); - var assemblies = GetAppDomainAssemblies(); - var factories = GetMessageFactories(assemblies); - _factories = ConvertToDictionary(factories); - } + private readonly IReadOnlyDictionary _factories; - /// - /// This constructor will - /// 1. Locate all IMessageFactory implementations from the provided assemblies (must have parameterless constructor) - /// 2. Use them based on begin strings they support - /// - /// Assemblies that may contain IMessageFactory implementations - /// ApplVerID value used by default in Create methods that don't explicitly specify it (only relevant for FIX5+) - public DefaultMessageFactory(IEnumerable assemblies, string defaultApplVerId = QuickFix.FixValues.ApplVerID.FIX50SP2) - { - _defaultApplVerId = new ApplVerID(defaultApplVerId); - var factories = GetMessageFactories(assemblies); - _factories = ConvertToDictionary(factories); - } + private readonly QuickFix.Fields.ApplVerID _defaultApplVerId; - #region IMessageFactory Members + /// + /// This constructor will + /// 1. Dynamically load all QuickFix.*.dll assemblies into the current appdomain + /// 2. Find all IMessageFactory implementations in these assemblies (must have parameterless constructor) + /// 3. Use them based on begin strings they support + /// + /// ApplVerID value used by default in Create methods that don't explicitly specify it (only relevant for FIX5+) + public DefaultMessageFactory(string defaultApplVerId = QuickFix.FixValues.ApplVerID.FIX50SP2) + { + _defaultApplVerId = new ApplVerID(defaultApplVerId); + var assemblies = GetAppDomainAssemblies(); + var factories = GetMessageFactories(assemblies); + _factories = ConvertToDictionary(factories); + } - public ICollection GetSupportedBeginStrings() - { - return _factories.Keys.ToList(); - } + /// + /// This constructor will + /// 1. Locate all IMessageFactory implementations from the provided assemblies (must have parameterless constructor) + /// 2. Use them based on begin strings they support + /// + /// Assemblies that may contain IMessageFactory implementations + /// ApplVerID value used by default in Create methods that don't explicitly specify it (only relevant for FIX5+) + public DefaultMessageFactory(IEnumerable assemblies, string defaultApplVerId = QuickFix.FixValues.ApplVerID.FIX50SP2) + { + _defaultApplVerId = new ApplVerID(defaultApplVerId); + var factories = GetMessageFactories(assemblies); + _factories = ConvertToDictionary(factories); + } - public Message Create(string beginString, string msgType) - { - return Create(beginString, _defaultApplVerId, msgType); - } + #region IMessageFactory Members - public Message Create(string beginString, QuickFix.Fields.ApplVerID applVerId, string msgType) - { - _factories.TryGetValue(beginString, out IMessageFactory? messageFactory); + public ICollection GetSupportedBeginStrings() + { + return _factories.Keys.ToList(); + } - if (beginString == QuickFix.Values.BeginString_FIXT11 && !Message.IsAdminMsgType(msgType)) - { - _factories.TryGetValue( - QuickFix.FixValues.ApplVerID.ToBeginString(applVerId.Value), - out messageFactory); - } + public Message Create(string beginString, string msgType) + { + return Create(beginString, _defaultApplVerId, msgType); + } - if (messageFactory != null) - return messageFactory.Create(beginString, applVerId, msgType); + public Message Create(string beginString, QuickFix.Fields.ApplVerID applVerId, string msgType) + { + _factories.TryGetValue(beginString, out IMessageFactory? messageFactory); - // didn't find a factory, so return a generic Message object - var message = new Message(); - message.Header.SetField(new StringField(QuickFix.Fields.Tags.MsgType, msgType)); - return message; + if (beginString == QuickFix.Values.BeginString_FIXT11 && !Message.IsAdminMsgType(msgType)) + { + _factories.TryGetValue( + QuickFix.FixValues.ApplVerID.ToBeginString(applVerId.Value), + out messageFactory); } - public Group? Create(string beginString, string msgType, int groupCounterTag) - { - string key = beginString; - if(beginString.Equals(FixValues.BeginString.FIXT11)) - key = QuickFix.FixValues.ApplVerID.ToBeginString(_defaultApplVerId.Value); + if (messageFactory != null) + return messageFactory.Create(beginString, applVerId, msgType); - if (_factories.TryGetValue(key, out IMessageFactory? factory)) - return factory.Create(beginString, msgType, groupCounterTag); + // didn't find a factory, so return a generic Message object + var message = new Message(); + message.Header.SetField(new StringField(QuickFix.Fields.Tags.MsgType, msgType)); + return message; + } - throw new UnsupportedVersion(beginString); - } + public Group? Create(string beginString, string msgType, int groupCounterTag) + { + string key = beginString; + if(beginString.Equals(FixValues.BeginString.FIXT11)) + key = QuickFix.FixValues.ApplVerID.ToBeginString(_defaultApplVerId.Value); + + if (_factories.TryGetValue(key, out IMessageFactory? factory)) + return factory.Create(beginString, msgType, groupCounterTag); + + throw new UnsupportedVersion(beginString); + } - #endregion + #endregion - #region Dynamic assembly load related methods + #region Dynamic assembly load related methods - /// - /// Creates a dictionary keyed by each IMessageFactory's supported BeginStrings - /// - /// - /// - private static Dictionary ConvertToDictionary(IEnumerable factories) + /// + /// Creates a dictionary keyed by each IMessageFactory's supported BeginStrings + /// + /// + /// + private static Dictionary ConvertToDictionary(IEnumerable factories) + { + var dict = new Dictionary(); + foreach (var factory in factories) { - var dict = new Dictionary(); - foreach (var factory in factories) + foreach (var beginString in factory.GetSupportedBeginStrings()) { - foreach (var beginString in factory.GetSupportedBeginStrings()) - { - dict[beginString] = factory; - } + dict[beginString] = factory; } - - return dict; } - private static bool _dllsAreLoaded = false; - private static readonly object _dllLoadSync = new object(); + return dict; + } + + private static bool _dllsAreLoaded = false; + private static readonly object _dllLoadSync = new object(); - private static void LoadLocalDlls() + private static void LoadLocalDlls() + { + lock (_dllLoadSync) { - lock (_dllLoadSync) + // check again in case the load happened while this thread was waiting for the lock + if (_dllsAreLoaded) + return; + + try { - // check again in case the load happened while this thread was waiting for the lock - if (_dllsAreLoaded) + var assemblyLocation = Assembly.GetExecutingAssembly().Location; + if (String.IsNullOrWhiteSpace(assemblyLocation)) return; - try - { - var assemblyLocation = Assembly.GetExecutingAssembly().Location; - if (String.IsNullOrWhiteSpace(assemblyLocation)) - return; - - var directory = Path.GetDirectoryName(assemblyLocation); - if (String.IsNullOrWhiteSpace(directory)) - return; - - var dlls = Directory.GetFiles(directory, "QuickFix.*.dll"); - foreach (var path in dlls) - Assembly.LoadFrom(path); - - _dllsAreLoaded = true; - } - catch (Exception ex) - { - // TODO: can we log this properly instead of Console write? - Console.Error.WriteLine("Found quickfix.*.dll dlls but failed to load them, " + ex); - } - } - } + var directory = Path.GetDirectoryName(assemblyLocation); + if (String.IsNullOrWhiteSpace(directory)) + return; - private static ICollection GetMessageFactories(IEnumerable assemblies) - { - var factoryTypes = assemblies - .SelectMany(assembly => assembly.GetExportedTypes()) - .Where(IsMessageFactory) - .ToList(); - var factories = new List(); - foreach (var factoryType in factoryTypes) + var dlls = Directory.GetFiles(directory, "QuickFix.*.dll"); + foreach (var path in dlls) + Assembly.LoadFrom(path); + + _dllsAreLoaded = true; + } + catch (Exception ex) { - var factory = (IMessageFactory)Activator.CreateInstance(factoryType)!; - factories.Add(factory); + // TODO: can we log this properly instead of Console write? + Console.Error.WriteLine("Found quickfix.*.dll dlls but failed to load them, " + ex); } - - return factories; } + } - private static ICollection GetAppDomainAssemblies() + private static ICollection GetMessageFactories(IEnumerable assemblies) + { + var factoryTypes = assemblies + .SelectMany(assembly => assembly.GetExportedTypes()) + .Where(IsMessageFactory) + .ToList(); + var factories = new List(); + foreach (var factoryType in factoryTypes) { - LoadLocalDlls(); - var assemblies = AppDomain - .CurrentDomain - .GetAssemblies() - .Where(assembly => !assembly.IsDynamic && assembly.GetName().Name!.StartsWith("QuickFix", StringComparison.Ordinal)) - .ToList(); - return assemblies; + var factory = (IMessageFactory)Activator.CreateInstance(factoryType)!; + factories.Add(factory); } - private static bool IsMessageFactory(Type type) - { - return type != typeof(DefaultMessageFactory) && - type.IsClass && - !type.IsAbstract && - typeof(IMessageFactory).IsAssignableFrom(type) && - type.GetConstructor(Type.EmptyTypes) != null; - } + return factories; + } - #endregion + private static ICollection GetAppDomainAssemblies() + { + LoadLocalDlls(); + var assemblies = AppDomain + .CurrentDomain + .GetAssemblies() + .Where(assembly => !assembly.IsDynamic && assembly.GetName().Name!.StartsWith("QuickFix", StringComparison.Ordinal)) + .ToList(); + return assemblies; } + + private static bool IsMessageFactory(Type type) + { + return type != typeof(DefaultMessageFactory) && + type.IsClass && + !type.IsAbstract && + typeof(IMessageFactory).IsAssignableFrom(type) && + type.GetConstructor(Type.EmptyTypes) != null; + } + + #endregion } diff --git a/QuickFIXn/Exceptions.cs b/QuickFIXn/Exceptions.cs index 629eb8675..ad20754c3 100755 --- a/QuickFIXn/Exceptions.cs +++ b/QuickFIXn/Exceptions.cs @@ -1,300 +1,299 @@ using System; -namespace QuickFix +namespace QuickFix; + +public class QuickFIXException : System.Exception { - public class QuickFIXException : System.Exception - { - public QuickFIXException() - : base() - { } + public QuickFIXException() + : base() + { } - public QuickFIXException(string msg) - : base(msg) - { } + public QuickFIXException(string msg) + : base(msg) + { } - public QuickFIXException(string msg, System.Exception innerException) - : base(msg, innerException) - { } - } + public QuickFIXException(string msg, System.Exception innerException) + : base(msg, innerException) + { } +} - /// - /// Application is not configured correctly - /// - public class ConfigError : QuickFIXException - { - public ConfigError(string msg) - : base("Configuration failed: " + msg) - { } +/// +/// Application is not configured correctly +/// +public class ConfigError : QuickFIXException +{ + public ConfigError(string msg) + : base("Configuration failed: " + msg) + { } - public ConfigError(string msg, System.Exception innerException) - : base("Configuration failed: " + msg, innerException) - { } - } + public ConfigError(string msg, System.Exception innerException) + : base("Configuration failed: " + msg, innerException) + { } +} - /// - /// Unable to convert field into its native format - /// - public class FieldConvertError : QuickFIXException - { - public FieldConvertError(string msg) - : base("Could not convert field: " + msg) - { } +/// +/// Unable to convert field into its native format +/// +public class FieldConvertError : QuickFIXException +{ + public FieldConvertError(string msg) + : base("Could not convert field: " + msg) + { } - public FieldConvertError(string msg, System.Exception innerException) - : base("Could not convert field: " + msg, innerException) - { } - } - - /// - /// Session cannot be found for specified action - /// - public class SessionNotFound : QuickFIXException - { - public SessionNotFound(string msg) - : base("Session Not Found: " + msg) - { } + public FieldConvertError(string msg, System.Exception innerException) + : base("Could not convert field: " + msg, innerException) + { } +} - public SessionNotFound(SessionID sessionID) - : base("Session '" + sessionID + "' Not Found") - { } +/// +/// Session cannot be found for specified action +/// +public class SessionNotFound : QuickFIXException +{ + public SessionNotFound(string msg) + : base("Session Not Found: " + msg) + { } - public SessionNotFound(SessionID sessionID, string msg) - : base("Session '" + sessionID + "' Not Found: " + msg) - { } - } + public SessionNotFound(SessionID sessionID) + : base("Session '" + sessionID + "' Not Found") + { } - /// - /// Version of FIX is not supported. In practice, this means the BeginString is somehow wrong. - /// - public class UnsupportedVersion : QuickFIXException - { - public UnsupportedVersion(string beginString) - : base("Incorrect BeginString (" + beginString + ")") - { } + public SessionNotFound(SessionID sessionID, string msg) + : base("Session '" + sessionID + "' Not Found: " + msg) + { } +} - public UnsupportedVersion(string beginString, System.Exception innerException) - : base("Incorrect BeginString (" + beginString + ")", innerException) - { } - } +/// +/// Version of FIX is not supported. In practice, this means the BeginString is somehow wrong. +/// +public class UnsupportedVersion : QuickFIXException +{ + public UnsupportedVersion(string beginString) + : base("Incorrect BeginString (" + beginString + ")") + { } - /// - /// Message type is not supported by application - /// - public class UnsupportedMessageType : QuickFIXException - { - public UnsupportedMessageType() - : base() - { } - } + public UnsupportedVersion(string beginString, System.Exception innerException) + : base("Incorrect BeginString (" + beginString + ")", innerException) + { } +} - /// - /// Not a recognizable message - /// - [System.Serializable] - public class InvalidMessage : QuickFIXException - { - public InvalidMessage() - : base("Invalid message") - { } +/// +/// Message type is not supported by application +/// +public class UnsupportedMessageType : QuickFIXException +{ + public UnsupportedMessageType() + : base() + { } +} - public InvalidMessage(string msg) - : base("Invalid message: " + msg) - { } +/// +/// Not a recognizable message +/// +[System.Serializable] +public class InvalidMessage : QuickFIXException +{ + public InvalidMessage() + : base("Invalid message") + { } - public InvalidMessage(string msg, System.Exception innerException) - : base("Invalid message: " + msg, innerException) - { } - } + public InvalidMessage(string msg) + : base("Invalid message: " + msg) + { } - /// - /// Socket connection was reset by peer - /// - public class ConnectionResetByPeerException : QuickFIXException - { - public ConnectionResetByPeerException() - : base("Connection reset by peer") - { } + public InvalidMessage(string msg, System.Exception innerException) + : base("Invalid message: " + msg, innerException) + { } +} - public ConnectionResetByPeerException(System.Exception innerException) - : base("Connection reset by peer", innerException) - { } - } +/// +/// Socket connection was reset by peer +/// +public class ConnectionResetByPeerException : QuickFIXException +{ + public ConnectionResetByPeerException() + : base("Connection reset by peer") + { } - public class ConnectionShutdownRequestedException : QuickFIXException - { - public ConnectionShutdownRequestedException() - : base("Connection shutdown requested") - { } + public ConnectionResetByPeerException(System.Exception innerException) + : base("Connection reset by peer", innerException) + { } +} - public ConnectionShutdownRequestedException(System.Exception innerException) - : base("Connection shutdown requested", innerException) - { } - } +public class ConnectionShutdownRequestedException : QuickFIXException +{ + public ConnectionShutdownRequestedException() + : base("Connection shutdown requested") + { } - public class MessageParseError : QuickFIXException - { - public MessageParseError() - : base("Could not parse message") - { } + public ConnectionShutdownRequestedException(System.Exception innerException) + : base("Connection shutdown requested", innerException) + { } +} - public MessageParseError(string msg) - : base("Could not parse message: " + msg) - { } +public class MessageParseError : QuickFIXException +{ + public MessageParseError() + : base("Could not parse message") + { } - public MessageParseError(string msg, System.Exception innerException) - : base("Could not parse message: " + msg, innerException) - { } - } + public MessageParseError(string msg) + : base("Could not parse message: " + msg) + { } - /// - /// Thrown in Application.ToApp callback to indicate that app should abort sending the message - /// - public class DoNotSend : QuickFIXException - { - public DoNotSend() - : base() - { } - } + public MessageParseError(string msg, System.Exception innerException) + : base("Could not parse message: " + msg, innerException) + { } +} - /// - /// Thrown in Application.FromAdmin callback to indicate that app should reject logon attempt - /// - public class RejectLogon : QuickFIXException - { - public RejectLogon(string msg) - : base("Rejected Logon Attempt: " + msg) - { } +/// +/// Thrown in Application.ToApp callback to indicate that app should abort sending the message +/// +public class DoNotSend : QuickFIXException +{ + public DoNotSend() + : base() + { } +} - } +/// +/// Thrown in Application.FromAdmin callback to indicate that app should reject logon attempt +/// +public class RejectLogon : QuickFIXException +{ + public RejectLogon(string msg) + : base("Rejected Logon Attempt: " + msg) + { } - #region Tag Exceptions +} - /// - /// Base class for tag-related errors - /// - public abstract class TagException : QuickFIXException - { - protected int _field; - - public int Field { get { return _field; } } - public FixValues.SessionRejectReason sessionRejectReason; - - public TagException(string msg, int field) - : base(msg) - { - this._field = field; - this.sessionRejectReason = new QuickFix.FixValues.SessionRejectReason(FixValues.SessionRejectReason.OTHER.Value, msg); - } - - public TagException(int field, FixValues.SessionRejectReason reason) - : base(reason.Description) - { - this._field = field; - this.sessionRejectReason = reason; - } - - public TagException(int field, FixValues.SessionRejectReason reason, System.Exception innerException) - : base(reason.Description, innerException) - { - this._field = field; - this.sessionRejectReason = reason; - } - } - /// - /// Tag is not in the correct order - /// - public class TagOutOfOrder : TagException - { - public TagOutOfOrder(int field) : base(field, FixValues.SessionRejectReason.TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER) { } - } - /// - /// Tag number does not exist in specification - /// - public class InvalidTagNumber : TagException - { - public InvalidTagNumber(int field) : base(field, FixValues.SessionRejectReason.INVALID_TAG_NUMBER) { } - } - /// - /// Required field is not in message - /// - public class RequiredTagMissing : TagException - { - public RequiredTagMissing(int field) : base(field, FixValues.SessionRejectReason.REQUIRED_TAG_MISSING) { } - } - /// - /// Field does not belong to message - /// - public class TagNotDefinedForMessage : TagException - { - public string msgType; +#region Tag Exceptions - public TagNotDefinedForMessage(int field, string msgType) : base(field, FixValues.SessionRejectReason.TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE) - { - this.msgType = msgType; - } - } - /// - /// Field exists in message without a value - /// - public class NoTagValue : TagException - { - public NoTagValue(int field) : base(field, FixValues.SessionRejectReason.TAG_SPECIFIED_WITHOUT_A_VALUE) { } - } - /// - /// Field has a value that is out of range - /// - public class IncorrectTagValue : TagException - { - public IncorrectTagValue(int field) : base(field, FixValues.SessionRejectReason.VALUE_IS_INCORRECT) { } - } - /// - /// Repeated tag not part of repeating group - /// - public class RepeatedTag : TagException - { - public RepeatedTag(int field) : base(field, FixValues.SessionRejectReason.TAG_APPEARS_MORE_THAN_ONCE) { } - } - /// - /// Field has a badly formatted value - /// - public class IncorrectDataFormat : TagException - { - public IncorrectDataFormat(int field, System.Exception innerException) - : base(field, FixValues.SessionRejectReason.INCORRECT_DATA_FORMAT_FOR_VALUE, innerException) - { } - } +/// +/// Base class for tag-related errors +/// +public abstract class TagException : QuickFIXException +{ + protected int _field; - public class InvalidMessageType : TagException - { - public InvalidMessageType() - : base(QuickFix.Fields.Tags.MsgType, FixValues.SessionRejectReason.INVALID_MSGTYPE) - { } + public int Field { get { return _field; } } + public FixValues.SessionRejectReason sessionRejectReason; + public TagException(string msg, int field) + : base(msg) + { + this._field = field; + this.sessionRejectReason = new QuickFix.FixValues.SessionRejectReason(FixValues.SessionRejectReason.OTHER.Value, msg); } - public class RepeatingGroupCountMismatch : TagException + public TagException(int field, FixValues.SessionRejectReason reason) + : base(reason.Description) { - public RepeatingGroupCountMismatch(int tag) - :base(tag, FixValues.SessionRejectReason.INCORRECT_NUM_IN_GROUP_COUNT_FOR_REPEATING_GROUP) - {} + this._field = field; + this.sessionRejectReason = reason; } - /// - /// For when a received message has a group that doesn't start its entries with the delimiter tag - /// - public class GroupDelimiterTagException : TagException + public TagException(int field, FixValues.SessionRejectReason reason, System.Exception innerException) + : base(reason.Description, innerException) { - public GroupDelimiterTagException(int counterTag, int delimiterTag) - : base(string.Format("Group {0}'s first entry does not start with delimiter {1}", counterTag, delimiterTag), counterTag) - { } + this._field = field; + this.sessionRejectReason = reason; } +} +/// +/// Tag is not in the correct order +/// +public class TagOutOfOrder : TagException +{ + public TagOutOfOrder(int field) : base(field, FixValues.SessionRejectReason.TAG_SPECIFIED_OUT_OF_REQUIRED_ORDER) { } +} +/// +/// Tag number does not exist in specification +/// +public class InvalidTagNumber : TagException +{ + public InvalidTagNumber(int field) : base(field, FixValues.SessionRejectReason.INVALID_TAG_NUMBER) { } +} +/// +/// Required field is not in message +/// +public class RequiredTagMissing : TagException +{ + public RequiredTagMissing(int field) : base(field, FixValues.SessionRejectReason.REQUIRED_TAG_MISSING) { } +} +/// +/// Field does not belong to message +/// +public class TagNotDefinedForMessage : TagException +{ + public string msgType; - public class RepeatedTagWithoutGroupDelimiterTagException : TagException + public TagNotDefinedForMessage(int field, string msgType) : base(field, FixValues.SessionRejectReason.TAG_NOT_DEFINED_FOR_THIS_MESSAGE_TYPE) { - public RepeatedTagWithoutGroupDelimiterTagException(int counterTag, int troubleTag) - : base(string.Format("Group {0} contains a repeat occurrence of tag {1} in a single group, which is illegal.", counterTag, troubleTag), troubleTag) - { } + this.msgType = msgType; } +} +/// +/// Field exists in message without a value +/// +public class NoTagValue : TagException +{ + public NoTagValue(int field) : base(field, FixValues.SessionRejectReason.TAG_SPECIFIED_WITHOUT_A_VALUE) { } +} +/// +/// Field has a value that is out of range +/// +public class IncorrectTagValue : TagException +{ + public IncorrectTagValue(int field) : base(field, FixValues.SessionRejectReason.VALUE_IS_INCORRECT) { } +} +/// +/// Repeated tag not part of repeating group +/// +public class RepeatedTag : TagException +{ + public RepeatedTag(int field) : base(field, FixValues.SessionRejectReason.TAG_APPEARS_MORE_THAN_ONCE) { } +} +/// +/// Field has a badly formatted value +/// +public class IncorrectDataFormat : TagException +{ + public IncorrectDataFormat(int field, System.Exception innerException) + : base(field, FixValues.SessionRejectReason.INCORRECT_DATA_FORMAT_FOR_VALUE, innerException) + { } +} - #endregion +public class InvalidMessageType : TagException +{ + public InvalidMessageType() + : base(QuickFix.Fields.Tags.MsgType, FixValues.SessionRejectReason.INVALID_MSGTYPE) + { } + +} + +public class RepeatingGroupCountMismatch : TagException +{ + public RepeatingGroupCountMismatch(int tag) + :base(tag, FixValues.SessionRejectReason.INCORRECT_NUM_IN_GROUP_COUNT_FOR_REPEATING_GROUP) + {} +} + +/// +/// For when a received message has a group that doesn't start its entries with the delimiter tag +/// +public class GroupDelimiterTagException : TagException +{ + public GroupDelimiterTagException(int counterTag, int delimiterTag) + : base(string.Format("Group {0}'s first entry does not start with delimiter {1}", counterTag, delimiterTag), counterTag) + { } +} + +public class RepeatedTagWithoutGroupDelimiterTagException : TagException +{ + public RepeatedTagWithoutGroupDelimiterTagException(int counterTag, int troubleTag) + : base(string.Format("Group {0} contains a repeat occurrence of tag {1} in a single group, which is illegal.", counterTag, troubleTag), troubleTag) + { } } + +#endregion diff --git a/QuickFIXn/Fields/Converters/AsciiConverter.cs b/QuickFIXn/Fields/Converters/AsciiConverter.cs index e77df7674..1f7206ae8 100644 --- a/QuickFIXn/Fields/Converters/AsciiConverter.cs +++ b/QuickFIXn/Fields/Converters/AsciiConverter.cs @@ -1,29 +1,28 @@  -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +/// +/// convert Int64 to/from string +/// +public static class AsciiValidator { + public const int ASCII_ZERO = 48; + public const int ASCII_NINE = 57; + public const int ASCII_MINUS = 45; + + /// TODO can we use NumberFormatInfo or NumberStyles to avoid this bit of ASCII hackery? /// - /// convert Int64 to/from string + /// Validates that a string looks like a number (for use before conversion to an int, ulong, etc.). /// - public static class AsciiValidator + /// + /// + public static void Validate(string i) { - public const int ASCII_ZERO = 48; - public const int ASCII_NINE = 57; - public const int ASCII_MINUS = 45; - - /// TODO can we use NumberFormatInfo or NumberStyles to avoid this bit of ASCII hackery? - /// - /// Validates that a string looks like a number (for use before conversion to an int, ulong, etc.). - /// - /// - /// - public static void Validate(string i) - { - if (i is null || i.Length < 1) - throw new FieldConvertError("The argument string cannot be null or empty"); - int asciiValOfFirstChar = System.Convert.ToInt32(i[0]); - if (asciiValOfFirstChar < ASCII_ZERO || asciiValOfFirstChar > ASCII_NINE) - if (asciiValOfFirstChar != ASCII_MINUS) - throw new FieldConvertError("Could not convert string to int (" + i + "): The first character must be a digit or a minus sign"); - } + if (string.IsNullOrEmpty(i)) + throw new FieldConvertError("The argument string cannot be null or empty"); + int asciiValOfFirstChar = System.Convert.ToInt32(i[0]); + if (asciiValOfFirstChar < ASCII_ZERO || asciiValOfFirstChar > ASCII_NINE) + if (asciiValOfFirstChar != ASCII_MINUS) + throw new FieldConvertError($"Could not convert string to int ({i}): The first character must be a digit or a minus sign"); } } diff --git a/QuickFIXn/Fields/Converters/BoolConverter.cs b/QuickFIXn/Fields/Converters/BoolConverter.cs index b476f18de..3965ab046 100644 --- a/QuickFIXn/Fields/Converters/BoolConverter.cs +++ b/QuickFIXn/Fields/Converters/BoolConverter.cs @@ -1,39 +1,35 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +/// +/// Converts Boolean to/from string +/// +public static class BoolConverter { /// - /// Converts Boolean to/from string + /// Converts boolean to string /// - public static class BoolConverter + /// + /// "Y" for true, "N" for false + public static string Convert(bool b) { - /// - /// Converts boolean to string - /// - /// - /// "Y" for true, "N" for false - public static string Convert(Boolean b) - { - return b ? "Y" : "N"; - } + return b ? "Y" : "N"; + } - /// - /// converts string to boolean - /// - /// - /// true for "Y", false for "N" - /// - public static Boolean Convert(string boolstr) + /// + /// converts string to boolean + /// + /// + /// true for "Y", false for "N" + /// + public static bool Convert(string boolstr) + { + switch (boolstr) { - switch (boolstr) - { - case "Y": return true; - case "N": return false; - default: throw new FieldConvertError("Cannot convert string to boolean"); - } + case "Y": return true; + case "N": return false; + default: throw new FieldConvertError("Cannot convert string to boolean"); } } } diff --git a/QuickFIXn/Fields/Converters/CharConverter.cs b/QuickFIXn/Fields/Converters/CharConverter.cs index 99ea89ff7..cbd0dac73 100644 --- a/QuickFIXn/Fields/Converters/CharConverter.cs +++ b/QuickFIXn/Fields/Converters/CharConverter.cs @@ -1,32 +1,28 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +/// +/// Converts char to/from string +/// +public static class CharConverter { /// - /// Converts char to/from string + /// Convert string to char /// - public static class CharConverter + /// + public static char Convert(string c) { - /// - /// Convert string to char - /// - /// - public static char Convert(string c) - { - if (c.Length != 1) - throw new FieldConvertError("could not convert string to char, str=" + c); - return c[0]; - } + if (c.Length != 1) + throw new FieldConvertError($"could not convert string to char, str={c}"); + return c[0]; + } - /// - /// Converts char to string - /// - public static string Convert(char c) - { - return c.ToString(); - } + /// + /// Converts char to string + /// + public static string Convert(char c) + { + return c.ToString(); } } diff --git a/QuickFIXn/Fields/Converters/CheckSumConverter.cs b/QuickFIXn/Fields/Converters/CheckSumConverter.cs index 19b733aab..537d27776 100755 --- a/QuickFIXn/Fields/Converters/CheckSumConverter.cs +++ b/QuickFIXn/Fields/Converters/CheckSumConverter.cs @@ -1,25 +1,24 @@ -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +public static class CheckSumConverter { - public static class CheckSumConverter + /// + /// Convert input string to int + /// + /// + /// + public static int Convert(string i) { - /// - /// Convert input string to int - /// - /// - /// - public static int Convert(string i) - { - return IntConverter.Convert(i); - } + return IntConverter.Convert(i); + } - /// - /// Convert input int to 3-character string - /// - /// - /// - public static string Convert(int i) - { - return i.ToString("000"); - } + /// + /// Convert input int to 3-character string + /// + /// + /// + public static string Convert(int i) + { + return i.ToString("000"); } } diff --git a/QuickFIXn/Fields/Converters/DecimalConverter.cs b/QuickFIXn/Fields/Converters/DecimalConverter.cs index 749fa180f..9c9a11d01 100644 --- a/QuickFIXn/Fields/Converters/DecimalConverter.cs +++ b/QuickFIXn/Fields/Converters/DecimalConverter.cs @@ -1,54 +1,49 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +/// +/// convert Decimal to/from string +/// +public static class DecimalConverter { + private const int ASCII_DECIMALPOINT = 46; + /// - /// convert Decimal to/from string + /// convert string to decimal /// - public static class DecimalConverter + /// + public static decimal Convert(string d) { - private const int ASCII_DECIMALPOINT = 46; - - /// - /// convert string to decimal - /// - /// - public static Decimal Convert(string d) + try { - try - { - if((null == d) || (d.Length < 1)) - throw new FieldConvertError("The argument string cannot be null or empty"); - int asciiValOfFirstChar = System.Convert.ToInt32(d[0]); - if ((asciiValOfFirstChar < AsciiValidator.ASCII_ZERO) || (asciiValOfFirstChar > AsciiValidator.ASCII_NINE)) - if (asciiValOfFirstChar != AsciiValidator.ASCII_MINUS && asciiValOfFirstChar != ASCII_DECIMALPOINT) - throw new FieldConvertError("Could not convert string to decimal (" + d + "): The first character must be a digit, decimal point, or minus sign"); - return decimal.Parse(d, System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture); - } - catch (System.OverflowException e) - { - throw new FieldConvertError("Could not convert string to decimal (" + d + ")", e); - } - catch (System.FormatException e) - { - throw new FieldConvertError("Could not convert string to decimal (" + d + ")", e); - } - catch (System.ArgumentNullException e) - { - throw new FieldConvertError("Could not convert string to decimal (" + d + ")", e); - } + if((null == d) || (d.Length < 1)) + throw new FieldConvertError("The argument string cannot be null or empty"); + int asciiValOfFirstChar = System.Convert.ToInt32(d[0]); + if ((asciiValOfFirstChar < AsciiValidator.ASCII_ZERO) || (asciiValOfFirstChar > AsciiValidator.ASCII_NINE)) + if (asciiValOfFirstChar != AsciiValidator.ASCII_MINUS && asciiValOfFirstChar != ASCII_DECIMALPOINT) + throw new FieldConvertError($"Could not convert string to decimal ({d}): The first character must be a digit, decimal point, or minus sign"); + return decimal.Parse(d, System.Globalization.NumberStyles.AllowExponent | System.Globalization.NumberStyles.AllowLeadingSign | System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture); } - - /// - /// convert Decimal to string - /// - public static string Convert(Decimal d) + catch (System.OverflowException e) + { + throw new FieldConvertError($"Could not convert string to decimal ({d})", e); + } + catch (System.FormatException e) { - return d.ToString( System.Globalization.CultureInfo.InvariantCulture ); + throw new FieldConvertError($"Could not convert string to decimal ({d})", e); } + catch (System.ArgumentNullException e) + { + throw new FieldConvertError($"Could not convert string to decimal ({d})", e); + } + } + /// + /// convert Decimal to string + /// + public static string Convert(decimal d) + { + return d.ToString( System.Globalization.CultureInfo.InvariantCulture ); } } diff --git a/QuickFIXn/Fields/Converters/IntConverter.cs b/QuickFIXn/Fields/Converters/IntConverter.cs index bb38bdb42..0ac809874 100644 --- a/QuickFIXn/Fields/Converters/IntConverter.cs +++ b/QuickFIXn/Fields/Converters/IntConverter.cs @@ -1,39 +1,38 @@  -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +/// +/// convert Int64 to/from string +/// +public static class IntConverter { /// - /// convert Int64 to/from string + /// Converts string to int. /// - public static class IntConverter + /// + /// + public static int Convert(string i) { - /// - /// Converts string to int. - /// - /// - /// - public static int Convert(string i) + try { - try - { - AsciiValidator.Validate(i); - return System.Convert.ToInt32(i); - } - catch (System.FormatException e) - { - throw new FieldConvertError("Could not convert string to int (" + i + ")", e); - } - catch (System.OverflowException e) - { - throw new FieldConvertError("Could not convert string to int (" + i + ")", e); - } + AsciiValidator.Validate(i); + return System.Convert.ToInt32(i); } - - /// - /// convert integer to string - /// - public static string Convert(System.Int64 i) + catch (System.FormatException e) { - return i.ToString(); + throw new FieldConvertError($"Could not convert string to int ({i})", e); } + catch (System.OverflowException e) + { + throw new FieldConvertError($"Could not convert string to int ({i})", e); + } + } + + /// + /// convert integer to string + /// + public static string Convert(long i) + { + return i.ToString(); } } diff --git a/QuickFIXn/Fields/Converters/TimeStampPrecision.cs b/QuickFIXn/Fields/Converters/TimeStampPrecision.cs index fa41b1f0f..c551f6707 100644 --- a/QuickFIXn/Fields/Converters/TimeStampPrecision.cs +++ b/QuickFIXn/Fields/Converters/TimeStampPrecision.cs @@ -1,11 +1,10 @@  -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +public enum TimeStampPrecision { - public enum TimeStampPrecision - { - Second, - Millisecond, - Microsecond, - Nanosecond - } + Second, + Millisecond, + Microsecond, + Nanosecond } diff --git a/QuickFIXn/Fields/Converters/ULongConverter.cs b/QuickFIXn/Fields/Converters/ULongConverter.cs index efc4a7f42..838985ab7 100644 --- a/QuickFIXn/Fields/Converters/ULongConverter.cs +++ b/QuickFIXn/Fields/Converters/ULongConverter.cs @@ -1,39 +1,38 @@  -namespace QuickFix.Fields.Converters +namespace QuickFix.Fields.Converters; + +/// +/// convert UInt64 to/from string +/// +public static class ULongConverter { /// - /// convert UInt64 to/from string + /// Converts string to ulong. /// - public static class ULongConverter + /// + /// + public static ulong Convert(string i) { - /// - /// Converts string to ulong. - /// - /// - /// - public static ulong Convert(string i) + try { - try - { - AsciiValidator.Validate(i); - return System.Convert.ToUInt64(i); - } - catch (System.FormatException e) - { - throw new FieldConvertError("Could not convert string to ulong (" + i + ")", e); - } - catch (System.OverflowException e) - { - throw new FieldConvertError("Could not convert string to ulong (" + i + ")", e); - } + AsciiValidator.Validate(i); + return System.Convert.ToUInt64(i); } - - /// - /// convert ulong to string - /// - public static string Convert(System.UInt64 i) + catch (System.FormatException e) { - return i.ToString(); + throw new FieldConvertError($"Could not convert string to ulong ({i})", e); } + catch (System.OverflowException e) + { + throw new FieldConvertError($"Could not convert string to ulong ({i})", e); + } + } + + /// + /// convert ulong to string + /// + public static string Convert(ulong i) + { + return i.ToString(); } } diff --git a/QuickFIXn/Fields/DateOnlyField.cs b/QuickFIXn/Fields/DateOnlyField.cs new file mode 100644 index 000000000..8d060f936 --- /dev/null +++ b/QuickFIXn/Fields/DateOnlyField.cs @@ -0,0 +1,24 @@ +using System; +using QuickFix.Fields.Converters; + +namespace QuickFix.Fields; + +public class DateOnlyField : DateTimeField +{ + public DateOnlyField(int tag) + : base(tag, new DateTime()) { } + + public DateOnlyField(int tag, DateTime dt) + : base(tag, dt) { } + + public DateOnlyField(int tag, DateTime dt, bool showMilliseconds) + : base(tag, dt, showMilliseconds) { } + + public DateOnlyField(int tag, DateTime dt, TimeStampPrecision timeFormatPrecision) + : base(tag, dt, timeFormatPrecision) { } + + protected override string MakeString() + { + return DateTimeConverter.ToFIXDateOnly(Value); + } +} diff --git a/QuickFIXn/Fields/DateTimeField.cs b/QuickFIXn/Fields/DateTimeField.cs index 15ae59b18..4b582c7db 100644 --- a/QuickFIXn/Fields/DateTimeField.cs +++ b/QuickFIXn/Fields/DateTimeField.cs @@ -1,69 +1,28 @@ using System; using QuickFix.Fields.Converters; -namespace QuickFix.Fields -{ - public class DateTimeField : FieldBase - { - protected readonly TimeStampPrecision timePrecision = TimeStampPrecision.Millisecond; - public DateTimeField(int tag) - : base(tag, new DateTime()) {} +namespace QuickFix.Fields; - public DateTimeField(int tag, DateTime dt) - : base(tag, dt) {} +public class DateTimeField : FieldBase +{ + protected readonly TimeStampPrecision TimePrecision = TimeStampPrecision.Millisecond; + public DateTimeField(int tag) + : base(tag, new DateTime()) {} - public DateTimeField(int tag, DateTime dt, bool showMilliseconds) - : this(tag, dt, showMilliseconds ? TimeStampPrecision.Millisecond : TimeStampPrecision.Second ) { } + public DateTimeField(int tag, DateTime dt) + : base(tag, dt) {} - public DateTimeField(int tag, DateTime dt, TimeStampPrecision timeFormatPrecision) - : base(tag, dt ) - { - timePrecision = timeFormatPrecision; - } + public DateTimeField(int tag, DateTime dt, bool showMilliseconds) + : this(tag, dt, showMilliseconds ? TimeStampPrecision.Millisecond : TimeStampPrecision.Second ) { } - protected override string MakeString() - { - return Converters.DateTimeConverter.ToFIX(Value, timePrecision); - } - } - - public class DateOnlyField : DateTimeField + public DateTimeField(int tag, DateTime dt, TimeStampPrecision timeFormatPrecision) + : base(tag, dt ) { - public DateOnlyField(int tag) - : base(tag, new DateTime()) { } - - public DateOnlyField(int tag, DateTime dt) - : base(tag, dt) { } - - public DateOnlyField(int tag, DateTime dt, bool showMilliseconds) - : base(tag, dt, showMilliseconds) { } - - public DateOnlyField(int tag, DateTime dt, TimeStampPrecision timeFormatPrecision) - : base(tag, dt, timeFormatPrecision) { } - - protected override string MakeString() - { - return Converters.DateTimeConverter.ToFIXDateOnly(Value); - } + TimePrecision = timeFormatPrecision; } - public class TimeOnlyField : DateTimeField + protected override string MakeString() { - public TimeOnlyField(int tag) - : base(tag, new DateTime()) { } - - public TimeOnlyField(int tag, DateTime dt) - : base(tag, dt) { } - - public TimeOnlyField(int tag, DateTime dt, bool showMilliseconds) - : base(tag, dt, showMilliseconds) { } - - public TimeOnlyField(int tag, DateTime dt, TimeStampPrecision timeFormatPrecision) - : base(tag, dt, timeFormatPrecision) { } - - protected override string MakeString() - { - return Converters.DateTimeConverter.ToFIXTimeOnly(Value, base.timePrecision); - } + return DateTimeConverter.ToFIX(Value, TimePrecision); } } diff --git a/QuickFIXn/Fields/DecimalField.cs b/QuickFIXn/Fields/DecimalField.cs index 574042239..3e4505bb8 100644 --- a/QuickFIXn/Fields/DecimalField.cs +++ b/QuickFIXn/Fields/DecimalField.cs @@ -1,23 +1,20 @@ using System; -using System.Collections.Generic; -using System.Text; -namespace QuickFix.Fields +namespace QuickFix.Fields; + +/// +/// A decimal FIX field +/// +public class DecimalField : FieldBase { - /// - /// A decimal FIX field - /// - public class DecimalField : FieldBase - { - public DecimalField(int tag) - : base(tag, new Decimal(0.0)) {} + public DecimalField(int tag) + : base(tag, new decimal(0.0)) {} - public DecimalField(int tag, Decimal val) - : base(tag, val) { } + public DecimalField(int tag, decimal val) + : base(tag, val) { } - protected override string MakeString() - { - return Converters.DecimalConverter.Convert(Value); - } + protected override string MakeString() + { + return Converters.DecimalConverter.Convert(Value); } } diff --git a/QuickFIXn/Fields/IField.cs b/QuickFIXn/Fields/IField.cs index 5320486e4..eb2f8b3cd 100644 --- a/QuickFIXn/Fields/IField.cs +++ b/QuickFIXn/Fields/IField.cs @@ -1,39 +1,38 @@ using System; -namespace QuickFix.Fields +namespace QuickFix.Fields; + +/// +/// Interface for all field classes +/// +public interface IField { + public int Tag { get; set; } + /// - /// Interface for all field classes + /// returns full fix string: tag=val /// - public interface IField - { - public int Tag { get; set; } - - /// - /// returns full fix string: tag=val - /// - public string ToStringField(); + public string ToStringField(); - /// - /// returns field value (not tag) formatted for FIX - /// - public string ToString(); + /// + /// returns field value (not tag) formatted for FIX + /// + public string ToString(); - /// - /// length of formatted field (including the trailing SOH) e.g. tag=val\001 - /// - public int GetLength(); + /// + /// length of formatted field (including the trailing SOH) e.g. tag=val\001 + /// + public int GetLength(); - /// - /// Sum of bytes; used in calculating checksum - /// - public int GetTotal(); + /// + /// Sum of bytes; used in calculating checksum + /// + public int GetTotal(); - [Obsolete("Use capitalized ToStringField() instead. This function will be removed in 1.16.")] - public string toStringField(); - [Obsolete("Use capitalized GetLength() instead. This function will be removed in 1.16.")] - public int getLength(); - [Obsolete("Use capitalized GetTotal() instead. This function will be removed in 1.16.")] - public int getTotal(); - } + [Obsolete("Use capitalized ToStringField() instead. This function will be removed in 1.16.")] + public string toStringField(); + [Obsolete("Use capitalized GetLength() instead. This function will be removed in 1.16.")] + public int getLength(); + [Obsolete("Use capitalized GetTotal() instead. This function will be removed in 1.16.")] + public int getTotal(); } diff --git a/QuickFIXn/Fields/Limits.cs b/QuickFIXn/Fields/Limits.cs index 12112dba0..ae0b09576 100755 --- a/QuickFIXn/Fields/Limits.cs +++ b/QuickFIXn/Fields/Limits.cs @@ -1,12 +1,11 @@  -namespace QuickFix.Fields +namespace QuickFix.Fields; + +public static class Limits { - public static class Limits - { - public const int NORMAL_MIN = 1; - public const int NORMAL_MAX = 4999; - public const int USER_MIN = 5000; - public const int USER_MAX = 9999; - public const int INTERNAL_MIN = 10000; - } + public const int NORMAL_MIN = 1; + public const int NORMAL_MAX = 4999; + public const int USER_MIN = 5000; + public const int USER_MAX = 9999; + public const int INTERNAL_MIN = 10000; } diff --git a/QuickFIXn/Fields/StringField.cs b/QuickFIXn/Fields/StringField.cs index 7e73025c5..6b495b75d 100644 --- a/QuickFIXn/Fields/StringField.cs +++ b/QuickFIXn/Fields/StringField.cs @@ -1,23 +1,20 @@ using System; -using System.Collections.Generic; -using System.Text; -namespace QuickFix.Fields +namespace QuickFix.Fields; + +/// +/// A string-valued message field +/// +public class StringField : FieldBase { - /// - /// A string-valued message field - /// - public class StringField : FieldBase - { - public StringField(int tag) - : base(tag, "") { } + public StringField(int tag) + : base(tag, "") { } - public StringField(int tag, string str) - : base(tag, str) { } + public StringField(int tag, string str) + : base(tag, str) { } - protected override string MakeString() - { - return Value; - } + protected override string MakeString() + { + return Value; } } diff --git a/QuickFIXn/Fields/TimeOnlyField.cs b/QuickFIXn/Fields/TimeOnlyField.cs new file mode 100644 index 000000000..1f5d2e790 --- /dev/null +++ b/QuickFIXn/Fields/TimeOnlyField.cs @@ -0,0 +1,24 @@ +using System; +using QuickFix.Fields.Converters; + +namespace QuickFix.Fields; + +public class TimeOnlyField : DateTimeField +{ + public TimeOnlyField(int tag) + : base(tag, new DateTime()) { } + + public TimeOnlyField(int tag, DateTime dt) + : base(tag, dt) { } + + public TimeOnlyField(int tag, DateTime dt, bool showMilliseconds) + : base(tag, dt, showMilliseconds) { } + + public TimeOnlyField(int tag, DateTime dt, TimeStampPrecision timeFormatPrecision) + : base(tag, dt, timeFormatPrecision) { } + + protected override string MakeString() + { + return DateTimeConverter.ToFIXTimeOnly(Value, base.TimePrecision); + } +} diff --git a/QuickFIXn/Fields/ULongField.cs b/QuickFIXn/Fields/ULongField.cs index 20b045079..f8121bacf 100644 --- a/QuickFIXn/Fields/ULongField.cs +++ b/QuickFIXn/Fields/ULongField.cs @@ -1,23 +1,20 @@ using System; -using System.Collections.Generic; -using System.Text; -namespace QuickFix.Fields +namespace QuickFix.Fields; + +/// +/// A ulong (System.UInt64) message field +/// +public class ULongField: FieldBase { - /// - /// A ulong (System.UInt64) message field - /// - public class ULongField: FieldBase - { - public ULongField(int tag) - : base(tag, 0L) { } + public ULongField(int tag) + : base(tag, 0L) { } - public ULongField(int tag, ulong val) - : base(tag, val) {} + public ULongField(int tag, ulong val) + : base(tag, val) {} - protected override string MakeString() - { - return Converters.ULongConverter.Convert(Value); - } + protected override string MakeString() + { + return Converters.ULongConverter.Convert(Value); } } diff --git a/QuickFIXn/IAcceptor.cs b/QuickFIXn/IAcceptor.cs index ab91b6486..3c3aa7fd7 100644 --- a/QuickFIXn/IAcceptor.cs +++ b/QuickFIXn/IAcceptor.cs @@ -2,61 +2,60 @@ using System.Net; using System.Collections.Generic; -namespace QuickFix +namespace QuickFix; + +/// +/// Accepts connections from FIX clients and manages the associated sessions. +/// +public interface IAcceptor : IDisposable { /// - /// Accepts connections from FIX clients and manages the associated sessions. - /// - public interface IAcceptor : IDisposable - { - /// - /// Start accepting connections - /// - void Start(); - - /// - /// Close exising connections and stop accepting new ones - /// - void Stop(); - - /// - /// Close exising connections and stop accepting new ones - /// - /// If true, do not wait for existing Sessions to logout - void Stop(bool force); - - /// - /// Check whether any sessions are logged on - /// - /// true if any session is logged on, else false - bool IsLoggedOn { get; } - - /// - /// Get the SessionIDs for the sessions managed by this acceptor. - /// - /// the SessionIDs for the sessions managed by this acceptor - HashSet GetSessionIDs(); - - /// - /// Get accepted socket end points - /// - /// a map of SessionIDs to EndPoints - Dictionary GetAcceptorAddresses(); - - /// - /// Add a new session after acceptor has been started - /// - /// ID of session to be added - /// session settings - /// >true if session added successfully, false if session already exists or is not an acceptor - bool AddSession(SessionID sessionID, QuickFix.SettingsDictionary dict); - - /// - /// Remove an existing session after acceptor has been started - /// - /// ID of session to be removed - /// if true, force disconnection and removal of session even if it has an active connection - /// true if session removed or not already present; false if could not be removed due to an active connection - bool RemoveSession(SessionID sessionID, bool terminateActiveSession); - } + /// Start accepting connections + /// + void Start(); + + /// + /// Close exising connections and stop accepting new ones + /// + void Stop(); + + /// + /// Close exising connections and stop accepting new ones + /// + /// If true, do not wait for existing Sessions to logout + void Stop(bool force); + + /// + /// Check whether any sessions are logged on + /// + /// true if any session is logged on, else false + bool IsLoggedOn { get; } + + /// + /// Get the SessionIDs for the sessions managed by this acceptor. + /// + /// the SessionIDs for the sessions managed by this acceptor + HashSet GetSessionIDs(); + + /// + /// Get accepted socket end points + /// + /// a map of SessionIDs to EndPoints + Dictionary GetAcceptorAddresses(); + + /// + /// Add a new session after acceptor has been started + /// + /// ID of session to be added + /// session settings + /// >true if session added successfully, false if session already exists or is not an acceptor + bool AddSession(SessionID sessionID, QuickFix.SettingsDictionary dict); + + /// + /// Remove an existing session after acceptor has been started + /// + /// ID of session to be removed + /// if true, force disconnection and removal of session even if it has an active connection + /// true if session removed or not already present; false if could not be removed due to an active connection + bool RemoveSession(SessionID sessionID, bool terminateActiveSession); } diff --git a/QuickFIXn/IApplication.cs b/QuickFIXn/IApplication.cs index 3f685e907..1ad52ab68 100644 --- a/QuickFIXn/IApplication.cs +++ b/QuickFIXn/IApplication.cs @@ -1,99 +1,98 @@ -namespace QuickFix +namespace QuickFix; + +/// +/// This is the primary interface for processing session messages. +/// +public interface IApplication { /// - /// This is the primary interface for processing session messages. + /// This callback provides you with a peek at the administrative messages + /// that are being sent from your FIX engine to the counter party. This is + /// normally not useful for an application however it is provided for any + /// logging you may wish to do. You may add fields in an administrative + /// message before it is sent. + /// In some rare cases, it might be useful to throw a DoNotSend exception + /// in this function to suppress sending of the message by the application. /// - public interface IApplication - { - /// - /// This callback provides you with a peek at the administrative messages - /// that are being sent from your FIX engine to the counter party. This is - /// normally not useful for an application however it is provided for any - /// logging you may wish to do. You may add fields in an administrative - /// message before it is sent. - /// In some rare cases, it might be useful to throw a DoNotSend exception - /// in this function to suppress sending of the message by the application. - /// - /// - /// - void ToAdmin(Message message, SessionID sessionID); + /// + /// + void ToAdmin(Message message, SessionID sessionID); - /// - /// This callback notifies you when an administrative message is sent from a - /// counterparty to your FIX engine. This can be useful for doing extra - /// validation on logon messages such as for checking passwords. Throwing a - /// RejectLogon exception will disconnect the counterparty. - /// - /// - /// - /// throw this to reject a login - void FromAdmin(Message message, SessionID sessionID); + /// + /// This callback notifies you when an administrative message is sent from a + /// counterparty to your FIX engine. This can be useful for doing extra + /// validation on logon messages such as for checking passwords. Throwing a + /// RejectLogon exception will disconnect the counterparty. + /// + /// + /// + /// throw this to reject a login + void FromAdmin(Message message, SessionID sessionID); - /// - /// This is a callback for application messages that you are sending to a - /// counterparty. If you throw a DoNotSend exception in this function, the - /// application will not send the message. This is mostly useful if the - /// application has been asked to resend a message such as an order that is - /// no longer relevant for the current market. Messages that are being resent - /// are marked with the PossDupFlag in the header set to true; If a DoNotSend - /// exception is thrown and the flag is set to true, a sequence reset will be - /// sent in place of the message. If it is set to false, the message will - /// simply not be sent. You may add fields before an application message - /// before it is sent out. - /// - /// - /// - /// throw this to abort sending the message - void ToApp(Message message, SessionID sessionID); + /// + /// This is a callback for application messages that you are sending to a + /// counterparty. If you throw a DoNotSend exception in this function, the + /// application will not send the message. This is mostly useful if the + /// application has been asked to resend a message such as an order that is + /// no longer relevant for the current market. Messages that are being resent + /// are marked with the PossDupFlag in the header set to true; If a DoNotSend + /// exception is thrown and the flag is set to true, a sequence reset will be + /// sent in place of the message. If it is set to false, the message will + /// simply not be sent. You may add fields before an application message + /// before it is sent out. + /// + /// + /// + /// throw this to abort sending the message + void ToApp(Message message, SessionID sessionID); - /// - /// This callback receives messages for the application. This is one of the - /// core entry points for your FIX application. Every application level - /// request will come through here. If, for example, your application is a - /// sell-side OMS, this is where you will get your new order requests. If you - /// were a buy side, you would get your execution reports here. If a - /// FieldNotFound exception is thrown, the counterparty will receive a reject - /// indicating a conditionally required field is missing. The Message class - /// will throw this exception when trying to retrieve a missing field, so you - /// will rarely need the throw this explicitly. You can also throw an - /// UnsupportedMessageType exception. This will result in the counterparty - /// getting a business reject informing them your application cannot process - /// those types of messages. An IncorrectTagValue can also be thrown if a - /// field contains a value that is out of range or you do not support. - /// - /// - /// - /// throw this to notify counterparty is missing a required field - /// throw this to notify counterparty we can't process this message - /// throw this to notify counterparty that a field contains an incorrect value - void FromApp(Message message, SessionID sessionID); + /// + /// This callback receives messages for the application. This is one of the + /// core entry points for your FIX application. Every application level + /// request will come through here. If, for example, your application is a + /// sell-side OMS, this is where you will get your new order requests. If you + /// were a buy side, you would get your execution reports here. If a + /// FieldNotFound exception is thrown, the counterparty will receive a reject + /// indicating a conditionally required field is missing. The Message class + /// will throw this exception when trying to retrieve a missing field, so you + /// will rarely need the throw this explicitly. You can also throw an + /// UnsupportedMessageType exception. This will result in the counterparty + /// getting a business reject informing them your application cannot process + /// those types of messages. An IncorrectTagValue can also be thrown if a + /// field contains a value that is out of range or you do not support. + /// + /// + /// + /// throw this to notify counterparty is missing a required field + /// throw this to notify counterparty we can't process this message + /// throw this to notify counterparty that a field contains an incorrect value + void FromApp(Message message, SessionID sessionID); - /// - /// This method is called when quickfix creates a new session. A session - /// comes into and remains in existence for the life of the application. - /// Sessions exist whether or not a counter party is connected to it. As soon - /// as a session is created, you can begin sending messages to it. If no one - /// is logged on, the messages will be sent at the time a connection is - /// established with the counterparty. - /// - /// - void OnCreate(SessionID sessionID); + /// + /// This method is called when quickfix creates a new session. A session + /// comes into and remains in existence for the life of the application. + /// Sessions exist whether or not a counter party is connected to it. As soon + /// as a session is created, you can begin sending messages to it. If no one + /// is logged on, the messages will be sent at the time a connection is + /// established with the counterparty. + /// + /// + void OnCreate(SessionID sessionID); - /// - /// This callback notifies you when an FIX session is no longer online. This - /// could happen during a normal logout exchange or because of a forced - /// termination or a loss of network connection. - /// - /// - void OnLogout(SessionID sessionID); + /// + /// This callback notifies you when an FIX session is no longer online. This + /// could happen during a normal logout exchange or because of a forced + /// termination or a loss of network connection. + /// + /// + void OnLogout(SessionID sessionID); - /// - /// This callback notifies you when a valid logon has been established with a - /// counter party. This is called when a connection has been established and - /// the FIX logon process has completed with both parties exchanging valid - /// logon messages. - /// - /// - void OnLogon(SessionID sessionID); - } + /// + /// This callback notifies you when a valid logon has been established with a + /// counter party. This is called when a connection has been established and + /// the FIX logon process has completed with both parties exchanging valid + /// logon messages. + /// + /// + void OnLogon(SessionID sessionID); } diff --git a/QuickFIXn/IApplicationExt.cs b/QuickFIXn/IApplicationExt.cs index 30ee02f76..34173c879 100644 --- a/QuickFIXn/IApplicationExt.cs +++ b/QuickFIXn/IApplicationExt.cs @@ -1,29 +1,28 @@ using System; -namespace QuickFix +namespace QuickFix; + +/// +/// This is the optional extension interface for processing inbound messages, +/// and facilitates early interception of such messages. 'Early', in this context, +/// means after structure, length and checksum have been validated, but before any +/// further validation has been performed. +/// +/// This interface will not normally be required, and it should be used only with caution: +/// it allows modifications to be made to irregular inbound messages that would otherwise +/// fail validation against the Fix dictionary, an provides an alternative to dictionary +/// customisation as a means of dealing with such messages. +/// +public interface IApplicationExt : IApplication { /// - /// This is the optional extension interface for processing inbound messages, - /// and facilitates early interception of such messages. 'Early', in this context, - /// means after structure, length and checksum have been validated, but before any - /// further validation has been performed. - /// - /// This interface will not normally be required, and it should be used only with caution: - /// it allows modifications to be made to irregular inbound messages that would otherwise - /// fail validation against the Fix dictionary, an provides an alternative to dictionary - /// customisation as a means of dealing with such messages. + /// This callback provides early notification of when an administrative or application + /// message is sent from a counterparty to your FIX engine. + /// This can be useful for doing pre-processing of an inbound message after its structure, + /// checksum and length have been validated, but before + /// any further validation has been performed on it. /// - public interface IApplicationExt : IApplication - { - /// - /// This callback provides early notification of when an administrative or application - /// message is sent from a counterparty to your FIX engine. - /// This can be useful for doing pre-processing of an inbound message after its structure, - /// checksum and length have been validated, but before - /// any further validation has been performed on it. - /// - /// received message - /// session on which message received - void FromEarlyIntercept(Message message, SessionID sessionId); - } + /// received message + /// session on which message received + void FromEarlyIntercept(Message message, SessionID sessionId); } diff --git a/QuickFIXn/IInitiator.cs b/QuickFIXn/IInitiator.cs index 6ad70d3e0..ff082c756 100644 --- a/QuickFIXn/IInitiator.cs +++ b/QuickFIXn/IInitiator.cs @@ -1,61 +1,58 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace QuickFix +namespace QuickFix; + +/// +/// Public interface for initiator. +/// Establishes sessions with FIX servers and manages the associated sessions. +/// The class AbstractInitiator contains a default base implementation. +/// +public interface IInitiator : IDisposable { + bool IsStopped { get; } + + /// + /// Starts a connection with a remote acceptor + /// + void Start(); + + /// + /// Logout existing session and close connection. All open resources are released. + /// + void Stop(); + + /// + /// Stops existing session, optinally waiting for logout completion + /// + /// don't wait for logout before disconnect + void Stop(bool force); + + /// + /// Checks the logged on status of the session + /// + /// true if the session is logged on, false otherwise + bool IsLoggedOn { get; } + + /// + /// Get the SessionIDs for the sessions managed by this initiator. + /// + /// the SessionIDs for the sessions managed by this initiator + HashSet GetSessionIDs(); + + /// + /// Add a new session after initiator has been started + /// + /// ID of session to be added + /// session settings + /// true if session added successfully, false if session already exists or is not an initiator + bool AddSession(SessionID sessionID, SettingsDictionary dict); + /// - /// Public interface for initiator. - /// Establishes sessions with FIX servers and manages the associated sessions. - /// The class AbstractInitiator contains a default base implementation. + /// Remove an existing session after initiator has been started /// - public interface IInitiator : IDisposable - { - bool IsStopped { get; } - - /// - /// Starts a connection with a remote acceptor - /// - void Start(); - - /// - /// Logout existing session and close connection. All open resources are released. - /// - void Stop(); - - /// - /// Stops existing session, optinally waiting for logout completion - /// - /// don't wait for logout before disconnect - void Stop(bool force); - - /// - /// Checks the logged on status of the session - /// - /// true if the session is logged on, false otherwise - bool IsLoggedOn { get; } - - /// - /// Get the SessionIDs for the sessions managed by this initiator. - /// - /// the SessionIDs for the sessions managed by this initiator - HashSet GetSessionIDs(); - - /// - /// Add a new session after initiator has been started - /// - /// ID of session to be added - /// session settings - /// true if session added successfully, false if session already exists or is not an initiator - bool AddSession(SessionID sessionID, SettingsDictionary dict); - - /// - /// Remove an existing session after initiator has been started - /// - /// ID of session to be removed - /// if true, force disconnection and removal of session even if it has an active connection - /// true if session removed or not already present; false if could not be removed due to an active connection - bool RemoveSession(SessionID sessionID, bool terminateActiveSession); - } + /// ID of session to be removed + /// if true, force disconnection and removal of session even if it has an active connection + /// true if session removed or not already present; false if could not be removed due to an active connection + bool RemoveSession(SessionID sessionID, bool terminateActiveSession); } diff --git a/QuickFIXn/IMessageFactory.cs b/QuickFIXn/IMessageFactory.cs index 949041fca..9acb2bcec 100644 --- a/QuickFIXn/IMessageFactory.cs +++ b/QuickFIXn/IMessageFactory.cs @@ -1,45 +1,44 @@ using System.Collections.Generic; -namespace QuickFix +namespace QuickFix; + +/// +/// Used by Session to create a Message of the appropriate type. +/// +public interface IMessageFactory { /// - /// Used by Session to create a Message of the appropriate type. + /// Lists the supported begin strings this factory can create messages and groups for + /// + /// List of supported begin strings + ICollection GetSupportedBeginStrings(); + + /// + /// Creates a message for a specified type and FIX version. + /// (FIXT11 apps should use the other Create method with explicit applVerId, + /// or devise some other way of specifying the FIX version) /// - public interface IMessageFactory - { - /// - /// Lists the supported begin strings this factory can create messages and groups for - /// - /// List of supported begin strings - ICollection GetSupportedBeginStrings(); - - /// - /// Creates a message for a specified type and FIX version. - /// (FIXT11 apps should use the other Create method with explicit applVerId, - /// or devise some other way of specifying the FIX version) - /// - /// the FIX version (e.g. "FIX.4.2") - /// the FIX message type (e.g. "D" for a NewOrderSingle) - /// a message instance of proper derived type - Message Create(string beginString, string msgType); + /// the FIX version (e.g. "FIX.4.2") + /// the FIX message type (e.g. "D" for a NewOrderSingle) + /// a message instance of proper derived type + Message Create(string beginString, string msgType); - /// - /// Creates a message for a specified type, FIX version, and ApplVerID - /// - /// the FIX version (e.g. "FIX.4.2") - /// the ApplVerID to use if the BeginString is not specific enough (e.g. if it's FIXT11) - /// the FIX message type (e.g. "D" for a NewOrderSingle) - /// a message instance of proper derived type - Message Create(string beginString, QuickFix.Fields.ApplVerID applVerId, string msgType); + /// + /// Creates a message for a specified type, FIX version, and ApplVerID + /// + /// the FIX version (e.g. "FIX.4.2") + /// the ApplVerID to use if the BeginString is not specific enough (e.g. if it's FIXT11) + /// the FIX message type (e.g. "D" for a NewOrderSingle) + /// a message instance of proper derived type + Message Create(string beginString, QuickFix.Fields.ApplVerID applVerId, string msgType); - /// - /// Creates a group for the specified parent message type and - /// for the fields with the corresponding field ID - /// - /// the FIX version (e.g. "FIX.4.2") - /// message type of the enclosing message (e.g. "D" for a NewOrderSingle - /// the tag of the group's counter field - /// A group, or null if the group can't be created - Group? Create(string beginString, string msgType, int groupCounterTag); - } + /// + /// Creates a group for the specified parent message type and + /// for the fields with the corresponding field ID + /// + /// the FIX version (e.g. "FIX.4.2") + /// message type of the enclosing message (e.g. "D" for a NewOrderSingle + /// the tag of the group's counter field + /// A group, or null if the group can't be created + Group? Create(string beginString, string msgType, int groupCounterTag); } diff --git a/QuickFIXn/IResponder.cs b/QuickFIXn/IResponder.cs index 9e30f4345..3cd24cfa4 100755 --- a/QuickFIXn/IResponder.cs +++ b/QuickFIXn/IResponder.cs @@ -1,21 +1,20 @@ -namespace QuickFix +namespace QuickFix; + +/// +/// Used by a Session to send raw FIX message data and to disconnect a +/// connection. This interface is used by Acceptor or Initiator implementations. +/// +public interface IResponder { /// - /// Used by a Session to send raw FIX message data and to disconnect a - /// connection. This interface is used by Acceptor or Initiator implementations. + /// Sends a raw FIX message /// - public interface IResponder - { - /// - /// Sends a raw FIX message - /// - /// the raw FIX message data - /// true if successful, false if send operation failed - bool Send(string s); + /// the raw FIX message data + /// true if successful, false if send operation failed + bool Send(string s); - /// - /// Disconnect the underlying connection - /// - void Disconnect(); - } + /// + /// Disconnect the underlying connection + /// + void Disconnect(); } diff --git a/QuickFIXn/Message/FieldNotFoundException.cs b/QuickFIXn/Message/FieldNotFoundException.cs index 1376214dc..d496c058e 100644 --- a/QuickFIXn/Message/FieldNotFoundException.cs +++ b/QuickFIXn/Message/FieldNotFoundException.cs @@ -1,27 +1,27 @@ using System; -namespace QuickFix +namespace QuickFix; + +/// +/// An exception thrown when a field is not found in a message. If you see +/// this exception, be sure you are accessing the field in the correct +/// section of the message (for example, a header field in message.Header) +/// +public class FieldNotFoundException : ApplicationException { - /// - /// An exception thrown when a field is not found in a message. If you see - /// this exception, be sure you are accessing the field in the correct - /// section of the message (for example, a header field in message.Header) - /// - public class FieldNotFoundException : ApplicationException - { - public int Field { get; set; } - public FieldNotFoundException() { } + public int Field { get; set; } + public FieldNotFoundException() { } - public FieldNotFoundException(int tag) - : base($"field not found for tag: {tag}") - { Field = tag; } + public FieldNotFoundException(int tag) + : base($"field not found for tag: {tag}") + { Field = tag; } - public FieldNotFoundException(string message) - : base(message) - { Field = -1; } + public FieldNotFoundException(string message) + : base(message) + { Field = -1; } - public FieldNotFoundException(string message, System.Exception inner) - : base(message, inner) - { Field = -1; } - } + public FieldNotFoundException(string message, System.Exception inner) + : base(message, inner) + { Field = -1; } } + diff --git a/QuickFIXn/Message/Group.cs b/QuickFIXn/Message/Group.cs index 263b9c424..356ed4278 100644 --- a/QuickFIXn/Message/Group.cs +++ b/QuickFIXn/Message/Group.cs @@ -1,80 +1,79 @@ using QuickFix.ObjectPooling; using System; -namespace QuickFix +namespace QuickFix; + +/// +/// Represents a repeating field group within a message +/// +public class Group : FieldMap { /// - /// Represents a repeating field group within a message + /// Create a group with the specified count and delimiter fields. /// - public class Group : FieldMap + /// tag of the counter field + /// delimiter field's tag (first field in the group) + public Group(int counterField, int delim) + :base(fieldOrd: new[] { delim }) { - /// - /// Create a group with the specified count and delimiter fields. - /// - /// tag of the counter field - /// delimiter field's tag (first field in the group) - public Group(int counterField, int delim) - :base(fieldOrd: new[] { delim }) - { - CounterField = counterField; - Delim = delim; - } + CounterField = counterField; + Delim = delim; + } - /// - /// Create a group with the specified count and delimiter fields and field ordering. - /// - /// tag of the counter field - /// delimiter field's tag (first field in the group) - /// the group's member tags in order - public Group(int counterField, int delim, int[] fieldOrd) - :base(fieldOrd) - { - CounterField = counterField; - Delim = delim; - } + /// + /// Create a group with the specified count and delimiter fields and field ordering. + /// + /// tag of the counter field + /// delimiter field's tag (first field in the group) + /// the group's member tags in order + public Group(int counterField, int delim, int[] fieldOrd) + :base(fieldOrd) + { + CounterField = counterField; + Delim = delim; + } - /// - /// returns a copy of src (it's only as deep as FieldMap implemented) - /// - /// the Group to copy - public Group(Group src) - :base(src) - { - CounterField = src.CounterField; - Delim = src.Delim; - } + /// + /// returns a copy of src (it's only as deep as FieldMap implemented) + /// + /// the Group to copy + public Group(Group src) + :base(src) + { + CounterField = src.CounterField; + Delim = src.Delim; + } - public virtual Group Clone() - { - return new Group(this); - } + public virtual Group Clone() + { + return new Group(this); + } - /// - /// Tag of the group's counter field - /// - public int CounterField { get; } + /// + /// Tag of the group's counter field + /// + public int CounterField { get; } - [Obsolete("Use CounterField instead. This will be removed in 1.16.")] - public int Field => CounterField; + [Obsolete("Use CounterField instead. This will be removed in 1.16.")] + public int Field => CounterField; - /// - /// Tag of the group's delimiter field (first field in the group) - /// - public int Delim { get; } + /// + /// Tag of the group's delimiter field (first field in the group) + /// + public int Delim { get; } - /// - /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) - /// - /// - public override string CalculateString() - { - using PooledStringBuilder pooledSb = new PooledStringBuilder(); - return base.CalculateString(pooledSb.Builder, FieldOrder ?? new[] { Delim }); - } + /// + /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) + /// + /// + public override string CalculateString() + { + using PooledStringBuilder pooledSb = new PooledStringBuilder(); + return base.CalculateString(pooledSb.Builder, FieldOrder ?? new[] { Delim }); + } - public override string ToString() - { - return CalculateString(); - } + public override string ToString() + { + return CalculateString(); } } diff --git a/QuickFIXn/Message/Header.cs b/QuickFIXn/Message/Header.cs index eb2dc2d05..200407f4e 100644 --- a/QuickFIXn/Message/Header.cs +++ b/QuickFIXn/Message/Header.cs @@ -2,36 +2,36 @@ using QuickFix.Fields; using QuickFix.ObjectPooling; -namespace QuickFix { - public class Header : FieldMap { - public int[] HEADER_FIELD_ORDER = { Tags.BeginString, Tags.BodyLength, Tags.MsgType }; +namespace QuickFix; - public Header() - : base() { - } +public class Header : FieldMap { + public int[] HEADER_FIELD_ORDER = [Tags.BeginString, Tags.BodyLength, Tags.MsgType]; - public Header(Header src) - : base(src) { - } + public Header() + : base() { + } + + public Header(Header src) + : base(src) { + } - /// - /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) - /// - /// - public override string CalculateString() - { - using PooledStringBuilder pooledSb = new PooledStringBuilder(); - return base.CalculateString(pooledSb.Builder, HEADER_FIELD_ORDER); - } + /// + /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) + /// + /// + public override string CalculateString() + { + using PooledStringBuilder pooledSb = new PooledStringBuilder(); + return base.CalculateString(pooledSb.Builder, HEADER_FIELD_ORDER); + } - /// - /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) - /// - /// - /// - /// - public override string CalculateString(StringBuilder sb, int[] preFields) { - return base.CalculateString(sb, HEADER_FIELD_ORDER); - } + /// + /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) + /// + /// + /// + /// + public override string CalculateString(StringBuilder sb, int[] preFields) { + return base.CalculateString(sb, HEADER_FIELD_ORDER); } } diff --git a/QuickFIXn/Message/Trailer.cs b/QuickFIXn/Message/Trailer.cs index 69694ff0d..a9307224b 100644 --- a/QuickFIXn/Message/Trailer.cs +++ b/QuickFIXn/Message/Trailer.cs @@ -2,36 +2,36 @@ using QuickFix.Fields; using QuickFix.ObjectPooling; -namespace QuickFix { - public class Trailer : FieldMap { - public int[] TRAILER_FIELD_ORDER = { Tags.SignatureLength, Tags.Signature, Tags.CheckSum }; +namespace QuickFix; - public Trailer() - : base() { - } +public class Trailer : FieldMap { + public int[] TRAILER_FIELD_ORDER = [Tags.SignatureLength, Tags.Signature, Tags.CheckSum]; - public Trailer(Trailer src) - : base(src) { - } + public Trailer() + : base() { + } + + public Trailer(Trailer src) + : base(src) { + } - /// - /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) - /// - /// - public override string CalculateString() - { - using PooledStringBuilder pooledSb = new PooledStringBuilder(); - return base.CalculateString(pooledSb.Builder, TRAILER_FIELD_ORDER); - } + /// + /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) + /// + /// + public override string CalculateString() + { + using PooledStringBuilder pooledSb = new PooledStringBuilder(); + return base.CalculateString(pooledSb.Builder, TRAILER_FIELD_ORDER); + } - /// - /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) - /// - /// - /// - /// - public override string CalculateString(StringBuilder sb, int[] preFields) { - return base.CalculateString(sb, TRAILER_FIELD_ORDER); - } + /// + /// Creates a FIX (ish) string representation of this FieldMap (does not change the object state) + /// + /// + /// + /// + public override string CalculateString(StringBuilder sb, int[] preFields) { + return base.CalculateString(sb, TRAILER_FIELD_ORDER); } } diff --git a/QuickFIXn/MessageBuilder.cs b/QuickFIXn/MessageBuilder.cs index deebf8e41..9ca87109a 100644 --- a/QuickFIXn/MessageBuilder.cs +++ b/QuickFIXn/MessageBuilder.cs @@ -1,70 +1,69 @@ -namespace QuickFix +namespace QuickFix; + +internal class MessageBuilder { - internal class MessageBuilder - { - private readonly string _msgStr; - private readonly bool _validateLengthAndChecksum; - private readonly DataDictionary.DataDictionary _sessionDict; - private readonly DataDictionary.DataDictionary _appDict; - private readonly IMessageFactory _msgFactory; + private readonly bool _validateLengthAndChecksum; + private readonly DataDictionary.DataDictionary _sessionDict; + private readonly DataDictionary.DataDictionary _appDict; + private readonly IMessageFactory _msgFactory; - private Message? _message; - private readonly Fields.ApplVerID _defaultApplVerId; + private Message? _message; + private readonly Fields.ApplVerID _defaultApplVerId; - public string OriginalString => _msgStr; - public Fields.MsgType MsgType { get; } + public string OriginalString { get; } - /// - /// The BeginString from the raw FIX message - /// - public string BeginString { get; } + public Fields.MsgType MsgType { get; } - internal MessageBuilder( - string msgStr, - string defaultApplVerId, - bool validateLengthAndChecksum, - DataDictionary.DataDictionary sessionDict, - DataDictionary.DataDictionary appDict, - IMessageFactory msgFactory) - { - _msgStr = msgStr; - _defaultApplVerId = new Fields.ApplVerID(defaultApplVerId); - _validateLengthAndChecksum = validateLengthAndChecksum; - _sessionDict = sessionDict; - _appDict = appDict; - _msgFactory = msgFactory; - MsgType = Message.IdentifyType(_msgStr); - BeginString = Message.ExtractBeginString(_msgStr); - } + /// + /// The BeginString from the raw FIX message + /// + public string BeginString { get; } - internal Message Build() - { - Message message = _msgFactory.Create(BeginString, _defaultApplVerId, MsgType.Value); - message.FromString( - _msgStr, - _validateLengthAndChecksum, - _sessionDict, - _appDict, - _msgFactory, - ignoreBody: false); - _message = message; - return _message; - } + internal MessageBuilder( + string msgStr, + string defaultApplVerId, + bool validateLengthAndChecksum, + DataDictionary.DataDictionary sessionDict, + DataDictionary.DataDictionary appDict, + IMessageFactory msgFactory) + { + OriginalString = msgStr; + _defaultApplVerId = new Fields.ApplVerID(defaultApplVerId); + _validateLengthAndChecksum = validateLengthAndChecksum; + _sessionDict = sessionDict; + _appDict = appDict; + _msgFactory = msgFactory; + MsgType = Message.IdentifyType(OriginalString); + BeginString = Message.ExtractBeginString(OriginalString); + } - internal Message RejectableMessage() - { - if (_message is not null) - return _message; + internal Message Build() + { + Message message = _msgFactory.Create(BeginString, _defaultApplVerId, MsgType.Value); + message.FromString( + OriginalString, + _validateLengthAndChecksum, + _sessionDict, + _appDict, + _msgFactory, + ignoreBody: false); + _message = message; + return _message; + } + + internal Message RejectableMessage() + { + if (_message is not null) + return _message; - Message message = _msgFactory.Create(BeginString, MsgType.Value); - message.FromString( - _msgStr, - false, - _sessionDict, - _appDict, - _msgFactory, - true); - return message; - } + Message message = _msgFactory.Create(BeginString, MsgType.Value); + message.FromString( + OriginalString, + false, + _sessionDict, + _appDict, + _msgFactory, + true); + return message; } } diff --git a/QuickFIXn/MessageCracker.cs b/QuickFIXn/MessageCracker.cs index 98126dc22..4d1623f71 100644 --- a/QuickFIXn/MessageCracker.cs +++ b/QuickFIXn/MessageCracker.cs @@ -3,83 +3,82 @@ using System.Reflection; using System.Linq.Expressions; -namespace QuickFix +namespace QuickFix; + +/// +/// Helper class for delegating message types for various FIX versions to +/// type-safe OnMessage methods. +/// +public abstract class MessageCracker { - /// - /// Helper class for delegating message types for various FIX versions to - /// type-safe OnMessage methods. - /// - public abstract class MessageCracker + private readonly Dictionary> _callCache = new (); + + protected MessageCracker() + { + Initialize(this); + } + + private void Initialize(object messageHandler) { - private readonly Dictionary> _callCache = new (); + Type handlerType = messageHandler.GetType(); - protected MessageCracker() + MethodInfo[] methods = handlerType.GetMethods(BindingFlags.Public | BindingFlags.Instance); + + foreach (MethodInfo m in methods) { - Initialize(this); + TryBuildCallCache(m); } + } - private void Initialize(object messageHandler) + /// + /// build a complied expression tree - much faster than calling MethodInfo.Invoke + /// + /// + private void TryBuildCallCache(MethodInfo m) + { + if (IsHandlerMethod(m)) { - Type handlerType = messageHandler.GetType(); + var parameters = m.GetParameters(); + var expParamMessage = parameters[0]; + var expParamSessionId = parameters[1]; + var messageParam = Expression.Parameter(typeof(Message), "message"); + var sessionParam = Expression.Parameter(typeof(SessionID), "sessionID"); + var instance = Expression.Constant(this); + var methodCall = Expression.Call(instance, m, Expression.Convert(messageParam, expParamMessage.ParameterType), Expression.Convert(sessionParam, expParamSessionId.ParameterType)); + var action = Expression.Lambda>(methodCall, messageParam, sessionParam).Compile(); + _callCache[expParamMessage.ParameterType] = action; + } + } - MethodInfo[] methods = handlerType.GetMethods(BindingFlags.Public | BindingFlags.Instance); - foreach (MethodInfo m in methods) - { - TryBuildCallCache(m); - } - } + public static bool IsHandlerMethod(MethodInfo m) + { + ParameterInfo[] parameters; + return m.IsPublic + && m.ReturnType == typeof(void) + && m.Name.Equals("OnMessage") + && (parameters = m.GetParameters()).Length == 2 + && parameters[0].ParameterType.IsSubclassOf(typeof(Message)) + && typeof(SessionID).IsAssignableFrom(parameters[1].ParameterType); + } - /// - /// build a complied expression tree - much faster than calling MethodInfo.Invoke - /// - /// - private void TryBuildCallCache(MethodInfo m) - { - if (IsHandlerMethod(m)) - { - var parameters = m.GetParameters(); - var expParamMessage = parameters[0]; - var expParamSessionId = parameters[1]; - var messageParam = Expression.Parameter(typeof(Message), "message"); - var sessionParam = Expression.Parameter(typeof(SessionID), "sessionID"); - var instance = Expression.Constant(this); - var methodCall = Expression.Call(instance, m, Expression.Convert(messageParam, expParamMessage.ParameterType), Expression.Convert(sessionParam, expParamSessionId.ParameterType)); - var action = Expression.Lambda>(methodCall, messageParam, sessionParam).Compile(); - _callCache[expParamMessage.ParameterType] = action; - } - } + /// + /// Process ("crack") a FIX message and call the registered handlers for that type, if any + /// + /// + /// + public void Crack(Message message, SessionID sessionId) + { + Type messageType = message.GetType(); - public static bool IsHandlerMethod(MethodInfo m) + if (_callCache.TryGetValue(messageType, out Action? onMessage)) { - ParameterInfo[] parameters; - return m.IsPublic - && m.ReturnType == typeof(void) - && m.Name.Equals("OnMessage") - && (parameters = m.GetParameters()).Length == 2 - && parameters[0].ParameterType.IsSubclassOf(typeof(Message)) - && typeof(SessionID).IsAssignableFrom(parameters[1].ParameterType); + onMessage(message, sessionId); } - - - /// - /// Process ("crack") a FIX message and call the registered handlers for that type, if any - /// - /// - /// - public void Crack(Message message, SessionID sessionId) + else { - Type messageType = message.GetType(); - - if (_callCache.TryGetValue(messageType, out Action? onMessage)) - { - onMessage(message, sessionId); - } - else - { - throw new UnsupportedMessageType(); - } + throw new UnsupportedMessageType(); } } } diff --git a/QuickFIXn/NullApplication.cs b/QuickFIXn/NullApplication.cs index 130c8771d..042722685 100755 --- a/QuickFIXn/NullApplication.cs +++ b/QuickFIXn/NullApplication.cs @@ -1,22 +1,21 @@  -namespace QuickFix +namespace QuickFix; + +/// +/// Application implementation that does not do anything. +/// Useful for unit testing. +/// +public class NullApplication : IApplication { - /// - /// Application implementation that does not do anything. - /// Useful for unit testing. - /// - public class NullApplication : IApplication - { - public void FromAdmin(Message message, SessionID sessionID) - { } + public void FromAdmin(Message message, SessionID sessionID) + { } - public void FromApp(Message message, SessionID sessionID) - { } + public void FromApp(Message message, SessionID sessionID) + { } - public void OnCreate(SessionID sessionID) { } - public void OnLogout(SessionID sessionID) { } - public void OnLogon(SessionID sessionID) { } - public void ToAdmin(Message message, SessionID sessionID) { } - public void ToApp(Message message, SessionID sessionID) { } - } + public void OnCreate(SessionID sessionID) { } + public void OnLogout(SessionID sessionID) { } + public void OnLogon(SessionID sessionID) { } + public void ToAdmin(Message message, SessionID sessionID) { } + public void ToApp(Message message, SessionID sessionID) { } } diff --git a/QuickFIXn/ResendRange.cs b/QuickFIXn/ResendRange.cs index 36bc9d63c..aed4cd3a9 100755 --- a/QuickFIXn/ResendRange.cs +++ b/QuickFIXn/ResendRange.cs @@ -1,81 +1,79 @@ using System; -namespace QuickFix +namespace QuickFix; + +public class ResendRange { - public class ResendRange - { - public const SeqNumType NOT_SET = SeqNumType.MaxValue; + public const SeqNumType NOT_SET = SeqNumType.MaxValue; - public SeqNumType BeginSeqNo { get; private set; } + public SeqNumType BeginSeqNo { get; private set; } - /// - /// Final sequence number needed, regardless of configured MaxMessagesInResendRequest. - /// If it's zero (aka infinity) then TriggerSeqNo has the real value. - /// - public SeqNumType EndSeqNo { get; private set; } + /// + /// Final sequence number needed, regardless of configured MaxMessagesInResendRequest. + /// If it's zero (aka infinity) then TriggerSeqNo has the real value. + /// + public SeqNumType EndSeqNo { get; private set; } - /// - /// If set, this is the EndSeqNo of the active ResendRequest, - /// because of MaxMessagesInResendRequest. - /// - public SeqNumType ChunkEndSeqNo { get; private set; } + /// + /// If set, this is the EndSeqNo of the active ResendRequest, + /// because of MaxMessagesInResendRequest. + /// + public SeqNumType ChunkEndSeqNo { get; private set; } - public bool IsResendStarted { get; private set; } + public bool IsResendStarted { get; private set; } - /// - /// The original too-high seq num - /// (so we can track the end of the resend if EndSeqNo=0 aka infinity) - /// - public SeqNumType TriggerSeqNo { get; private set; } + /// + /// The original too-high seq num + /// (so we can track the end of the resend if EndSeqNo=0 aka infinity) + /// + public SeqNumType TriggerSeqNo { get; private set; } - public ResendRange() - { - Reset(); - } + public ResendRange() + { + Reset(); + } - public void Reset() - { - BeginSeqNo = 0; - EndSeqNo = 0; - ChunkEndSeqNo = ResendRange.NOT_SET; - TriggerSeqNo = 0; - IsResendStarted = false; - } + public void Reset() + { + BeginSeqNo = 0; + EndSeqNo = 0; + ChunkEndSeqNo = ResendRange.NOT_SET; + TriggerSeqNo = 0; + IsResendStarted = false; + } - public void Set( - SeqNumType beginSeqNo, SeqNumType endSeqNo, SeqNumType triggerSeqNo, - Message resendRequest, SeqNumType endChunkSeqNo = NOT_SET) - { - BeginSeqNo = beginSeqNo; - EndSeqNo = endSeqNo; - ChunkEndSeqNo = endChunkSeqNo; - TriggerSeqNo = triggerSeqNo; - IsResendStarted = false; - } + public void Set( + SeqNumType beginSeqNo, SeqNumType endSeqNo, SeqNumType triggerSeqNo, + Message resendRequest, SeqNumType endChunkSeqNo = NOT_SET) + { + BeginSeqNo = beginSeqNo; + EndSeqNo = endSeqNo; + ChunkEndSeqNo = endChunkSeqNo; + TriggerSeqNo = triggerSeqNo; + IsResendStarted = false; + } - public void MarkAsStarted() - { - IsResendStarted = true; - } + public void MarkAsStarted() + { + IsResendStarted = true; + } - public void UpdateChunk(SeqNumType chunkBegin, SeqNumType chunkEnd) - { - BeginSeqNo = chunkBegin; - ChunkEndSeqNo = chunkEnd; - IsResendStarted = false; - } + public void UpdateChunk(SeqNumType chunkBegin, SeqNumType chunkEnd) + { + BeginSeqNo = chunkBegin; + ChunkEndSeqNo = chunkEnd; + IsResendStarted = false; + } - /// - /// If EndSeqNo is 0, then need to derive the end from TriggerSeqNo - /// - public SeqNumType ActualEndSeqNo => EndSeqNo > 0 ? EndSeqNo : TriggerSeqNo - 1; + /// + /// If EndSeqNo is 0, then need to derive the end from TriggerSeqNo + /// + public SeqNumType ActualEndSeqNo => EndSeqNo > 0 ? EndSeqNo : TriggerSeqNo - 1; - public override string ToString() - { - string chunkEnd = ChunkEndSeqNo == NOT_SET ? "-" : ChunkEndSeqNo.ToString(); - return - $"{BeginSeqNo}:{EndSeqNo} (ChunkEndSeqNo={chunkEnd} IsResendStarted={IsResendStarted} TriggeredSeqNo={TriggerSeqNo})"; - } + public override string ToString() + { + string chunkEnd = ChunkEndSeqNo == NOT_SET ? "-" : ChunkEndSeqNo.ToString(); + return + $"{BeginSeqNo}:{EndSeqNo} (ChunkEndSeqNo={chunkEnd} IsResendStarted={IsResendStarted} TriggeredSeqNo={TriggerSeqNo})"; } } - diff --git a/QuickFIXn/SessionID.cs b/QuickFIXn/SessionID.cs index c85b07ca2..1daed1a4f 100755 --- a/QuickFIXn/SessionID.cs +++ b/QuickFIXn/SessionID.cs @@ -1,94 +1,93 @@ using System; -namespace QuickFix +namespace QuickFix; + +/// +/// Identifies a session. Only supports a company ID (target, sender) +/// and a session qualifier. Sessions are also identified by FIX version so +/// that it's possible to have multiple sessions to the same counterparty +/// but using different FIX versions (and/or session qualifiers). +/// +public class SessionID { + public string BeginString { get; } + public string SenderCompID { get; } + public string SenderSubID { get; } + public string SenderLocationID { get; } + public string TargetCompID { get; } + public string TargetSubID { get; } + public string TargetLocationID { get; } + /// - /// Identifies a session. Only supports a company ID (target, sender) - /// and a session qualifier. Sessions are also identified by FIX version so - /// that it's possible to have multiple sessions to the same counterparty - /// but using different FIX versions (and/or session qualifiers). + /// Session qualifier can be used to identify different sessions + /// for the same target company ID. Session qualifiers can only be used + /// with initiated sessions. They cannot be used with accepted sessions. /// - public class SessionID - { - public string BeginString { get; } - public string SenderCompID { get; } - public string SenderSubID { get; } - public string SenderLocationID { get; } - public string TargetCompID { get; } - public string TargetSubID { get; } - public string TargetLocationID { get; } + public string? SessionQualifier { get; } - /// - /// Session qualifier can be used to identify different sessions - /// for the same target company ID. Session qualifiers can only be used - /// with initiated sessions. They cannot be used with accepted sessions. - /// - public string? SessionQualifier { get; } + /// + /// Returns whether session version is FIXT 1.1 or newer + /// + public bool IsFIXT { get; } - /// - /// Returns whether session version is FIXT 1.1 or newer - /// - public bool IsFIXT { get; } + // TODO just make the values nullable, jeez + public const string NOT_SET = ""; - // TODO just make the values nullable, jeez - public const string NOT_SET = ""; + private readonly string _id; - private readonly string _id; + public SessionID(string beginString, string senderCompId, string senderSubId, string senderLocationId, string targetCompId, string targetSubId, string targetLocationId, string? sessionQualifier = NOT_SET) + { + BeginString = beginString ?? throw new ArgumentNullException(nameof(beginString)); + SenderCompID = senderCompId ?? throw new ArgumentNullException(nameof(senderCompId)); + SenderSubID = senderSubId; + SenderLocationID = senderLocationId; + TargetCompID = targetCompId ?? throw new ArgumentNullException(nameof(targetCompId)); + TargetSubID = targetSubId; + TargetLocationID = targetLocationId; + SessionQualifier = sessionQualifier; + IsFIXT = BeginString.StartsWith("FIXT", StringComparison.Ordinal); - public SessionID(string beginString, string senderCompId, string senderSubId, string senderLocationId, string targetCompId, string targetSubId, string targetLocationId, string? sessionQualifier = NOT_SET) - { - BeginString = beginString ?? throw new ArgumentNullException(nameof(beginString)); - SenderCompID = senderCompId ?? throw new ArgumentNullException(nameof(senderCompId)); - SenderSubID = senderSubId; - SenderLocationID = senderLocationId; - TargetCompID = targetCompId ?? throw new ArgumentNullException(nameof(targetCompId)); - TargetSubID = targetSubId; - TargetLocationID = targetLocationId; - SessionQualifier = sessionQualifier; - IsFIXT = BeginString.StartsWith("FIXT", StringComparison.Ordinal); + _id = BeginString + + ":" + + SenderCompID + + (IsSet(SenderSubID) ? "/" + SenderSubID : "") + + (IsSet(SenderLocationID) ? "/" + SenderLocationID : "") + + "->" + + TargetCompID + + (IsSet(TargetSubID) ? "/" + TargetSubID : "") + + (IsSet(TargetLocationID) ? "/" + TargetLocationID : ""); + if (SessionQualifier is not null && SessionQualifier.Length > 0) + _id += ":" + SessionQualifier; + } - _id = BeginString - + ":" - + SenderCompID - + (IsSet(SenderSubID) ? "/" + SenderSubID : "") - + (IsSet(SenderLocationID) ? "/" + SenderLocationID : "") - + "->" - + TargetCompID - + (IsSet(TargetSubID) ? "/" + TargetSubID : "") - + (IsSet(TargetLocationID) ? "/" + TargetLocationID : ""); - if (SessionQualifier is not null && SessionQualifier.Length > 0) - _id += ":" + SessionQualifier; - } + public SessionID(string beginString, string senderCompId, string senderSubId, string targetCompId, string targetSubId) + : this(beginString, senderCompId, senderSubId, senderLocationId: NOT_SET, targetCompId, targetSubId, targetLocationId: NOT_SET) + { } - public SessionID(string beginString, string senderCompId, string senderSubId, string targetCompId, string targetSubId) - : this(beginString, senderCompId, senderSubId, senderLocationId: NOT_SET, targetCompId, targetSubId, targetLocationId: NOT_SET) - { } + public SessionID(string beginString, string senderCompId, string targetCompId, string sessionQualifier = NOT_SET) + : this(beginString, senderCompId, senderSubId: NOT_SET, senderLocationId: NOT_SET, targetCompId, targetSubId: NOT_SET, targetLocationId: NOT_SET, sessionQualifier) + { } - public SessionID(string beginString, string senderCompId, string targetCompId, string sessionQualifier = NOT_SET) - : this(beginString, senderCompId, senderSubId: NOT_SET, senderLocationId: NOT_SET, targetCompId, targetSubId: NOT_SET, targetLocationId: NOT_SET, sessionQualifier) - { } + public static bool IsSet(string? value) + { + return value != null && value != NOT_SET; + } - public static bool IsSet(string? value) - { - return value != null && value != NOT_SET; - } + public override string ToString() + { + return _id; + } - public override string ToString() - { - return _id; - } + public override int GetHashCode() + { + return _id.GetHashCode(); + } - public override int GetHashCode() - { - return _id.GetHashCode(); - } - - public override bool Equals(object? obj) - { - if (obj == null || GetType() != obj.GetType()) - return false; - SessionID rhs = (SessionID)obj; - return _id.Equals(rhs._id); - } + public override bool Equals(object? obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + SessionID rhs = (SessionID)obj; + return _id.Equals(rhs._id); } } diff --git a/QuickFIXn/SessionSchedule.cs b/QuickFIXn/SessionSchedule.cs index e4a990bda..951b3251f 100755 --- a/QuickFIXn/SessionSchedule.cs +++ b/QuickFIXn/SessionSchedule.cs @@ -1,296 +1,295 @@ using System; using System.Collections.Generic; -namespace QuickFix -{ - public class SessionSchedule - { - public TimeSpan? StartTime { get; } - public TimeSpan? EndTime { get; } +namespace QuickFix; - public bool WeeklySession { get; } - public DayOfWeek? StartDay { get; } - public DayOfWeek? EndDay { get; } +public class SessionSchedule +{ + public TimeSpan? StartTime { get; } + public TimeSpan? EndTime { get; } - private readonly bool _isWeekdaysSession; - private readonly HashSet _weekdays = new(); + public bool WeeklySession { get; } + public DayOfWeek? StartDay { get; } + public DayOfWeek? EndDay { get; } - public bool NonStopSession { get; } + private readonly bool _isWeekdaysSession; + private readonly HashSet _weekdays = []; - public bool UseLocalTime { get; } - public TimeZoneInfo? TimeZone { get; } + public bool NonStopSession { get; } + public bool UseLocalTime { get; } + public TimeZoneInfo? TimeZone { get; } - /// - /// Returns true if testtime is in a different and newer session than old time - /// (or more explicitly: oldtime <= some EndTime < testtime) - /// - /// - /// - /// - public bool IsNewSession(DateTime oldtimeUtc, DateTime testtimeUtc) - { - if (NonStopSession) - return false; - if (oldtimeUtc.Kind != DateTimeKind.Utc) - throw new ArgumentException("Only UTC time is supported", nameof(oldtimeUtc)); - if (testtimeUtc.Kind != DateTimeKind.Utc) - throw new ArgumentException("Only UTC time is supported", nameof(testtimeUtc)); + /// + /// Returns true if testtime is in a different and newer session than old time + /// (or more explicitly: oldtime <= some EndTime < testtime) + /// + /// + /// + /// + public bool IsNewSession(DateTime oldtimeUtc, DateTime testtimeUtc) + { + if (NonStopSession) + return false; - DateTime old = AdjustUtcDateTime(oldtimeUtc); - DateTime test = AdjustUtcDateTime(testtimeUtc); + if (oldtimeUtc.Kind != DateTimeKind.Utc) + throw new ArgumentException("Only UTC time is supported", nameof(oldtimeUtc)); + if (testtimeUtc.Kind != DateTimeKind.Utc) + throw new ArgumentException("Only UTC time is supported", nameof(testtimeUtc)); - if (DateTime.Compare(old, test) < 0) // old is earlier than test - { - DateTime nextend = NextEndTime(oldtimeUtc); - return (DateTime.Compare(old, nextend) <= 0) && (DateTime.Compare(nextend, test) < 0); - } + DateTime old = AdjustUtcDateTime(oldtimeUtc); + DateTime test = AdjustUtcDateTime(testtimeUtc); - return false; + if (DateTime.Compare(old, test) < 0) // old is earlier than test + { + DateTime nextend = NextEndTime(oldtimeUtc); + return (DateTime.Compare(old, nextend) <= 0) && (DateTime.Compare(nextend, test) < 0); } - /// - /// Convert the parameter to its equivalent datetime in the config file's stated timezone - /// - /// - /// - public DateTime AdjustUtcDateTime(DateTime utc) - { - if (utc.Kind != DateTimeKind.Utc) - throw new ArgumentException("Only UTC time is supported", nameof(utc)); + return false; + } - if(UseLocalTime) - return utc.ToLocalTime(); + /// + /// Convert the parameter to its equivalent datetime in the config file's stated timezone + /// + /// + /// + public DateTime AdjustUtcDateTime(DateTime utc) + { + if (utc.Kind != DateTimeKind.Utc) + throw new ArgumentException("Only UTC time is supported", nameof(utc)); - return TimeZone==null ? utc : TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZone); - } + if(UseLocalTime) + return utc.ToLocalTime(); - public bool IsSessionTime(DateTime utc) - { - if (utc.Kind != DateTimeKind.Utc) - throw new ArgumentException("Only UTC time is supported", nameof(utc)); + return TimeZone==null ? utc : TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZone); + } - DateTime adjusted = AdjustUtcDateTime(utc); + public bool IsSessionTime(DateTime utc) + { + if (utc.Kind != DateTimeKind.Utc) + throw new ArgumentException("Only UTC time is supported", nameof(utc)); - if (_isWeekdaysSession) - return CheckWeekdays(adjusted); + DateTime adjusted = AdjustUtcDateTime(utc); - return WeeklySession ? CheckDay(adjusted) : CheckTime(adjusted.TimeOfDay); - } + if (_isWeekdaysSession) + return CheckWeekdays(adjusted); - /// - /// Get the next endtime (in config file's timezone) that is equal to or after the input. - /// - /// a utc time (raises an ArgumentException if not utc) - /// - public DateTime NextEndTime(DateTime utc) - { - if (NonStopSession) - throw new InvalidOperationException("NonStopSession is set; this statement should be unreachable"); + return WeeklySession ? CheckDay(adjusted) : CheckTime(adjusted.TimeOfDay); + } - TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); + /// + /// Get the next endtime (in config file's timezone) that is equal to or after the input. + /// + /// a utc time (raises an ArgumentException if not utc) + /// + public DateTime NextEndTime(DateTime utc) + { + if (NonStopSession) + throw new InvalidOperationException("NonStopSession is set; this statement should be unreachable"); - if (utc.Kind != DateTimeKind.Utc) - throw new ArgumentException("Only UTC time is supported", nameof(utc)); + TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); - DateTime d = AdjustUtcDateTime(utc); - DateTime end = DateTime.MinValue; + if (utc.Kind != DateTimeKind.Utc) + throw new ArgumentException("Only UTC time is supported", nameof(utc)); + DateTime d = AdjustUtcDateTime(utc); + DateTime end = DateTime.MinValue; - if (_isWeekdaysSession) - { - end = new DateTime(d.Year, d.Month, d.Day, vEndTime.Hours, vEndTime.Minutes, vEndTime.Seconds, d.Kind); - if (DateTime.Compare(d, end) > 0) // d is later than end - end = end.AddDays(1); - } - else if (WeeklySession) - { - end = new DateTime(d.Year, d.Month, d.Day, vEndTime.Hours, vEndTime.Minutes, vEndTime.Seconds, d.Kind); - while (end.DayOfWeek != EndDay) - end = end.AddDays(1); - if (DateTime.Compare(d, end) > 0) // d is later than end - end = end.AddDays(7); - } - else - { - end = new DateTime(d.Year, d.Month, d.Day, vEndTime.Hours, vEndTime.Minutes, vEndTime.Seconds, d.Kind); - if (DateTime.Compare(d, end) > 0) // d is later than end - end = end.AddDays(1); - } - return end; + if (_isWeekdaysSession) + { + end = new DateTime(d.Year, d.Month, d.Day, vEndTime.Hours, vEndTime.Minutes, vEndTime.Seconds, d.Kind); + if (DateTime.Compare(d, end) > 0) // d is later than end + end = end.AddDays(1); } - - /// - /// return true if time falls within StartTime/EndTime - /// - /// - /// - private bool CheckDay(DateTime dt) + else if (WeeklySession) + { + end = new DateTime(d.Year, d.Month, d.Day, vEndTime.Hours, vEndTime.Minutes, vEndTime.Seconds, d.Kind); + while (end.DayOfWeek != EndDay) + end = end.AddDays(1); + if (DateTime.Compare(d, end) > 0) // d is later than end + end = end.AddDays(7); + } + else { - if (NonStopSession) - throw new InvalidOperationException("NonStopSession is set; this statement should be unreachable"); + end = new DateTime(d.Year, d.Month, d.Day, vEndTime.Hours, vEndTime.Minutes, vEndTime.Seconds, d.Kind); + if (DateTime.Compare(d, end) > 0) // d is later than end + end = end.AddDays(1); + } - DayOfWeek vStartDay = StartDay ?? throw new ConfigError("StartDay is null"); - DayOfWeek vEndDay = EndDay ?? throw new ConfigError("EndDay is null"); - TimeSpan vStartTime = StartTime ?? throw new ConfigError("StartTime is null"); - TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); + return end; + } - if (vStartDay < vEndDay) - { - if (dt.DayOfWeek < vStartDay || dt.DayOfWeek > vEndDay) - return false; + /// + /// return true if time falls within StartTime/EndTime + /// + /// + /// + private bool CheckDay(DateTime dt) + { + if (NonStopSession) + throw new InvalidOperationException("NonStopSession is set; this statement should be unreachable"); - if (dt.DayOfWeek < vEndDay) - return (vStartDay < dt.DayOfWeek) || (vStartTime.CompareTo(dt.TimeOfDay) <= 0); + DayOfWeek vStartDay = StartDay ?? throw new ConfigError("StartDay is null"); + DayOfWeek vEndDay = EndDay ?? throw new ConfigError("EndDay is null"); + TimeSpan vStartTime = StartTime ?? throw new ConfigError("StartTime is null"); + TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); - return (dt.DayOfWeek < vEndDay) || (vEndTime.CompareTo(dt.TimeOfDay) >= 0); - } + if (vStartDay < vEndDay) + { + if (dt.DayOfWeek < vStartDay || dt.DayOfWeek > vEndDay) + return false; - if (vEndDay < vStartDay) - { - if (vEndDay < dt.DayOfWeek && dt.DayOfWeek < vStartDay) - return false; + if (dt.DayOfWeek < vEndDay) + return (vStartDay < dt.DayOfWeek) || (vStartTime.CompareTo(dt.TimeOfDay) <= 0); - if (dt.DayOfWeek < vStartDay) - return (dt.DayOfWeek < vEndDay) || (vEndTime.CompareTo(dt.TimeOfDay) >= 0); + return (dt.DayOfWeek < vEndDay) || (vEndTime.CompareTo(dt.TimeOfDay) >= 0); + } - return (dt.DayOfWeek > vStartDay) || (vStartTime.CompareTo(dt.TimeOfDay) <= 0); - } + if (vEndDay < vStartDay) + { + if (vEndDay < dt.DayOfWeek && dt.DayOfWeek < vStartDay) + return false; - //start day must be same as end day - if (vStartTime >= vEndTime) - return dt.DayOfWeek != vStartDay || CheckTime(dt.TimeOfDay); + if (dt.DayOfWeek < vStartDay) + return (dt.DayOfWeek < vEndDay) || (vEndTime.CompareTo(dt.TimeOfDay) >= 0); - return dt.DayOfWeek == vStartDay && CheckTime(dt.TimeOfDay); + return (dt.DayOfWeek > vStartDay) || (vStartTime.CompareTo(dt.TimeOfDay) <= 0); } - /// - /// Return true if time is between StartDay:StartTime and EndDay:EndTime - /// - /// - /// - private bool CheckTime(TimeSpan time) - { - if (NonStopSession) - return true; + //start day must be same as end day + if (vStartTime >= vEndTime) + return dt.DayOfWeek != vStartDay || CheckTime(dt.TimeOfDay); - TimeSpan vStartTime = StartTime ?? throw new ConfigError("StartTime is null"); - TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); + return dt.DayOfWeek == vStartDay && CheckTime(dt.TimeOfDay); + } - if (vStartTime.CompareTo(vEndTime) < 0) - { - return time.CompareTo(vStartTime) >= 0 && - time.CompareTo(vEndTime) <= 0; - } + /// + /// Return true if time is between StartDay:StartTime and EndDay:EndTime + /// + /// + /// + private bool CheckTime(TimeSpan time) + { + if (NonStopSession) + return true; - return time.CompareTo(vStartTime) >= 0 || + TimeSpan vStartTime = StartTime ?? throw new ConfigError("StartTime is null"); + TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); + + if (vStartTime.CompareTo(vEndTime) < 0) + { + return time.CompareTo(vStartTime) >= 0 && time.CompareTo(vEndTime) <= 0; } - private bool CheckWeekdays(DateTime dt) - { - if (NonStopSession) - throw new InvalidOperationException("NonStopSession is set; this statement should be unreachable"); + return time.CompareTo(vStartTime) >= 0 || + time.CompareTo(vEndTime) <= 0; + } - TimeSpan vStartTime = StartTime ?? throw new ConfigError("StartTime is null"); - TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); + private bool CheckWeekdays(DateTime dt) + { + if (NonStopSession) + throw new InvalidOperationException("NonStopSession is set; this statement should be unreachable"); - TimeSpan tod = dt.TimeOfDay; + TimeSpan vStartTime = StartTime ?? throw new ConfigError("StartTime is null"); + TimeSpan vEndTime = EndTime ?? throw new ConfigError("EndTime is null"); - // session spans midnight - if (vStartTime.CompareTo(vEndTime) < 0) { - return _weekdays.Contains(dt.DayOfWeek) && - tod.CompareTo(vStartTime) >= 0 && - tod.CompareTo(vEndTime) < 0; - } + TimeSpan tod = dt.TimeOfDay; - // session doesn't span midnight - if (tod.CompareTo(vEndTime) >= 0 && tod.CompareTo(vStartTime) < 0) - return false; - var targetDay = tod.CompareTo(vStartTime) >= 0 - ? dt.DayOfWeek - : PreviousDay(dt.DayOfWeek); - return _weekdays.Contains(targetDay); + // session spans midnight + if (vStartTime.CompareTo(vEndTime) < 0) { + return _weekdays.Contains(dt.DayOfWeek) && + tod.CompareTo(vStartTime) >= 0 && + tod.CompareTo(vEndTime) < 0; } - private static DayOfWeek PreviousDay(DayOfWeek d) { - return d == DayOfWeek.Sunday - ? DayOfWeek.Saturday - : d - 1; - } + // session doesn't span midnight + if (tod.CompareTo(vEndTime) >= 0 && tod.CompareTo(vStartTime) < 0) + return false; + var targetDay = tod.CompareTo(vStartTime) >= 0 + ? dt.DayOfWeek + : PreviousDay(dt.DayOfWeek); + return _weekdays.Contains(targetDay); + } - /// - /// - /// - public SessionSchedule(SettingsDictionary settings) - { - if (settings.IsBoolPresentAndTrue(SessionSettings.NON_STOP_SESSION)) { - NonStopSession = true; - - if (settings.Has(SessionSettings.START_DAY) - || settings.Has(SessionSettings.END_DAY) - || settings.Has(SessionSettings.START_TIME) - || settings.Has(SessionSettings.END_TIME)) - { - throw new ConfigError( - "NonStopSession is not compatible with StartDay/EndDay and StartTime/EndTime"); - } - - return; - } + private static DayOfWeek PreviousDay(DayOfWeek d) { + return d == DayOfWeek.Sunday + ? DayOfWeek.Saturday + : d - 1; + } - if (settings.Has(SessionSettings.WEEKDAYS)) - { - _isWeekdaysSession = true; - if (settings.Has(SessionSettings.START_DAY) || settings.Has(SessionSettings.END_DAY) ) - throw new ConfigError("StartDay/EndDay are not compatible with 'Weekdays' setting"); + /// + /// + /// + public SessionSchedule(SettingsDictionary settings) + { + if (settings.IsBoolPresentAndTrue(SessionSettings.NON_STOP_SESSION)) { + NonStopSession = true; - _weekdays = settings.GetDays(SessionSettings.WEEKDAYS); + if (settings.Has(SessionSettings.START_DAY) + || settings.Has(SessionSettings.END_DAY) + || settings.Has(SessionSettings.START_TIME) + || settings.Has(SessionSettings.END_TIME)) + { + throw new ConfigError( + "NonStopSession is not compatible with StartDay/EndDay and StartTime/EndTime"); } - if (!settings.Has(SessionSettings.START_DAY) && settings.Has(SessionSettings.END_DAY)) - throw new ConfigError("EndDay used without StartDay"); + return; + } - if (settings.Has(SessionSettings.START_DAY) && !settings.Has(SessionSettings.END_DAY)) - throw new ConfigError("StartDay used without EndDay"); + if (settings.Has(SessionSettings.WEEKDAYS)) + { + _isWeekdaysSession = true; + if (settings.Has(SessionSettings.START_DAY) || settings.Has(SessionSettings.END_DAY) ) + throw new ConfigError("StartDay/EndDay are not compatible with 'Weekdays' setting"); - if (settings.Has(SessionSettings.START_DAY) && settings.Has(SessionSettings.END_DAY)) - { - StartDay = settings.GetDay(SessionSettings.START_DAY); - EndDay = settings.GetDay(SessionSettings.END_DAY); - WeeklySession = true; - } + _weekdays = settings.GetDays(SessionSettings.WEEKDAYS); + } - if (settings.Has(SessionSettings.USE_LOCAL_TIME)) - { - UseLocalTime = settings.GetBool(SessionSettings.USE_LOCAL_TIME); - } + if (!settings.Has(SessionSettings.START_DAY) && settings.Has(SessionSettings.END_DAY)) + throw new ConfigError("EndDay used without StartDay"); - if (settings.Has(SessionSettings.TIME_ZONE)) - { - if (UseLocalTime) - { - throw new ConfigError( - SessionSettings.TIME_ZONE + " conflicts with " + SessionSettings.USE_LOCAL_TIME); - } - string id = settings.GetString(SessionSettings.TIME_ZONE); - TimeZone = TimeZoneInfo.FindSystemTimeZoneById(id); - } + if (settings.Has(SessionSettings.START_DAY) && !settings.Has(SessionSettings.END_DAY)) + throw new ConfigError("StartDay used without EndDay"); - try - { - StartTime = TimeSpan.Parse( - settings.GetString(SessionSettings.START_TIME)); + if (settings.Has(SessionSettings.START_DAY) && settings.Has(SessionSettings.END_DAY)) + { + StartDay = settings.GetDay(SessionSettings.START_DAY); + EndDay = settings.GetDay(SessionSettings.END_DAY); + WeeklySession = true; + } - EndTime = TimeSpan.Parse( - settings.GetString(SessionSettings.END_TIME)); - } - catch (FormatException e) + if (settings.Has(SessionSettings.USE_LOCAL_TIME)) + { + UseLocalTime = settings.GetBool(SessionSettings.USE_LOCAL_TIME); + } + + if (settings.Has(SessionSettings.TIME_ZONE)) + { + if (UseLocalTime) { - throw new ConfigError(e.Message); + throw new ConfigError( + SessionSettings.TIME_ZONE + " conflicts with " + SessionSettings.USE_LOCAL_TIME); } + string id = settings.GetString(SessionSettings.TIME_ZONE); + TimeZone = TimeZoneInfo.FindSystemTimeZoneById(id); + } + + try + { + StartTime = TimeSpan.Parse( + settings.GetString(SessionSettings.START_TIME)); + + EndTime = TimeSpan.Parse( + settings.GetString(SessionSettings.END_TIME)); + } + catch (FormatException e) + { + throw new ConfigError(e.Message); } } } diff --git a/QuickFIXn/Settings.cs b/QuickFIXn/Settings.cs index 85a11ab36..5ee5466c4 100755 --- a/QuickFIXn/Settings.cs +++ b/QuickFIXn/Settings.cs @@ -1,84 +1,83 @@ using System.Collections.Generic; -namespace QuickFix +namespace QuickFix; + +public class Settings { - public class Settings + private readonly LinkedList _sections = []; + + public Settings(System.IO.TextReader conf) { - private readonly LinkedList _sections = new(); + SettingsDictionary? currentSection = null; - public Settings(System.IO.TextReader conf) + string? line; + while ((line = conf.ReadLine()) != null) { - SettingsDictionary? currentSection = null; - - string? line; - while ((line = conf.ReadLine()) != null) + line = line.Trim(); + if (IsComment(line)) { - line = line.Trim(); - if (IsComment(line)) - { - continue; - } + continue; + } - if (IsSection(line)) - { - currentSection = Add(new SettingsDictionary(SplitSection(line))); - } - else if (IsKeyValue(line) && currentSection != null) - { - string[] kv = line.Split(new char[] { '=' }, 2); - currentSection.SetString(kv[0].Trim(), kv[1].Trim()); - } + if (IsSection(line)) + { + currentSection = Add(new SettingsDictionary(SplitSection(line))); + } + else if (IsKeyValue(line) && currentSection != null) + { + string[] kv = line.Split(['='], 2); + currentSection.SetString(kv[0].Trim(), kv[1].Trim()); } } + } - /// - /// Strip the outer '[' and ']' from the section name, e.g. '[DEFAULT]' becomes 'DEFAULT' - /// - /// the section name - /// - public static string SplitSection(string s) - { - return s.Trim('[', ']').Trim(); - } + /// + /// Strip the outer '[' and ']' from the section name, e.g. '[DEFAULT]' becomes 'DEFAULT' + /// + /// the section name + /// + public static string SplitSection(string s) + { + return s.Trim('[', ']').Trim(); + } - public static bool IsComment(string s) - { - if (s.Length < 1) - return false; - return '#' == s[0]; - } + public static bool IsComment(string s) + { + if (s.Length < 1) + return false; + return '#' == s[0]; + } - public static bool IsKeyValue(string s) - { - return s.IndexOf('=') != -1; - } + public static bool IsKeyValue(string s) + { + return s.Contains('='); + } - public static bool IsSection(string s) - { - if (s.Length < 2) - return false; - return s[0] == '[' && s[^1] == ']'; - } + public static bool IsSection(string s) + { + if (s.Length < 2) + return false; + return s[0] == '[' && s[^1] == ']'; + } - public SettingsDictionary Add(SettingsDictionary section) - { - _sections.AddLast(section); - return section; - } + public SettingsDictionary Add(SettingsDictionary section) + { + _sections.AddLast(section); + return section; + } - /// - /// Retrieve dictionaries by section name - /// (e.g. 'SESSION' would return a list containing each "[SESSION]" Dictionary) - /// - /// (case is ignored) - /// - public LinkedList Get(string sectionName) - { - LinkedList result = new(); - foreach (SettingsDictionary dict in _sections) - if (sectionName.ToUpperInvariant() == dict.Name.ToUpperInvariant()) - result.AddLast(dict); - return result; - } + /// + /// Retrieve dictionaries by section name + /// (e.g. 'SESSION' would return a list containing each "[SESSION]" Dictionary) + /// + /// (case is ignored) + /// + public LinkedList Get(string sectionName) + { + LinkedList result = new(); + foreach (SettingsDictionary dict in _sections) + if (sectionName.ToUpperInvariant() == dict.Name.ToUpperInvariant()) + result.AddLast(dict); + return result; } } diff --git a/QuickFIXn/Util/ExceptionExtensions.cs b/QuickFIXn/Util/ExceptionExtensions.cs index 18e623ba4..cf50e32d7 100644 --- a/QuickFIXn/Util/ExceptionExtensions.cs +++ b/QuickFIXn/Util/ExceptionExtensions.cs @@ -1,14 +1,13 @@ using System; -namespace QuickFix.Util +namespace QuickFix.Util; + +internal static class ExceptionExtensions { - internal static class ExceptionExtensions + public static string GetFullMessage(this Exception ex) { - public static string GetFullMessage(this Exception ex) - { - return ex.InnerException == null - ? ex.Message - : ex.Message + " --> " + ex.InnerException.GetFullMessage(); - } + return ex.InnerException == null + ? ex.Message + : ex.Message + " --> " + ex.InnerException.GetFullMessage(); } } diff --git a/QuickFIXn/Util/StringUtil.cs b/QuickFIXn/Util/StringUtil.cs index 333f1745c..d241ed46e 100644 --- a/QuickFIXn/Util/StringUtil.cs +++ b/QuickFIXn/Util/StringUtil.cs @@ -1,20 +1,18 @@ using System.Runtime.InteropServices; -namespace QuickFix.Util +namespace QuickFix.Util; + +public static class StringUtil { - public static class StringUtil - { - /// - /// Convert forward-slashes to backslashes (windows) or backslashes to forward-slashes (not windows) - /// and return the result - /// - /// - /// - public static string FixSlashes(string s) { - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? s.Replace('/', '\\') - : s.Replace('\\', '/'); - } + /// + /// Convert forward-slashes to backslashes (windows) or backslashes to forward-slashes (not windows) + /// and return the result + /// + /// + /// + public static string FixSlashes(string s) { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? s.Replace('/', '\\') + : s.Replace('\\', '/'); } } - diff --git a/QuickFIXn/Util/UtcDateTimeSerializer.cs b/QuickFIXn/Util/UtcDateTimeSerializer.cs index 1624b4f09..5982d8d5a 100644 --- a/QuickFIXn/Util/UtcDateTimeSerializer.cs +++ b/QuickFIXn/Util/UtcDateTimeSerializer.cs @@ -1,46 +1,42 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace QuickFix.Util +namespace QuickFix.Util; + +/// +/// Utility class for serializing/deserializing a date (which is strangely not-trivial in C#). +/// Don't use these in your client app. +/// +public static class UtcDateTimeSerializer { + private const string FORMAT = "yyyyMMdd-HH:mm:ss.ffffff K"; + /// - /// Utility class for serializing/deserializing a date (which is strangely not-trivial in C#). - /// Don't use these in your client app. + /// Not for use by client apps. /// - public static class UtcDateTimeSerializer + /// + /// + public static string ToString(DateTime d) { - private const string FORMAT = "yyyyMMdd-HH:mm:ss.ffffff K"; + return d.ToString(FORMAT); + } - /// - /// Not for use by client apps. - /// - /// - /// - static public string ToString(DateTime d) + /// + /// Not for use by client apps. + /// + /// + /// + public static DateTime FromString(string s) + { + try { - return d.ToString(FORMAT); + DateTime d = DateTime.ParseExact(s, FORMAT, + System.Globalization.CultureInfo.InvariantCulture, + System.Globalization.DateTimeStyles.AdjustToUniversal); + return d; } - - /// - /// Not for use by client apps. - /// - /// - /// - static public DateTime FromString(string s) + catch (Exception) { - try - { - DateTime d = DateTime.ParseExact(s, FORMAT, - System.Globalization.CultureInfo.InvariantCulture, - System.Globalization.DateTimeStyles.AdjustToUniversal); - return d; - } - catch (Exception) - { - return DateTime.MinValue; - } + return DateTime.MinValue; } } } diff --git a/QuickFIXn/Values.cs b/QuickFIXn/Values.cs index 8521df8a4..01f3b912a 100755 --- a/QuickFIXn/Values.cs +++ b/QuickFIXn/Values.cs @@ -1,14 +1,13 @@  -namespace QuickFix +namespace QuickFix; + +public class Values { - public class Values - { - public const string BeginString_FIXT11 = "FIXT.1.1"; - public const string BeginString_FIX50 = "FIX.5.0"; - public const string BeginString_FIX44 = "FIX.4.4"; - public const string BeginString_FIX43 = "FIX.4.3"; - public const string BeginString_FIX42 = "FIX.4.2"; - public const string BeginString_FIX41 = "FIX.4.1"; - public const string BeginString_FIX40 = "FIX.4.0"; - } + public const string BeginString_FIXT11 = "FIXT.1.1"; + public const string BeginString_FIX50 = "FIX.5.0"; + public const string BeginString_FIX44 = "FIX.4.4"; + public const string BeginString_FIX43 = "FIX.4.3"; + public const string BeginString_FIX42 = "FIX.4.2"; + public const string BeginString_FIX41 = "FIX.4.1"; + public const string BeginString_FIX40 = "FIX.4.0"; }