Quickfix / n,提取消息类型的最有效方法?

时间:2013-07-31 09:11:31

标签: c# quickfix fix-protocol

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来实现它,但到目前为止,我还没有找到一种方法来实现一个catch-all-remaining消息类型,以防我没有实现所有的OnMessage重载。 (请参阅相关问题:Quickfix, Is there a "catch-all" method OnMessage to handle incoming messages not handled by overloaded methods?)。

由于

3 个答案:

答案 0 :(得分:4)

不是你的头衔问题,而是其中的关键部分:

  

我尝试确定ToAdmin(...)中的消息类型,以便捕获传出的登录请求消息,以便我可以添加用户名和密码。

这里有一大堆代码(taken from this post to the QF/n mailing list):

    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));
            }
        }
    }

答案 1 :(得分:2)

这是使用我在另一个post中提到的想法的另一种方法。实际上,在两种方法中拆分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);
        }
    }
}

如果你不想通过从crack方法中删除throw new UnsupportedMessageType();来实现所有可能的消息处理程序,你也可以跳过破解而不是抛出异常。

另一个想法是拆分破解管理员/应用程序消息。

答案 2 :(得分:1)

在这种情况下,您可以在ToAdmin中执行此操作:

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

或者按照you mentioned

的其他答案中的说明使用MessageCracker

希望它有所帮助。