Laden...

TCP Remoting: Die Assembly kann nicht geladen werden

Erstellt von FXBL vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.684 Views
F
FXBL Themenstarter:in
3 Beiträge seit 2018
vor 5 Jahren
TCP Remoting: Die Assembly kann nicht geladen werden

Hallo zusammen,

ich programmiere gerade eine "TradingPanel" für den Metatrader5. Im TradingPanel möchte ich Kauf- und Verkaufsaufträge erzeugen und über Metatrader5 an den Börsen platzieren.
Da im Metratrader nur eine sehr reduzierte Version von C++ als Programmiersprache zur Verfügung steht und der Metratrader performance-technisch nicht unbedingt der Beste ist, habe ich mir überlegt das TradingPanel in C#Net auszulagern. Als Schnittstelle für beide Applikationen (Metatrader + TradingPanel) dient eine unmanaged DLL. Leider kann Metatrader nur unmanaged verarbeiten (das funktioniert auch wunderbar). Die Kommunikation zwischen den beiden Applikationen soll über einen TCP Channel im .NET Remoting stattfinden. Beide Applikationen dienen als Client, ein Window Service fungiert als Server.
Soweit so gut, die Kommunikation von Metatrader > DLL > RemoteClient > RemoteObject > TradingPanel funktioniert einwandfrei. Jedoch habe ich bei der Kommunikation zurück, also vom TradePanel Richtung Metrader ein Problem. Kurz ausgeholt: der Metatrader hat kein richtiges EventHandling, also muss ich, wenn ich im TradePanel einen Kaufauftrag erzeugt habe, ein KeyDown Event im Metatrader erzeugen. Dies kann der Metatrader abfangen, ruft dann die DLL auf und soll dann die Kaufaufträge entgegennehmen.
An dieser Stelle kommt es zu einem Fehler:> Fehlermeldung:

mscorlib; Die Assembly "MT5Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" kann nicht gefunden werden.; ;
Server stack trace:
bei System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
bei System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
bei System.Runtime.Serialization.Formatters.Binary.BinaryConverter.TypeFromInfo(BinaryTypeEnum binaryTypeEnum, Object typeInformation, ObjectReader objectReader, BinaryAssemblyInfo assemblyInfo, InternalPrimitiveTypeE& primitiveTypeEnum, String& typeString, Type& type, Boolean& isVariant)
bei System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadArray(BinaryHeaderEnum binaryHeaderEnum)
bei System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
bei System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
bei System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
bei System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryResponseMessage(Stream inputStream, IMethodCallMessage reqMsg, Boolean bStrictBinding)
bei System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)

Exception rethrown at [0]:
bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
bei MT5Library.TerminalCommunication.Global.IRemoteObject.GetOrderQueue()
bei MT5Library.MT5Library.GetOrder(MT5Order& order, Int32 index); System.Runtime.Serialization.SerializationException: Die Assembly "MT5Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" kann nicht gefunden werden.

Server stack trace:
bei System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
bei System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
bei System.Runtime.Serialization.Formatters.Binary.BinaryConverter.TypeFromInfo(BinaryTypeEnum binaryTypeEnum, Object typeInformation, ObjectReader objectReader, BinaryAssemblyInfo assemblyInfo, InternalPrimitiveTypeE& primitiveTypeEnum, String& typeString, Type& type, Boolean& isVariant)
bei System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadArray(BinaryHeaderEnum binaryHeaderEnum)
bei System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
bei System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
bei System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
bei System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryResponseMessage(Stream inputStream, IMethodCallMessage reqMsg, Boolean bStrictBinding)
bei System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)

Exception rethrown at [0]:
bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
bei MT5Library.TerminalCommunication.Global.IRemoteObject.GetOrderQueue()
bei MT5Library.MT5Library.GetOrder(MT5Order& order, Int32 index)

die Methode in der DLL:


[DllExport("GetOrder", CallingConvention = CallingConvention.StdCall)]
        public static int GetOrder(ref MT5Order order, int index)
        {
            if (!Functions.ServiceIsRunning()) return 0;

            RemoteClient remote_client = new RemoteClient();
            IRemoteObject remote_proxy = null;

            try
            {
                remote_client.Connect();
                remote_proxy = remote_client.Remote_object;

                List<OrderWrapper> order_queue = remote_proxy.GetOrderQueue().ToList<OrderWrapper>();
                order = MT5ObjectsWrapper.UnWrapOrder(order_queue.ElementAt(index));

                remote_client.Disconnect();
            }
            catch (Exception e)
            {
                remote_client.Disconnect();
                
                Logger.AppendMessageToEventLog(Constants.LOGGER_MT5Terminal, e);

                return 0;
            }

            return 1;
        }

Der Abbruch ist an der Stelle

 List<OrderWrapper> order_queue = remote_proxy.GetOrderQueue().ToList<OrderWrapper>();

getOrderQueue:

public class RemoteObject : MarshalByRefObject, IRemoteObject
    {
        private string m_symbol_name;
        private SymbolInfoWrapper m_symbol_info;
        private AccountInfoWrapper m_account_info;
        private ChartWrapper m_chart;
        private List<OrderWrapper> m_order_queue;

        public event SymbolChangedDel SymbolChanged;
        public event NewSymbolSelectedDel NewSymbolSelected;

        public RemoteObject()
        {
            m_symbol_info = new SymbolInfoWrapper();
            m_account_info = new AccountInfoWrapper();
            m_chart = new ChartWrapper();
            m_order_queue = new List<OrderWrapper>();
        }

       .....

        public OrderWrapper[] GetOrderQueue()
        {
            return m_order_queue.ToArray<OrderWrapper>();
        }

RemoteClient:

public class RemoteClient
    {
        private TcpChannel m_channel;
        private IRemoteObject m_remote_object;

        public IRemoteObject Remote_object
        {
            get
            {
                return m_remote_object;
            }
        }

        public bool Connect()
        {
            try
            {
                m_channel = Channel.CreateTcpChannel(Constants.REMOTE_PORT_CLIENT, Constants.REMOTE_CHANNEL);
                ChannelServices.RegisterChannel(m_channel, false);
            }
            catch (Exception e)
            {
                Logger.AppendMessageToEventLog(Constants.LOGGER_MT5Terminal, e);
            }

            try
            {
                m_remote_object = (IRemoteObject)Activator.GetObject(typeof(IRemoteObject), Functions.GetServerAddress());
            }
            catch (Exception e)
            {
                Logger.AppendMessageToEventLog(Constants.LOGGER_MT5Terminal, e);

                return false;
            }

            return true;
        }

        public bool Disconnect()
        {
            try
            {
                if (m_channel != null)
                {
                    ChannelServices.UnregisterChannel(m_channel);
                }
            }
            catch (Exception e)
            {
                Logger.AppendMessageToEventLog(Constants.LOGGER_MT5Terminal, e);

                return false;
            }

            return true;
        }
    }

OrderWrapper Klasse:

 [Serializable]
    public class OrderWrapper
    {
        private string m_name;
        private double m_lots;
        private double m_limit;
        private double m_stop_loss;
        private double m_take_profit;
        private ENUM_ORDER_TYPE m_order_type;
        private ENUM_SYSTEM m_system;
        private int m_trade_id;

        public OrderWrapper()
        {

        }

        public string Name
        {
            get
            {
                return m_name;
            }

            set
            {
                m_name = value;
            }
        }

        public double Lots
        {
            get
            {
                return m_lots;
            }

            set
            {
                m_lots = value;
            }
        }
..........
    }

das Verrückte ist, in der DLL funktionieren alle anderen Methoden, auch diese (welche zurück an Metatrader geht):

[DllExport("GetOrderCount", CallingConvention = CallingConvention.StdCall)]
        public static int GetOrderCount()
        {
            if (!Functions.ServiceIsRunning()) return 0;

            RemoteClient remote_client = new RemoteClient();
            IRemoteObject remote_proxy = null;
            int order_count = 0;

            try
            {
                remote_client.Connect();
                remote_proxy = remote_client.Remote_object;
                order_count = remote_proxy.GetOrderCount();

                remote_client.Disconnect();
            }
            catch (Exception e)
            {
                remote_client.Disconnect();
                order_count = 0;
                
                Logger.AppendMessageToEventLog(Constants.LOGGER_MT5Terminal, e);
            }

            return order_count;
        }

Wenn ich die Methode in einer ConsolenAnwendung ausführe - dann klappt es.
Ich verstehe es nicht mehr! Ich habe bereits sämtliche Objekte serialisiert. Angehängt findet ihr die gesamte Projektmappe. Vielleicht hat jemand Lust und Zeit und kann mir ein paar Hinweise geben.

Ich danke euch!
Grüße

Projektmappe (leider 13MB groß) ((Link entfernt - Coffeebean)

Hinweis von Coffeebean vor 5 Jahren

Bitte beachte [Hinweis] Wie poste ich richtig?

F
FXBL Themenstarter:in
3 Beiträge seit 2018
vor 5 Jahren

Wenn ich statt des OrderWrapper Objektes einen string im RemoteObjekt zurückgebe, dann funktioniert es einwandfrei......

Ich frage mich warum er das OrderWrapper Objekt nicht verarbeiten kann?

16.827 Beiträge seit 2008
vor 5 Jahren

IIRC weil Remoting mit POCOs nicht sauber funktioniert, sondern IIRC MarshalByRefObject haben will.
Aber Jahre nichts mehr mit Remoting gemacht; benutzt man ja quasi nicht mehr, wenn man nicht muss.

F
FXBL Themenstarter:in
3 Beiträge seit 2018
vor 5 Jahren

Danke für die Antwort, was benutzt man stattdessen? Ich muss sagen, es läuft bisher eigentlich ganz stabil.

Also muss ich bei jedem Objekt ein Marshal mitgeben?

78 Beiträge seit 2016
vor 5 Jahren

Nach Remoting hätte man sicherlich WCF gesagt.
Man kann aber der Meinung sein, auch wenn man das .NET Framework verwendet, dass man das jetzt auch nicht mehr sagt.
Daher z.B. WebAPI (ASP.NET (core)) oder gRPC.

http://dotnet-paderborn.azurewebsites.net/