Quickfix/n, самый эффективный способ извлечь тип сообщения?

Каков наиболее эффективный способ в Quickfix/n 1.4 извлечь тип сообщения, как определено здесь: http://www.fixprotocol.org/FIXimate3.0/en/FIX.5.0SP2/messages_sorted_by_type.html

В настоящее время я использую var msgType = Message.GetMsgType(message.ToString());, что приводит к «A» для сообщения о входе в систему. Есть ли способ лучше? Я пытаюсь определить тип сообщения в ToAdmin(...), чтобы поймать исходящее сообщение с запросом на вход в систему, чтобы я мог добавить имя пользователя и пароль.

Я хотел бы сделать это через MessageCracker, но пока я не нашел способа реализовать перехват всех оставшихся типов сообщений на случай, если я не реализовал все перегрузки OnMessage. (См. соответствующий вопрос: Quickfix, существует ли универсальный метод OnMessage для обработки входящих сообщений, которые не обрабатываются перегруженными методами?).

Спасибо


person Matt    schedule 31.07.2013    source источник
comment
Это преждевременная оптимизация. Сначала заставьте это работать. Отложите исследования производительности до тех пор, пока не поймете, что они вам нужны.   -  person Grant Birchmeier    schedule 31.07.2013
comment
Извините, мой комментарий был слишком резким. Я хотел сказать, что если у вас есть проблемы с производительностью, эта небольшая штука с разбором строк вряд ли будет вашей основной причиной. Не беспокойтесь об оптимизации, пока у вас не будет доказательств того, что это проблема.   -  person Grant Birchmeier    schedule 31.07.2013
comment
Это совершенно не связано с производительностью. Мне нужно проверить, является ли исходящее сообщение входом в систему, чтобы добавить имя пользователя и пароль.   -  person Matt    schedule 31.07.2013
comment
Думаю, я истолковал ваше использование эффективного как производительность. Виноват.   -  person Grant Birchmeier    schedule 31.07.2013
comment
Не беспокойтесь, возможно, термин «эффективный» вводит в заблуждение. Спасибо за Ваш ответ   -  person Matt    schedule 31.07.2013


Ответы (3)


Не ваш заглавный вопрос, а его ключевая часть:

Я пытаюсь определить тип сообщения в ToAdmin(...), чтобы поймать исходящее сообщение с запросом на вход, чтобы я мог добавить имя пользователя и пароль.

Вот кусок кода, который в значительной степени прибивает его (взято из этого поста в список рассылки QF/n):

    public void ToAdmin(Message message, SessionID sessionID)
    {
        // Check message type
        if (message.Header.GetField(Tags.MsgType) == MsgType.LOGON)
        {
            // Yes it is logon message
            // Check if local variables YourUserName and YourPassword are set
            if (!string.IsNullOrEmpty(YourUserName) && !string.IsNullOrEmpty(YourPassword))
            {
                // Add Username and Password fields to logon message
                ((Logon) message).Set(new Username(YourUserName));
                ((Logon) message).Set(new Password(YourPassword));
            }
        }
    }
person Grant Birchmeier    schedule 31.07.2013
comment
Идеально. Именно то, что я искал. Я не знал о классе Tag. Большое спасибо. - person Matt; 31.07.2013

Вот еще один подход, использующий идею, о которой я упоминал в другом опубликовать. На самом деле очень просто разделить метод Crack на два метода и иметь обработчики OnMessageTo и OnMessageFrom. Модифицированная реализация вспомогательного класса MessageCracker выше знает о направление сообщения, хотя, конечно, можно улучшить.

В своем приложении реализуйте так (не полный код):

public class MyFixApplication: DirectedMessageCracker, Application
{
...

public void FromAdmin(Message msg, SessionID sessionId)
{
    CrackFrom(msg, sessionId);
}

public void ToAdmin(Message msg, SessionID sessionId)
{
    CrackTo(msg, sessionId);
}

public void OnMessageTo(Logon msg, SessionID sessionId)
{
    //Treat the outgoing message, set user, password, etc
}

public void OnMessageFrom(Allocation msg, SessionID sessionId)
{
    //Treat the incoming Allocation message
}
...and so on

И модифицированный MessageCracker:

using System;
using System.Collections.Generic;
using System.Reflection;

namespace QuickFix
{
    /// <summary>
    /// Helper class for delegating message types for various FIX versions to
    /// type-safe OnMessage methods, supports handling of incoming and outgoing messages separatelly
    /// </summary>
    public abstract class DirectedMessageCracker
    {
        private readonly Dictionary<Type, MethodInfo> _toHandlerMethods = new Dictionary<Type, MethodInfo>();
        private readonly Dictionary<Type, MethodInfo> _fromHandlerMethods = new Dictionary<Type, MethodInfo>();

        protected DirectedMessageCracker()
        {
            Initialize(this);
        }

        private void Initialize(Object messageHandler)
        {
            var handlerType = messageHandler.GetType();

            var methods = handlerType.GetMethods();
            foreach (var m in methods)
            {
                if (IsToHandlerMethod(m))
                    _toHandlerMethods[m.GetParameters()[0].ParameterType] = m;
                else if (IsFromHandlerMethod(m))
                    _fromHandlerMethods[m.GetParameters()[0].ParameterType] = m;
            }
        }

        static public bool IsToHandlerMethod(MethodInfo m)
        {
            return IsHandlerMethod("OnMessageTo", m);
        }

        static public bool IsFromHandlerMethod(MethodInfo m)
        {
            return IsHandlerMethod("OnMessageFrom", m);
        }

        static public bool IsHandlerMethod(string searchMethodName, MethodInfo m) 
        {
            return (m.IsPublic
                && m.Name.StartsWith(searchMethodName)
                && m.GetParameters().Length == 2
                && m.GetParameters()[0].ParameterType.IsSubclassOf(typeof(Message))
                && typeof(SessionID).IsAssignableFrom(m.GetParameters()[1].ParameterType)
                && m.ReturnType == typeof(void));
        }

        /// <summary>
        /// Process ("crack") a FIX message and call the registered handlers for that type, if any
        /// </summary>
        /// <param name="handlerMethods"></param>
        /// <param name="message"></param>
        /// <param name="sessionID"></param>
        private void Crack(IDictionary<Type, MethodInfo> handlerMethods, Message message, SessionID sessionID)
        {
            var messageType = message.GetType();
            MethodInfo handler;

            if (handlerMethods.TryGetValue(messageType, out handler))
                handler.Invoke(this, new object[] { message, sessionID });
            else
                throw new UnsupportedMessageType();
        }

        /// <summary>
        /// Process ("crack") an INCOMING FIX message and call the registered handlers for that type, if any
        /// </summary>
        /// <param name="message"></param>
        /// <param name="sessionID"></param>
        public void CrackFrom(Message message, SessionID sessionID)
        {
            Crack(_fromHandlerMethods, message, sessionID);
        }

        /// <summary>
        /// Process ("crack") an OUTGOING FIX message and call the registered handlers for that type, if any
        /// </summary>
        /// <param name="message"></param>
        /// <param name="sessionID"></param>
        public void CrackTo(Message message, SessionID sessionID)
        {
            Crack(_toHandlerMethods, message, sessionID);
        }
    }
}

Вы также можете пропустить взлом вместо создания исключения, если вы не хотите реализовывать все возможные обработчики сообщений, просто удалив throw new UnsupportedMessageType(); из метода взлома.

Другая идея состоит в том, чтобы разделить взломанные сообщения администратора/приложения.

person natenho    schedule 01.08.2013
comment
Большое спасибо за идею. Тем не менее, я отложил всю мысль об использовании MessageCracker, потому что в настоящее время построитель, похоже, не может создать код для добавленных пользовательских типов сообщений словаря данных xml. Без него я также не могу использовать MessageCracker и просто создаю сообщения самостоятельно. Все еще играю с ним, но пока не похоже, что методы сообщений правильно добавлены в соответствующее пространство имен FIXxx. - person Matt; 02.08.2013

В этом случае вы можете просто сделать это внутри ToAdmin:

var logonMessage = msg as Logon;
if (logonMessage != null)
{
    //Treat the logon message as you want
}

Или используйте MessageCracker, как объяснено в другом ответе, который not-handled">вы упомянули.

Надеюсь, поможет.

person natenho    schedule 31.07.2013
comment
Спасибо, но я нашел ответ Гранта немного более элегантным. Спасибо хоть. +1 - person Matt; 31.07.2013