Changed sign key in library MtApiService: using MtApiKey.snk. Added logging into MtApiService and used ILMerge.Task to merge assemblies into one dll.

This commit is contained in:
vdemydiuk
2016-10-12 16:37:54 +03:00
parent e373f7976c
commit 1d407b5e16
31 changed files with 1050 additions and 528 deletions
+67
View File
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- -->
<!-- ILMerge project-specific settings. Almost never need to be set explicitly. -->
<!-- for details, see http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx -->
<!-- -->
<!-- *** set this file to Type=None, CopyToOutput=Never *** -->
<!-- If True, all copy local dependencies will also be merged from referenced projects whether they are referenced in the current project explicitly or not -->
<ILMergeTransitive>true</ILMergeTransitive>
<!-- Extra ILMerge library paths (semicolon-separated). Dont put your package dependencies here, they will be added automagically -->
<ILMergeLibraryPath></ILMergeLibraryPath>
<!-- The solution NuGet package directory if not standard 'SOLUTION\packages' -->
<ILMergePackagesPath></ILMergePackagesPath>
<!-- The merge order file name if differs from standard 'ILMergeOrder.txt' -->
<ILMergeOrderFile></ILMergeOrderFile>
<!-- The strong key file name if not specified in the project -->
<ILMergeKeyFile>MtApiKey.snk</ILMergeKeyFile>
<!-- The assembly version if differs for the version of the main assembly -->
<ILMergeAssemblyVersion></ILMergeAssemblyVersion>
<!-- added in Version 1.0.4 -->
<ILMergeFileAlignment></ILMergeFileAlignment>
<!-- added in Version 1.0.4, default=none -->
<ILMergeAllowDuplicateType></ILMergeAllowDuplicateType>
<!-- If the <see cref="CopyAttributes"/> is also set, any assembly-level attributes names that have the same type are copied over into the target assembly -->
<ILMergeAllowMultipleAssemblyLevelAttributes></ILMergeAllowMultipleAssemblyLevelAttributes>
<!-- See ILMerge documentation -->
<ILMergeAllowZeroPeKind></ILMergeAllowZeroPeKind>
<!-- The assembly level attributes of each input assembly are copied over into the target assembly -->
<ILMergeCopyAttributes></ILMergeCopyAttributes>
<!-- Creates a .pdb file for the output assembly and merges into it any .pdb files found for input assemblies, default=true -->
<ILMergeDebugInfo></ILMergeDebugInfo>
<!-- Target assembly will be delay signed -->
<ILMergeDelaySign></ILMergeDelaySign>
<!-- Types in assemblies other than the primary assembly have their visibility modified -->
<ILMergeInternalize></ILMergeInternalize>
<!-- The path name of the file that will be used to identify types that are not to have their visibility modified -->
<ILMergeInternalizeExcludeFile></ILMergeInternalizeExcludeFile>
<!-- XML documentation files are merged to produce an XML documentation file for the target assembly -->
<ILMergeXmlDocumentation></ILMergeXmlDocumentation>
<!-- External assembly references in the manifest of the target assembly will use full public keys (false) or public key tokens (true, default value) -->
<ILMergePublicKeyTokens></ILMergePublicKeyTokens>
<!-- Types with the same name are all merged into a single type in the target assembly -->
<ILMergeUnionMerge></ILMergeUnionMerge>
<!-- The version of the target framework, default 40 (works for 45 too) -->
<ILTargetPlatform></ILTargetPlatform>
</PropertyGroup>
</Project>
+4
View File
@@ -0,0 +1,4 @@
# this file contains the partial list of the merged assemblies in the merge order
# you can fill it from the obj\CONFIG\PROJECT.ilmerge generated on every build
# and finetune merge order to your satisfaction
+2 -5
View File
@@ -1,13 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
namespace MTApiService
{
public interface IMtApiServer
{
MtResponse SendCommand(MtCommand command);
IEnumerable<MtQuote> GetQuotes();
List<MtQuote> GetQuotes();
}
}
+55
View File
@@ -0,0 +1,55 @@
using System;
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using log4net.Repository.Hierarchy;
namespace MTApiService
{
public class LogConfigurator
{
private const string LogFileNameExtension = "txt";
public static void Setup(string profileName)
{
if (string.IsNullOrEmpty(profileName))
throw new ArgumentNullException();
var hierarchy = (Hierarchy) LogManager.GetRepository();
var patternLayout = new PatternLayout
{
ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"
};
patternLayout.ActivateOptions();
string filename = $"{DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss")}.{LogFileNameExtension}";
var roller = new RollingFileAppender
{
AppendToFile = false,
File = $@"{System.IO.Path.GetTempPath()}{profileName}\Logs\{filename}",
Layout = patternLayout,
PreserveLogFileNameExtension = true,
MaxSizeRollBackups = 5,
MaximumFileSize = "1GB",
RollingStyle = RollingFileAppender.RollingMode.Size,
StaticLogFileName = false
};
roller.ActivateOptions();
hierarchy.Root.AddAppender(roller);
var memory = new MemoryAppender();
memory.ActivateOptions();
hierarchy.Root.AddAppender(memory);
#if (DEBUG)
hierarchy.Root.Level = Level.Debug;
#else
hierarchy.Root.Level = Level.Info;
#endif
hierarchy.Configured = true;
}
}
}
+27 -3
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props" Condition="Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -14,6 +15,8 @@
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -35,12 +38,17 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>MtApiKey.pfx</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.5\lib\net40-full\log4net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
@@ -54,6 +62,7 @@
<ItemGroup>
<Compile Include="ICommandManager.cs" />
<Compile Include="IMetaTraderHandler.cs" />
<Compile Include="LogConfigurator.cs" />
<Compile Include="MtCommandEventArgs.cs" />
<Compile Include="IDisposableChannel.cs" />
<Compile Include="IMtApiServer.cs" />
@@ -78,13 +87,28 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="MtApiKey.pfx" />
<None Include="ILMerge.props">
<SubType>Designer</SubType>
</None>
<None Include="MtApiKey.snk" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="ILMergeOrder.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.props'))" />
<Error Condition="!Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets'))" />
</Target>
<Import Project="..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets" Condition="Exists('..\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
Binary file not shown.
BIN
View File
Binary file not shown.
+11 -14
View File
@@ -1,20 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace MTApiService
{
class MtApiProxy : DuplexClientBase<IMtApi>, IMtApi, IDisposable
internal class MtApiProxy : DuplexClientBase<IMtApi>, IMtApi, IDisposable
{
public MtApiProxy(InstanceContext callbackContext, Binding binding,
EndpointAddress remoteAddress)
public MtApiProxy(InstanceContext callbackContext, Binding binding, EndpointAddress remoteAddress)
: base(callbackContext, binding, remoteAddress)
{
base.InnerDuplexChannel.Faulted += new EventHandler(InnerDuplexChannel_Faulted);
base.InnerDuplexChannel.Open();
InnerDuplexChannel.Faulted += InnerDuplexChannel_Faulted;
InnerDuplexChannel.Open();
}
#region IMtApi Members
@@ -34,7 +31,7 @@ namespace MTApiService
return Channel.SendCommand(command);
}
public IEnumerable<MtQuote> GetQuotes()
public List<MtQuote> GetQuotes()
{
return Channel.GetQuotes();
}
@@ -47,19 +44,19 @@ namespace MTApiService
{
try
{
this.Close();
Close();
}
catch (CommunicationException)
{
this.Abort();
Abort();
}
catch (TimeoutException)
{
this.Abort();
Abort();
}
catch (Exception)
{
this.Abort();
Abort();
}
}
@@ -68,9 +65,9 @@ namespace MTApiService
#region Private Methods
private void InnerDuplexChannel_Faulted(object sender, EventArgs e)
{
if (Faulted != null)
Faulted(this, e);
Faulted?.Invoke(this, e);
}
#endregion
#region Events
+108 -35
View File
@@ -1,8 +1,8 @@
using System;
using System.Diagnostics;
using System.Collections;
using System.ServiceModel;
using System.Collections.Generic;
using log4net;
namespace MTApiService
{
@@ -14,6 +14,8 @@ namespace MTApiService
public delegate void MtQuoteHandler(MtQuote quote);
#region Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtClient));
private MtApiProxy _proxy;
private bool _isConnected;
#endregion
@@ -21,7 +23,7 @@ namespace MTApiService
#region Public Methods
public void Open(string host, int port)
{
Debug.WriteLine("[INFO] MtClient::Open");
Log.DebugFormat("Open: begin. host = {0}, port = {1}", host, port);
if (string.IsNullOrEmpty(host))
throw new ArgumentNullException(nameof(host), "host is null or empty");
@@ -32,7 +34,10 @@ namespace MTApiService
var urlService = $"net.tcp://{host}:{port}/{ServiceName}";
if (_proxy != null)
{
Log.Warn("Open: end. _proxy is not null.");
return;
}
var bind = new NetTcpBinding(SecurityMode.None)
{
@@ -52,17 +57,24 @@ namespace MTApiService
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
_proxy.Faulted += ProxyFaulted;
Log.Debug("Open: end.");
}
public void Open(int port)
{
Log.DebugFormat("Open: begin. port = {0}", port);
if (port < 0 || port > 65536)
throw new ArgumentOutOfRangeException(nameof(port), "port value is invalid");
var urlService = $"net.pipe://localhost/{ServiceName}_{port}";
if (_proxy != null)
{
Log.Warn("Open: end. _proxy is not null.");
return;
}
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
{
@@ -82,11 +94,13 @@ namespace MTApiService
_proxy = new MtApiProxy(new InstanceContext(this), bind, new EndpointAddress(urlService));
_proxy.Faulted += ProxyFaulted;
Log.Debug("Open: end.");
}
public void Close()
{
Debug.WriteLine("[INFO] MtClient::Close");
Log.Debug("Close: begin.");
if (_proxy != null)
{
@@ -96,35 +110,52 @@ namespace MTApiService
}
_isConnected = false;
Log.Debug("Close: end.");
}
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
public void Connect()
{
Debug.WriteLine("[INFO] MtClient::Connect");
Log.Debug("Connect: begin.");
if (_proxy == null)
{
Log.Error("Connect: _proxy is not defined.");
throw new CommunicationException("Connection failed to service. Proxy is not defined (needs to call Open)");
}
if (_isConnected)
{
Log.Warn("Connected: end. Client is already connected.");
return;
}
try
{
if (_proxy != null && _isConnected)
return;
_isConnected = _proxy.Connect();
if (_isConnected == false)
throw new Exception("Connected failed");
}
catch (Exception ex)
{
Debug.WriteLine("[ERROR] MtClient::Connect: {0}", ex.Message);
Log.ErrorFormat("Connect: Exception - {0}", ex.Message);
Close();
throw new CommunicationException("Connection failed to service");
throw new CommunicationException($"Connection failed to service. {ex.Message}");
}
if (_isConnected == false)
{
Log.Error("Connect: end. Connection failed.");
throw new CommunicationException("Connection failed");
}
Log.Debug("Connect: end.");
}
public void Disconnect()
{
Debug.WriteLine("[INFO] MtClient::Disconnect");
Log.Debug("Disconnect: begin.");
try
{
@@ -134,26 +165,40 @@ namespace MTApiService
}
catch (Exception ex)
{
Debug.WriteLine("[ERROR] MtClient::Disconnect: {0}", ex.Message);
Log.ErrorFormat("Disconnect: Exception - {0}", ex.Message);
Close();
}
Log.Debug("Disconnect: end.");
}
public MtResponse SendCommand(int commandType, ArrayList commandParameters)
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
public MtResponse SendCommand(int commandType, ArrayList parameters)
{
Debug.WriteLine("[INFO] MtClient::SendCommand: commandType = {0}", commandType);
Log.DebugFormat("SendCommand: begin. commandType = {0}, parameters count = {1}", commandType, parameters?.Count);
MtResponse result = null;
MtResponse result;
if (_proxy == null)
{
Log.Error("SendCommand: Proxy is not defined.");
throw new CommunicationException("Proxy is not defined.");
}
if (_isConnected == false)
{
Log.Error("SendCommand: Client is not connected.");
throw new CommunicationException("Client is not connected.");
}
try
{
if (_proxy != null && _isConnected)
result = _proxy.SendCommand(new MtCommand(commandType, commandParameters));
result = _proxy.SendCommand(new MtCommand(commandType, parameters));
}
catch (Exception ex)
{
Debug.WriteLine("[ERROR] MtClient::SendCommand: {0}", ex.Message);
Log.ErrorFormat("SendCommand: Exception - {0}", ex.Message);
Close();
@@ -163,27 +208,41 @@ namespace MTApiService
return result;
}
/// <exception cref="CommunicationException">Thrown when connection failed</exception>
public IEnumerable<MtQuote> GetQuotes()
{
Debug.WriteLine("[INFO] MtClient::GetQuotes");
Log.Debug("GetQuotes: begin.");
IEnumerable<MtQuote> result = null;
if (_proxy == null)
{
Log.Warn("GetQuotes: end. _proxy is not defined.");
return null;
}
if (_isConnected == false)
{
Log.Warn("GetQuotes: end. Client is not connected.");
return null;
}
List<MtQuote> result;
try
{
if (_proxy != null && _isConnected)
result = _proxy.GetQuotes();
result = _proxy.GetQuotes();
}
catch (Exception ex)
{
Debug.WriteLine("[ERROR] MtClient::GetQuotes: {0}", ex.Message);
Log.ErrorFormat("GetQuotes: Exception - {0}", ex.Message);
Close();
throw new CommunicationException("Service connection failed");
throw new CommunicationException($"Service connection failed! {ex.Message}");
}
return result;;
Log.DebugFormat("GetQuotes: end. quotes count = {0}", result?.Count);
return result;
}
#endregion
@@ -192,40 +251,51 @@ namespace MTApiService
public void OnQuoteUpdate(MtQuote quote)
{
Log.DebugFormat("OnQuoteUpdate: begin. quote = {0}", quote);
if (quote == null) return;
QuoteUpdated?.Invoke(quote);
Debug.WriteLine("[INFO] MtClient::OnQuoteUpdate: " + quote);
Log.Debug("OnQuoteUpdate: end.");
}
public void OnQuoteAdded(MtQuote quote)
{
Debug.WriteLine("[INFO] MtClient::OnQuoteAdded");
Log.DebugFormat("OnQuoteAdded: begin. quote = {0}", quote);
QuoteAdded?.Invoke(quote);
Log.Debug("OnQuoteAdded: end.");
}
public void OnQuoteRemoved(MtQuote quote)
{
Debug.WriteLine("[INFO] MtClient::OnQuoteRemoved");
Log.DebugFormat("OnQuoteRemoved: begin. quote = {0}", quote);
QuoteRemoved?.Invoke(quote);
Log.Debug("OnQuoteRemoved: end.");
}
public void OnServerStopped()
{
Debug.WriteLine("[INFO] MtClient::OnServerStopped");
Log.Debug("OnServerStopped: begin.");
Close();
ServerDisconnected?.Invoke(this, EventArgs.Empty);
Log.Debug("OnServerStopped: end.");
}
public void OnMtEvent(MtEvent mtEvent)
{
Log.DebugFormat("OnMtEvent: begin. event = {0}", mtEvent);
MtEventReceived?.Invoke(this, new MtEventArgs(mtEvent));
Log.Debug("OnMtEvent: end.");
}
#endregion
@@ -239,11 +309,12 @@ namespace MTApiService
private void ProxyFaulted(object sender, EventArgs e)
{
Debug.WriteLine("[INFO] MtClient::ProxyFaulted");
Log.Debug("ProxyFaulted: begin.");
Close();
ServerFailed?.Invoke(this, EventArgs.Empty);
Log.Debug("ProxyFaulted: end.");
}
#endregion
@@ -252,9 +323,11 @@ namespace MTApiService
public void Dispose()
{
Debug.WriteLine("[INFO] MtClient::Dispose");
Log.Debug("Dispose: begin.");
Close();
Log.Debug("Dispose: end.");
}
#endregion
+5 -5
View File
@@ -1,8 +1,4 @@
using System;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.Runtime.Serialization;
using System.Collections;
namespace MTApiService
@@ -22,5 +18,9 @@ namespace MTApiService
[DataMember]
public ArrayList Parameters { get; private set; }
public override string ToString()
{
return $"CommandType = {CommandType}";
}
}
}
Regular → Executable
+11 -3
View File
@@ -1,4 +1,5 @@
using System.Threading;
using System;
using System.Threading;
namespace MTApiService
{
@@ -10,6 +11,9 @@ namespace MTApiService
public MtCommandTask(MtCommand command)
{
if (command == null)
throw new ArgumentNullException(nameof(command));
Command = command;
}
@@ -20,7 +24,7 @@ namespace MTApiService
_responseWaiter.WaitOne(time);
lock (_locker)
{
return _result;
return _result;
}
}
@@ -32,6 +36,10 @@ namespace MTApiService
}
_responseWaiter.Set();
}
public override string ToString()
{
return $"Command = {Command}";
}
}
}
+1 -5
View File
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MTApiService
{
public class MtConnectionProfile
+45 -11
View File
@@ -1,31 +1,50 @@
using System;
using System.Collections.Generic;
using log4net;
namespace MTApiService
{
internal class MtCommandExecutorManager : ICommandManager
{
#region Private Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtCommandExecutorManager));
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
private readonly object _locker = new object();
#endregion
#region Public Methods
public void Stop()
{
Log.Debug("Stop: begin.");
lock (_locker)
{
_commandExecutors.Clear();
_commandTasks.Clear();
}
Log.Debug("Stop: end.");
}
public void AddCommandExecutor(MtExpert commandExecutor)
{
if (commandExecutor == null)
return;
throw new ArgumentNullException(nameof(commandExecutor));
Log.DebugFormat("AddCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
var notify = false;
lock (_locker)
{
if (_commandExecutors.Contains(commandExecutor))
{
Log.Warn("AddCommandExecutor: end. Command executor already exist.");
return;
}
_commandExecutors.Add(commandExecutor);
if (_commandTasks.Count > 0)
@@ -41,18 +60,25 @@ namespace MTApiService
{
NotifyCommandReady();
}
Log.Debug("AddCommandExecutor: end.");
}
public void RemoveCommandExecutor(MtExpert commandExecutor)
{
if (commandExecutor == null)
return;
throw new ArgumentNullException(nameof(commandExecutor));
Log.DebugFormat("RemoveCommandExecutor: begin. commandExecutor = {0}", commandExecutor);
var notify = false;
lock (_locker)
{
if (_commandExecutors.Contains(commandExecutor) == false)
{
Log.Warn("RemoveCommandExecutor: end. Command executor is not exist in collection.");
return;
}
_commandExecutors.Remove(commandExecutor);
if (_commandTasks.Count > 0)
@@ -68,23 +94,31 @@ namespace MTApiService
{
NotifyCommandReady();
}
Log.Debug("RemoveCommandExecutor: end.");
}
public void EnqueueCommandTask(MtCommandTask task)
{
if (task == null)
return;
throw new ArgumentNullException(nameof(task));
Log.DebugFormat("EnqueueCommandTask: begin. task = {0}", task);
lock (_locker)
{
_commandTasks.Enqueue(task);
_commandTasks.Enqueue(task);
}
NotifyCommandReady();
Log.Debug("EnqueueCommandTask: end.");
}
public MtCommandTask DequeueCommandTask()
{
Log.Debug("DequeueCommandTask: called.");
lock (_locker)
{
return _commandTasks.Count > 0 ? _commandTasks.Dequeue() : null;
@@ -96,6 +130,8 @@ namespace MTApiService
#region Private Methods
private void NotifyCommandReady()
{
Log.Debug("NotifyCommandReady: begin.");
var commandExecutors = new List<MtExpert>();
lock (_locker)
{
@@ -106,10 +142,14 @@ namespace MTApiService
{
executor.NotifyCommandReady();
}
Log.DebugFormat("NotifyCommandReady: end. Notified executor count = {0}", commandExecutors.Count);
}
private void CommandExecutor_CommandExecuted(object sender, EventArgs e)
{
Log.Debug("CommandExecutor_CommandExecuted: begin.");
var notify = false;
lock (_locker)
{
@@ -124,14 +164,8 @@ namespace MTApiService
NotifyCommandReady();
}
Log.Debug("CommandExecutor_CommandExecuted: end.");
}
#endregion
#region Private Fields
private readonly List<MtExpert> _commandExecutors = new List<MtExpert>();
private readonly Queue<MtCommandTask> _commandTasks = new Queue<MtCommandTask>();
private readonly object _locker = new object();
#endregion
}
}
+93 -68
View File
@@ -1,4 +1,5 @@
using System;
using log4net;
namespace MTApiService
{
@@ -6,20 +7,103 @@ namespace MTApiService
{
public delegate void MtQuoteHandler(MtExpert expert, MtQuote quote);
#region Private Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtExpert));
private readonly IMetaTraderHandler _mtHadler;
private MtCommandTask _commandTask;
private ICommandManager _commandManager;
private readonly object _locker = new object();
#endregion
#region Public Methods
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
{
if (mtHandler == null)
throw new ArgumentNullException(nameof(mtHandler));
Quote = quote;
Handle = handle;
_mtHadler = mtHandler;
}
public void Deinit()
{
Log.Debug("Deinit: begin.");
IsEnable = false;
FireOnDeinited();
Log.Debug("Deinit: end.");
}
public void SendResponse(MtResponse response)
{
Log.DebugFormat("SendResponse: begin. response = {0}", response);
_commandTask.SetResult(response);
_commandTask = null;
FireOnCommandExecuted();
Log.Debug("SendResponse: end.");
}
public int GetCommandType()
{
Log.Debug("GetCommandType: called.");
var commandManager = CommandManager;
if (commandManager != null)
{
_commandTask = commandManager.DequeueCommandTask();
}
return _commandTask?.Command?.CommandType ?? 0;
}
public object GetCommandParameter(int index)
{
Log.DebugFormat("GetCommandType: called. index = {0}", index);
var command = _commandTask?.Command;
if (command?.Parameters != null && index >= 0 && index < command.Parameters.Count)
{
return command.Parameters[index];
}
return null;
}
public void SendEvent(MtEvent mtEvent)
{
Log.DebugFormat("SendEvent: begin. event = {0}", mtEvent);
FireOnMtEvent(mtEvent);
Log.Debug("SendEvent: end.");
}
public override string ToString()
{
return $"ExpertHandle = {Handle}";
}
#endregion
#region Properties
private MtQuote _quote;
public MtQuote Quote
public MtQuote Quote
{
get
{
lock (_locker)
{
return _quote;
return _quote;
}
}
set
{
lock(_locker)
lock (_locker)
{
_quote = value;
}
@@ -28,7 +112,7 @@ namespace MTApiService
}
}
public int Handle { get; private set; }
public int Handle { get; }
private bool _isEnable = true;
public bool IsEnable
@@ -69,73 +153,21 @@ namespace MTApiService
#endregion
#region Public Methods
public MtExpert(int handle, MtQuote quote, IMetaTraderHandler mtHandler)
{
Quote = quote;
Handle = handle;
_mtHadler = mtHandler;
}
public void Deinit()
{
IsEnable = false;
FireOnDeinited();
}
public void SendResponse(MtResponse response)
{
_commandTask.SetResult(response);
_commandTask = null;
FireOnCommandExecuted();
}
public int GetCommandType()
{
var commandManager = CommandManager;
if (commandManager != null)
{
_commandTask = commandManager.DequeueCommandTask();
}
return _commandTask != null && _commandTask.Command != null ? _commandTask.Command.CommandType : 0;
}
public object GetCommandParameter(int index)
{
if (_commandTask != null)
{
var command = _commandTask.Command;
if (command != null && command.Parameters != null
&& index >= 0 && index < command.Parameters.Count)
{
return command.Parameters[index];
}
}
return null;
}
public void SendEvent(MtEvent mtEvent)
{
FireOnMtEvent(mtEvent);
}
#endregion
#region IMtCommandExecutor
public void NotifyCommandReady()
{
Log.Debug("NotifyCommandReady: begin.");
SendTickToMetaTrader();
Log.Debug("NotifyCommandReady: end.");
}
#endregion
#region Private Methods
private void SendTickToMetaTrader()
{
if (_mtHadler != null)
{
_mtHadler.SendTickToMetaTrader(Handle);
}
_mtHadler.SendTickToMetaTrader(Handle);
}
private void FireOnQuoteChanged(MtQuote quote)
@@ -165,12 +197,5 @@ namespace MTApiService
public event EventHandler CommandExecuted;
public event EventHandler<MtEventArgs> OnMtEvent;
#endregion
#region Private Fields
private readonly IMetaTraderHandler _mtHadler;
private MtCommandTask _commandTask;
private ICommandManager _commandManager;
private readonly object _locker = new object();
#endregion
}
}
+1 -5
View File
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace MTApiService
{
+1 -5
View File
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace MTApiService
{
+1 -6
View File
@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace MTApiService
{
+1 -5
View File
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization;
namespace MTApiService
{
+15 -18
View File
@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace MTApiService
@@ -10,34 +7,34 @@ namespace MTApiService
public class MtMqlTradeRequest
{
[DataMember]
public int Action { get; set; }
public int Action { get; set; }
[DataMember]
public uint Magic { get; set; }
public uint Magic { get; set; }
[DataMember]
public uint Order { get; set; }
public uint Order { get; set; }
[DataMember]
public string Symbol { get; set; }
public string Symbol { get; set; }
[DataMember]
public double Volume { get; set; }
public double Volume { get; set; }
[DataMember]
public double Price { get; set; }
public double Price { get; set; }
[DataMember]
public double Stoplimit { get; set; }
public double Stoplimit { get; set; }
[DataMember]
public double Sl { get; set; }
public double Sl { get; set; }
[DataMember]
public double Tp { get; set; }
public double Tp { get; set; }
[DataMember]
public uint Deviation { get; set; }
public uint Deviation { get; set; }
[DataMember]
public int Type { get; set; }
public int Type { get; set; }
[DataMember]
public int Type_filling { get; set; }
public int Type_filling { get; set; }
[DataMember]
public int Type_time { get; set; }
public int Type_time { get; set; }
[DataMember]
public DateTime Expiration { get; set; }
public DateTime Expiration { get; set; }
[DataMember]
public string Comment { get; set; }
public string Comment { get; set; }
}
}
+89 -83
View File
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32;
using System.Diagnostics;
@@ -9,12 +7,12 @@ namespace MTApiService
{
public class MtRegistryManager
{
private const string SOFTWARE = "Software";
private const string APP_NAME = "MtApi";
private const string PROFILES_REGKEY = "ConnectionProfiles";
private const string HOST_REGVALUE_NAME = "Host";
private const string PORT_REGVALUE_NAME = "Port";
private const string SIGNATURE_REGVALUE_NAME = "MtSignature";
private const string Software = "Software";
private const string AppName = "MtApi";
private const string ProfilesRegkey = "ConnectionProfiles";
private const string HostRegvalueName = "Host";
private const string PortRegvalueName = "Port";
private const string SignatureRegvalueName = "MtSignature";
#region Public Methods
public static IEnumerable<MtConnectionProfile> LoadConnectionProfiles()
@@ -53,12 +51,12 @@ namespace MTApiService
string signature = null;
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
if (softwareRegKey != null)
{
using (softwareRegKey)
{
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
if (appRegKey != null)
{
using (appRegKey)
@@ -73,7 +71,7 @@ namespace MTApiService
{
using (numberKey)
{
signature = numberKey.GetValue(SIGNATURE_REGVALUE_NAME).ToString();
signature = numberKey.GetValue(SignatureRegvalueName).ToString();
}
}
}
@@ -94,7 +92,7 @@ namespace MTApiService
return null;
}
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
var softwareRgKey = Registry.CurrentUser.OpenSubKey(Software, true);
if (softwareRgKey == null)
return null;
@@ -105,35 +103,33 @@ namespace MTApiService
{
//app name
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
if (appRegKey == null)
var appRegKey = softwareRgKey.OpenSubKey(AppName, true) ?? softwareRgKey.CreateSubKey(AppName);
if (appRegKey != null)
{
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
}
using (appRegKey)
{
//account name
var accountKey = appRegKey.OpenSubKey(accountName, true);
if (accountKey == null)
using (appRegKey)
{
accountKey = appRegKey.CreateSubKey(accountName);
}
//account name
var accountKey = appRegKey.OpenSubKey(accountName, true) ?? appRegKey.CreateSubKey(accountName);
using (accountKey)
{
//account number
var numberKey = accountKey.OpenSubKey(accountNumber, true);
if (numberKey == null)
if (accountKey != null)
{
numberKey = accountKey.CreateSubKey(accountNumber);
}
using (accountKey)
{
//account number
var numberKey = accountKey.OpenSubKey(accountNumber, true) ??
accountKey.CreateSubKey(accountNumber);
using (numberKey)
{
numberKey.SetValue(SIGNATURE_REGVALUE_NAME, signature);
if (numberKey != null)
{
using (numberKey)
{
numberKey.SetValue(SignatureRegvalueName, signature);
retVal = numberKey.ToString();
retVal = numberKey.ToString();
}
}
}
}
}
}
@@ -142,20 +138,19 @@ namespace MTApiService
return retVal;
}
public static bool ExportKey(string RegKey, string SavePath)
public static bool ExportKey(string regKey, string savePath)
{
string path = "\"" + SavePath + "\"";
string key = "\"" + RegKey + "\"";
var path = $"\"{savePath}\"";
var key = $"\"{regKey}\"";
Process proc = new Process();
var proc = new Process();
try
{
proc.StartInfo.FileName = "regedit.exe";
proc.StartInfo.UseShellExecute = false;
proc = Process.Start("regedit.exe", "/e " + path + " " + key + "");
if (proc != null)
proc.WaitForExit();
proc?.WaitForExit();
}
catch(Exception)
{
@@ -163,8 +158,7 @@ namespace MTApiService
}
finally
{
if (proc != null)
proc.Dispose();
proc?.Dispose();
}
return true;
@@ -177,33 +171,38 @@ namespace MTApiService
{
List<MtConnectionProfile> profiles = null;
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
if (softwareRegKey != null)
{
using (softwareRegKey)
{
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
if (appRegKey != null)
{
using (appRegKey)
{
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
if (profilesRegKey != null)
{
using (profilesRegKey)
{
profiles = new List<MtConnectionProfile>();
foreach (string profileNameKey in profilesRegKey.GetSubKeyNames())
foreach (var profileNameKey in profilesRegKey.GetSubKeyNames())
{
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileNameKey))
var tempKey = profilesRegKey.OpenSubKey(profileNameKey);
if (tempKey != null)
{
var profile = new MtConnectionProfile(profileNameKey);
using (tempKey)
{
var profile = new MtConnectionProfile(profileNameKey)
{
Host = tempKey.GetValue(HostRegvalueName).ToString(),
Port = (int) tempKey.GetValue(PortRegvalueName)
};
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
profiles.Add(profile);
profiles.Add(profile);
}
}
}
}
@@ -220,27 +219,33 @@ namespace MTApiService
{
MtConnectionProfile profile = null;
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
if (softwareRegKey != null)
{
using (softwareRegKey)
{
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
if (appRegKey != null)
{
using (appRegKey)
{
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
if (profilesRegKey != null)
{
using (profilesRegKey)
{
using (RegistryKey tempKey = profilesRegKey.OpenSubKey(profileName))
var tempKey = profilesRegKey.OpenSubKey(profileName);
if (tempKey != null)
{
profile = new MtConnectionProfile(profileName);
using (tempKey)
{
profile = new MtConnectionProfile(profileName)
{
Host = tempKey.GetValue(HostRegvalueName).ToString(),
Port = (int) tempKey.GetValue(PortRegvalueName)
};
profile.Host = tempKey.GetValue(HOST_REGVALUE_NAME).ToString();
profile.Port = (int)tempKey.GetValue(PORT_REGVALUE_NAME);
}
}
}
}
@@ -254,7 +259,7 @@ namespace MTApiService
private static void SaveConnectionProfileToRegistry(MtConnectionProfile profile)
{
RegistryKey softwareRgKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
var softwareRgKey = Registry.CurrentUser.OpenSubKey(Software, true);
if (softwareRgKey == null)
return;
@@ -262,29 +267,30 @@ namespace MTApiService
using (softwareRgKey)
{
//app name
var appRegKey = softwareRgKey.OpenSubKey(APP_NAME, true);
if (appRegKey == null)
var appRegKey = softwareRgKey.OpenSubKey(AppName, true) ?? softwareRgKey.CreateSubKey(AppName);
if (appRegKey != null)
{
appRegKey = softwareRgKey.CreateSubKey(APP_NAME);
}
using (appRegKey)
{
//ConnectionProfiles key
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
if (profilesRegKey == null)
using (appRegKey)
{
profilesRegKey = appRegKey.CreateSubKey(PROFILES_REGKEY);
}
//ConnectionProfiles key
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true) ??
appRegKey.CreateSubKey(ProfilesRegkey);
using (profilesRegKey)
{
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
using (profileKey)
if (profilesRegKey != null)
{
profileKey.SetValue(HOST_REGVALUE_NAME, profile.Host);
profileKey.SetValue(PORT_REGVALUE_NAME, profile.Port);
using (profilesRegKey)
{
var profileKey = profilesRegKey.CreateSubKey(profile.Name);
if (profileKey != null)
{
using (profileKey)
{
profileKey.SetValue(HostRegvalueName, profile.Host);
profileKey.SetValue(PortRegvalueName, profile.Port);
}
}
}
}
}
}
@@ -293,19 +299,19 @@ namespace MTApiService
private static void DeleteConnectionProfileFromRegistry(string profileName)
{
var softwareRegKey = Registry.CurrentUser.OpenSubKey(SOFTWARE, true);
var softwareRegKey = Registry.CurrentUser.OpenSubKey(Software, true);
if (softwareRegKey == null)
return;
using (softwareRegKey)
{
var appRegKey = softwareRegKey.OpenSubKey(APP_NAME, true);
var appRegKey = softwareRegKey.OpenSubKey(AppName, true);
if (appRegKey == null)
return;
using (appRegKey)
{
var profilesRegKey = appRegKey.OpenSubKey(PROFILES_REGKEY, true);
var profilesRegKey = appRegKey.OpenSubKey(ProfilesRegkey, true);
if (profilesRegKey == null)
return;
+66
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Collections;
using System.Globalization;
namespace MTApiService
{
@@ -35,6 +36,11 @@ namespace MTApiService
public int Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -49,6 +55,11 @@ namespace MTApiService
public long Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -63,6 +74,11 @@ namespace MTApiService
public ulong Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -77,6 +93,11 @@ namespace MTApiService
public double Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString(CultureInfo.CurrentCulture);
}
}
[DataContract]
@@ -91,6 +112,11 @@ namespace MTApiService
public string Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value;
}
}
[DataContract]
@@ -105,6 +131,11 @@ namespace MTApiService
public bool Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -119,6 +150,11 @@ namespace MTApiService
public double[] Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -133,6 +169,11 @@ namespace MTApiService
public int[] Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -147,6 +188,11 @@ namespace MTApiService
public long[] Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -161,6 +207,11 @@ namespace MTApiService
public ArrayList Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -175,6 +226,11 @@ namespace MTApiService
public MtMqlRates[] Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -189,6 +245,11 @@ namespace MTApiService
public MtMqlTick Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
[DataContract]
@@ -203,6 +264,11 @@ namespace MTApiService
public MtMqlBookInfo[] Value { get; private set; }
public override object GetValue() { return Value; }
public override string ToString()
{
return Value.ToString();
}
}
}
+193 -107
View File
@@ -3,17 +3,26 @@ using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Net;
using System.Diagnostics;
using System.ServiceModel.Channels;
using System.Net.Sockets;
using log4net;
namespace MTApiService
{
internal class MtServer : IDisposable, IMtApiServer
{
#region Constants
private const int WAIT_RESPONSE_TIME = 40000; // 40 sec
private const int STOP_EXPERT_INTERVAL = 1000; // 1 sec
private const int WaitResponseTime = 40000; // 40 sec
private const int StopExpertInterval = 1000; // 1 sec
#endregion
#region Fields
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServer));
private readonly MtService _service;
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
private readonly List<MtExpert> _experts = new List<MtExpert>();
#endregion
#region ctor
@@ -25,99 +34,126 @@ namespace MTApiService
#endregion
#region Properties
public int Port { get; private set; }
public int Port { get; }
#endregion
#region Public Methods
public void Start()
{
Log.Debug("Start: begin");
var hostsInitialized = InitHosts(Port);
if (hostsInitialized == false)
{
Debug.WriteLine("Start: InitHosts failed. ");
}
Log.DebugFormat("Start: end. hostsInitialized = {0}", hostsInitialized);
}
private bool InitHosts(int port)
{
Log.DebugFormat("InitHosts: begin. port = {0}", port);
int count;
lock (_hosts)
{
if (_hosts.Count > 0)
{
Log.Info("InitHosts: end. Host's has been initialized");
return false;
}
//init local pipe host
string localUrl = CreateConnectionAddress(null, port, true);
ServiceHost localServiceHost = CreateServiceHost(localUrl, true);
var localUrl = CreateConnectionAddress(null, port, true);
var localServiceHost = CreateServiceHost(localUrl, true);
if (localServiceHost != null)
{
_hosts.Add(localServiceHost);
}
//init network hosts
IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());
if (ips != null)
var dnsHostName = Dns.GetHostName();
var ips = Dns.GetHostEntry(dnsHostName);
if (ips == null)
{
foreach (IPAddress ipAddress in ips.AddressList)
Log.WarnFormat("InitHosts: end. Dns.GetHostEntry has returned null for DNS Host Name {0}", dnsHostName);
return false;
}
foreach (var ipAddress in ips.AddressList)
{
if (ipAddress?.AddressFamily == AddressFamily.InterNetwork)
{
if (ipAddress != null)
var ip = ipAddress.ToString();
var networkUrl = CreateConnectionAddress(ip, port, false);
var serviceHost = CreateServiceHost(networkUrl, false);
if (serviceHost != null)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
{
string ip = ipAddress.ToString();
string networkUrl = CreateConnectionAddress(ip, port, false);
ServiceHost serviceHost = CreateServiceHost(networkUrl, false);
if (serviceHost != null)
{
_hosts.Add(serviceHost);
}
}
_hosts.Add(serviceHost);
}
}
}
count = _hosts.Count;
}
Log.DebugFormat("InitHosts: end. Host's count = {0}", count);
return true;
}
private ServiceHost CreateServiceHost(string serverUrlAdress, bool local)
{
ServiceHost serviceHost = null;
if (serverUrlAdress != null)
{
try
{
serviceHost = new ServiceHost(_service);
var binding = CreateConnectionBinding(local);
Log.DebugFormat("CreateServiceHost: begin. serverUrlAdress = {0}; local = {1}", serverUrlAdress, local);
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
serviceHost.Open();
}
catch(Exception e)
{
Debug.WriteLine("CreateServiceHost: Create ServiceHost failed. " + e.Message);
}
if (serverUrlAdress == null)
{
Log.Warn("CreateServiceHost: end. serverUrlAdress is not defined");
return null;
}
ServiceHost serviceHost;
try
{
serviceHost = new ServiceHost(_service);
var binding = CreateConnectionBinding(local);
serviceHost.AddServiceEndpoint(typeof(IMtApi), binding, serverUrlAdress);
serviceHost.Open();
}
catch(Exception e)
{
Log.ErrorFormat("CreateServiceHost: Error! {0}", e.Message);
serviceHost = null;
}
Log.Debug("CreateServiceHost: end.");
return serviceHost;
}
public void AddExpert(MtExpert expert)
{
if (expert != null)
Log.DebugFormat("AddExpert: begin. expert {0}", expert);
if (expert == null)
{
expert.Deinited += expert_Deinited;
expert.QuoteChanged += expert_QuoteChanged;
expert.OnMtEvent += Expert_OnMtEvent;
lock (_experts)
{
_experts.Add(expert);
}
_executorManager.AddCommandExecutor(expert);
_service.OnQuoteAdded(expert.Quote);
Log.Warn("AddExpert: end. expert is not defined");
return;
}
expert.Deinited += expert_Deinited;
expert.QuoteChanged += expert_QuoteChanged;
expert.OnMtEvent += Expert_OnMtEvent;
lock (_experts)
{
_experts.Add(expert);
}
_executorManager.AddCommandExecutor(expert);
_service.OnQuoteAdded(expert.Quote);
Log.Debug("AddExpert: end.");
}
#endregion
@@ -126,25 +162,30 @@ namespace MTApiService
public MtResponse SendCommand(MtCommand command)
{
MtResponse response = null;
Log.DebugFormat("SendCommand: begin. command {0}", command);
if (command != null)
if (command == null)
{
var task = new MtCommandTask(command);
_executorManager.EnqueueCommandTask(task);
//wait for execute command in MetaTrader
response = task.WaitResult(WAIT_RESPONSE_TIME);
Log.Warn("SendCommand: end. command is not defined");
return null;
}
var task = new MtCommandTask(command);
_executorManager.EnqueueCommandTask(task);
//wait for execute command in MetaTrader
var response = task.WaitResult(WaitResponseTime);
return response;
}
public IEnumerable<MtQuote> GetQuotes()
public List<MtQuote> GetQuotes()
{
Log.Debug("GetQuotes: called");
lock (_experts)
{
return (from s in _experts select s.Quote);
return _experts.Select(s => s.Quote).ToList();
}
}
@@ -153,99 +194,127 @@ namespace MTApiService
#region Private Methods
private void stopTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
var expertsCount = 0;
Log.DebugFormat("stopTimer_Elapsed: begin");
int expertsCount;
lock (_experts)
{
expertsCount = _experts.Count();
expertsCount = _experts.Count;
}
if (expertsCount == 0)
{
_service.OnStopServer();
Log.DebugFormat("stopTimer_Elapsed: experts count is 0. Call Stop().");
Stop();
}
var stopTimer = sender as System.Timers.Timer;
if (stopTimer != null)
{
stopTimer.Stop();
stopTimer.Elapsed -= stopTimer_Elapsed;
}
if (stopTimer == null) return;
stopTimer.Stop();
stopTimer.Elapsed -= stopTimer_Elapsed;
Log.DebugFormat("stopTimer_Elapsed: end");
}
private string CreateConnectionAddress(string host, int port, bool local)
private static string CreateConnectionAddress(string host, int port, bool local)
{
Log.DebugFormat("CreateConnectionAddress: begin. host = {0}, port = {1}, local = {2}", host, port, local);
string connectionAddress = null;
if (local == true)
if (local)
{
//by Pipe
connectionAddress = "net.pipe://localhost/MtApiService_" + port.ToString();
connectionAddress = "net.pipe://localhost/MtApiService_" + port;
}
else
{
//by Socket
if (host != null)
{
connectionAddress = "net.tcp://" + host.ToString() + ":" + port.ToString() + "/MtApiService";
}
connectionAddress = "net.tcp://" + host + ":" + port + "/MtApiService";
}
}
Log.DebugFormat("CreateConnectionAddress: end. connectionAddress = {0}", connectionAddress);
return connectionAddress;
}
private static Binding CreateConnectionBinding(bool local)
{
Binding connectionBinding = null;
Log.DebugFormat("CreateConnectionBinding: begin. local = {0}", local);
if (local == true)
Binding connectionBinding;
if (local)
{
//by Pipe
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
bind.MaxReceivedMessageSize = 2147483647;
bind.MaxBufferSize = 2147483647;
var bind = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None)
{
MaxReceivedMessageSize = 2147483647,
MaxBufferSize = 2147483647,
MaxBufferPoolSize = 2147483647,
ReaderQuotas =
{
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxDepth = 2147483647,
MaxStringContentLength = 2147483647,
MaxNameTableCharCount = 2147483647
}
};
// Commented next statement since it is not required
bind.MaxBufferPoolSize = 2147483647;
bind.ReaderQuotas.MaxArrayLength = 2147483647;
bind.ReaderQuotas.MaxBytesPerRead = 2147483647;
bind.ReaderQuotas.MaxDepth = 2147483647;
bind.ReaderQuotas.MaxStringContentLength = 2147483647;
bind.ReaderQuotas.MaxNameTableCharCount = 2147483647;
connectionBinding = bind;
}
else
{
//by Socket
var bind = new NetTcpBinding(SecurityMode.None);
bind.MaxReceivedMessageSize = 2147483647;
bind.MaxBufferSize = 2147483647;
var bind = new NetTcpBinding(SecurityMode.None)
{
MaxReceivedMessageSize = 2147483647,
MaxBufferSize = 2147483647,
MaxBufferPoolSize = 2147483647,
ReaderQuotas =
{
MaxArrayLength = 2147483647,
MaxBytesPerRead = 2147483647,
MaxDepth = 2147483647,
MaxStringContentLength = 2147483647,
MaxNameTableCharCount = 2147483647
}
};
// Commented next statement since it is not required
bind.MaxBufferPoolSize = 2147483647;
bind.ReaderQuotas.MaxArrayLength = 2147483647;
bind.ReaderQuotas.MaxBytesPerRead = 2147483647;
bind.ReaderQuotas.MaxDepth = 2147483647;
bind.ReaderQuotas.MaxStringContentLength = 2147483647;
bind.ReaderQuotas.MaxNameTableCharCount = 2147483647;
connectionBinding = bind;
}
Log.Debug("CreateConnectionBinding: end.");
return connectionBinding;
}
private void Stop()
{
Log.Debug("Stop: begin.");
_executorManager.Stop();
lock (_hosts)
{
if (_hosts.Count == 0)
{
Log.Debug("Stop: end. Host count is 0.");
return;
}
try
{
@@ -254,15 +323,18 @@ namespace MTApiService
host.Close();
}
}
catch (TimeoutException)
catch (TimeoutException ex)
{
Log.ErrorFormat("Stop: TimeoutException - {0}", ex.Message);
foreach (var host in _hosts)
{
host.Abort();
}
}
catch (Exception)
catch (Exception ex)
{
Log.ErrorFormat("Stop: Exception - {0}", ex.Message);
// ignored
}
finally
@@ -272,20 +344,27 @@ namespace MTApiService
}
FireOnStopped();
Log.Debug("Stop: end.");
}
private void expert_Deinited(object sender, EventArgs e)
{
if (sender == null)
return;
Log.Debug("expert_Deinited: begin.");
var expert = (MtExpert)sender;
var expertsCount = 0;
var expert = sender as MtExpert;
if (expert == null)
{
Log.Warn("expert_Deinited: end. Expert is not defined.");
return;
}
int expertsCount;
lock (_experts)
{
_experts.Remove(expert);
expertsCount = _experts.Count();
expertsCount = _experts.Count;
}
_executorManager.RemoveCommandExecutor(expert);
@@ -299,19 +378,29 @@ namespace MTApiService
{
var stopTimer = new System.Timers.Timer();
stopTimer.Elapsed += stopTimer_Elapsed;
stopTimer.Interval = STOP_EXPERT_INTERVAL;
stopTimer.Interval = StopExpertInterval;
stopTimer.Start();
}
Log.Debug("expert_Deinited: end.");
}
private void expert_QuoteChanged(MtExpert expert, MtQuote quote)
{
Log.DebugFormat("expert_QuoteChanged: begin. expert = {0}, quote = {1}", expert, quote);
_service.QuoteUpdate(quote);
Log.Debug("expert_QuoteChanged: end.");
}
private void Expert_OnMtEvent(object sender, MtEventArgs e)
{
Log.DebugFormat("Expert_OnMtEvent: begin. event = {0}", e.Event);
_service.OnMtEvent(e.Event);
Log.Debug("Expert_OnMtEvent: end.");
}
private void FireOnStopped()
@@ -328,16 +417,13 @@ namespace MTApiService
#region IDispose
public void Dispose()
{
Log.Debug("Dispose: begin");
Stop();
Log.Debug("Dispose: end.");
}
#endregion
#region Fields
private readonly MtService _service;
private readonly List<ServiceHost> _hosts = new List<ServiceHost>();
private readonly MtCommandExecutorManager _executorManager = new MtCommandExecutorManager();
private readonly List<MtExpert> _experts = new List<MtExpert>();
#endregion
}
}
+104 -61
View File
@@ -1,30 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Net;
using System.Diagnostics;
using log4net;
namespace MTApiService
{
public class MtServerInstance
{
#region Init_Instance
#region Fields
private const string LogProfileName = "MtApiService";
static readonly MtServerInstance mInstance = new MtServerInstance();
private static readonly ILog Log = LogManager.GetLogger(typeof(MtServerInstance));
private static readonly MtServerInstance Instance = new MtServerInstance();
private readonly Dictionary<int, MtServer> _servers = new Dictionary<int, MtServer>();
private readonly Dictionary<int, MtExpert> _experts = new Dictionary<int, MtExpert>();
#endregion
#region Init Instance
private MtServerInstance()
{
{
LogConfigurator.Setup(LogProfileName);
}
static MtServerInstance()
{
}
{
}
public static MtServerInstance GetInstance()
{
return mInstance;
return Instance;
}
#endregion
@@ -33,20 +38,23 @@ namespace MTApiService
#region Public Methods
public void InitExpert(int expertHandle, int port, string symbol, double bid, double ask, IMetaTraderHandler mtHandler)
{
Debug.WriteLine("MtApiServerInstance::InitExpert: symbol = {0}, expertHandle = {1}, port = {2}", symbol, expertHandle, port);
if (mtHandler == null)
throw new ArgumentNullException(nameof(mtHandler));
MtServer server = null;
lock (mServersDictionary)
Log.InfoFormat("InitExpert: begin. symbol = {0}, expertHandle = {1}, port = {2}", symbol, expertHandle, port);
MtServer server;
lock (_servers)
{
if (mServersDictionary.ContainsKey(port))
if (_servers.ContainsKey(port))
{
server = mServersDictionary[port];
server = _servers[port];
}
else
{
server = new MtServer(port);
server.Stopped += new EventHandler(server_Stopped);
mServersDictionary[port] = server;
server.Stopped += server_Stopped;
_servers[port] = server;
server.Start();
}
@@ -54,137 +62,172 @@ namespace MTApiService
var expert = new MtExpert(expertHandle, new MtQuote(symbol, bid, ask), mtHandler);
lock (mExpertsDictionary)
lock (_experts)
{
mExpertsDictionary[expert.Handle] = expert;
_experts[expert.Handle] = expert;
}
server.AddExpert(expert);
Log.Info("InitExpert: end");
}
public void DeinitExpert(int expertHandle)
{
Debug.WriteLine("MtApiServerInstance::DeinitExpert: expertHandle = {0}", expertHandle);
Log.InfoFormat("DeinitExpert: begin. symbol = {0}", expertHandle);
MtExpert expert = null;
lock (mExpertsDictionary)
lock (_experts)
{
if (mExpertsDictionary.ContainsKey(expertHandle) == true)
if (_experts.ContainsKey(expertHandle))
{
expert = mExpertsDictionary[expertHandle];
mExpertsDictionary.Remove(expertHandle);
expert = _experts[expertHandle];
_experts.Remove(expertHandle);
}
}
if (expert != null)
{
expert.Deinit();
}
}
else
{
Log.WarnFormat("DeinitExpert: expert with id {0} has not been found.", expertHandle);
}
Log.Info("DeinitExpert: end");
}
public void SendQuote(int expertHandle, string symbol, double bid, double ask)
{
Debug.WriteLine("MtApiServerInstance::SendQuote: enter. symbol = {0}, bid = {1}, ask = {2}", symbol, bid, ask);
Log.DebugFormat("SendQuote: begin. symbol = {0}, bid = {1}, ask = {2}", symbol, bid, ask);
MtExpert expert = null;
lock (mExpertsDictionary)
MtExpert expert;
lock (_experts)
{
expert = mExpertsDictionary[expertHandle];
expert = _experts[expertHandle];
}
if (expert != null)
{
expert.Quote = new MtQuote(symbol, bid, ask);
}
else
{
Log.WarnFormat("SendQuote: expert with id {0} has not been found.", expertHandle);
}
Debug.WriteLine("MtApiServerInstance::SendQuote: finish.");
Log.Debug("SendQuote: end");
}
public void SendEvent(int expertHandle, int eventType, string payload)
{
Debug.WriteLine("MtApiServerInstance::SendEvent called. eventType = {0}, payload = {1}", eventType, payload);
Log.DebugFormat("SendEvent: begin. eventType = {0}, payload = {1}", eventType, payload);
MtExpert expert = null;
lock (mExpertsDictionary)
MtExpert expert;
lock (_experts)
{
expert = mExpertsDictionary[expertHandle];
expert = _experts[expertHandle];
}
if (expert != null)
{
expert.SendEvent(new MtEvent(eventType, payload));
}
else
{
Log.WarnFormat("SendEvent: expert with id {0} has not been found.", expertHandle);
}
Debug.WriteLine("MtApiServerInstance::SendEvent: finished");
Log.Debug("SendEvent: end");
}
public void SendResponse(int expertHandle, MtResponse response)
{
Debug.WriteLine("MtApiServerInstance::SendResponse: id = {0}, response = {1}", expertHandle, response);
Log.DebugFormat("SendResponse: begin. id = {0}, response = {1}", expertHandle, response);
MtExpert expert = null;
lock (mExpertsDictionary)
MtExpert expert;
lock (_experts)
{
expert = mExpertsDictionary[expertHandle];
expert = _experts[expertHandle];
}
if (expert != null)
{
expert.SendResponse(response);
}
else
{
Log.WarnFormat("SendResponse: expert with id {0} has not been found.", expertHandle);
}
Debug.WriteLine("MtApiServerInstance::SendResponse: finish");
Log.Debug("SendResponse: end");
}
public int GetCommandType(int expertHandle)
{
Debug.WriteLine("MtApiServerInstance::GetCommandType: expertHandle = {0}", expertHandle);
Log.DebugFormat("GetCommandType: begin. expertHandle = {0}", expertHandle);
MtExpert expert = null;
lock (mExpertsDictionary)
MtExpert expert;
lock (_experts)
{
expert = mExpertsDictionary[expertHandle];
expert = _experts[expertHandle];
}
return (expert != null) ? expert.GetCommandType() : 0;
if (expert == null)
{
Log.WarnFormat("GetCommandType: expert with id {0} has not been found.", expertHandle);
}
var retval = expert?.GetCommandType() ?? 0;
Log.DebugFormat("GetCommandType: end. retval = {0}", retval);
return retval;
}
public object GetCommandParameter(int expertHandle, int index)
{
Debug.WriteLine("MtApiServerInstance::GetCommandParameter: expertHandle = {0}, index = {1}", expertHandle, index);
Log.DebugFormat("GetCommandParameter: begin. expertHandle = {0}, index = {1}", expertHandle, index);
MtExpert expert = null;
lock (mExpertsDictionary)
MtExpert expert;
lock (_experts)
{
expert = mExpertsDictionary[expertHandle];
expert = _experts[expertHandle];
}
return (expert != null) ? expert.GetCommandParameter(index) : null;
if (expert == null)
{
Log.WarnFormat("GetCommandParameter: expert with id {0} has not been found.", expertHandle);
}
var retval = expert?.GetCommandParameter(index);
Log.DebugFormat("GetCommandParameter: end. retval = {0}", retval);
return retval;
}
#endregion
#region Private Methods
private void server_Stopped(object sender, EventArgs e)
{
MtServer server = (MtServer)sender;
var server = (MtServer)sender;
server.Stopped -= server_Stopped;
var port = server.Port;
lock (mServersDictionary)
Log.InfoFormat("server_Stopped: port = {0}", port);
lock (_servers)
{
if (mServersDictionary.ContainsKey(port))
if (_servers.ContainsKey(port))
{
mServersDictionary.Remove(port);
_servers.Remove(port);
}
}
}
#endregion
#region Fields
private readonly MtRegistryManager mConnectionManager = new MtRegistryManager();
private readonly Dictionary<int, MtServer> mServersDictionary = new Dictionary<int, MtServer>();
private readonly Dictionary<int, MtExpert> mExpertsDictionary = new Dictionary<int, MtExpert>();
#endregion
}
}
+96 -45
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;
using log4net;
namespace MTApiService
{
@@ -18,7 +19,7 @@ namespace MTApiService
MtResponse SendCommand(MtCommand command);
[OperationContract]
IEnumerable<MtQuote> GetQuotes();
List<MtQuote> GetQuotes();
}
[ServiceContract]
@@ -46,107 +47,149 @@ namespace MTApiService
InstanceContextMode = InstanceContextMode.Single)]
public sealed class MtService : IMtApi
{
private static readonly ILog Log = LogManager.GetLogger(typeof(MtService));
public MtService(IMtApiServer serverCallback)
{
if (serverCallback == null)
throw new ArgumentNullException("serverCallback");
throw new ArgumentNullException(nameof(serverCallback));
mServer = serverCallback;
_server = serverCallback;
}
#region IMtApi
public bool Connect()
{
bool connected = false;
Log.Debug("Connect: begin");
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
if (callback != null)
if (callback == null)
{
Log.Warn("Connect: end. Callback is not definded.");
return false;
}
var connected = false;
try
{
_clientsLocker.AcquireWriterLock(10000);
try
{
mClientsLocker.AcquireWriterLock(10000);
if (_clientCallbacks.Contains(callback) == false)
_clientCallbacks.Add(callback);
try
{
if (mClientCallbacks.Contains(callback) == false)
mClientCallbacks.Add(callback);
connected = true;
}
finally
{
mClientsLocker.ReleaseWriterLock();
}
connected = true;
}
catch (ApplicationException)
finally
{
_clientsLocker.ReleaseWriterLock();
}
}
catch (ApplicationException ex)
{
Log.ErrorFormat("Connect: ApplicationException - {0}", ex.Message);
}
Log.DebugFormat("Connect: end. connected = {0}", connected);
return connected;
}
public void Disconnect()
{
IMtApiCallback callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
Log.Debug("Disconnect: begin");
if (callback != null)
var callback = OperationContext.Current.GetCallbackChannel<IMtApiCallback>();
if (callback == null)
{
Log.Warn("Disconnect: end. Callback is not definded.");
return;
}
try
{
_clientsLocker.AcquireWriterLock(10000);
try
{
mClientsLocker.AcquireWriterLock(10000);
try
{
mClientCallbacks.Remove(callback);
}
finally
{
mClientsLocker.ReleaseWriterLock();
}
_clientCallbacks.Remove(callback);
}
catch (ApplicationException)
finally
{
_clientsLocker.ReleaseWriterLock();
}
}
catch (ApplicationException ex)
{
Log.ErrorFormat("Disconnect: ApplicationException - {0}", ex.Message);
}
Log.Debug("Disconnect: end.");
}
public MtResponse SendCommand(MtCommand command)
{
return mServer.SendCommand(command);
Log.DebugFormat("SendCommand: called. command = {0}", command);
return _server.SendCommand(command);
}
public IEnumerable<MtQuote> GetQuotes()
public List<MtQuote> GetQuotes()
{
return mServer.GetQuotes();
Log.Debug("GetQuotes: called.");
return _server.GetQuotes();
}
#endregion
#region Public Methods
public void OnStopServer()
{
Log.Debug("OnStopServer: begin.");
ExecuteCallbackAction(a => a.OnServerStopped());
Log.Debug("OnStopServer: end.");
}
public void QuoteUpdate(MtQuote quote)
{
Log.Debug("QuoteUpdate: begin.");
ExecuteCallbackAction(a => a.OnQuoteUpdate(quote));
Log.Debug("QuoteUpdate: end.");
}
public void OnQuoteAdded(MtQuote quote)
{
Log.Debug("OnQuoteAdded: begin.");
ExecuteCallbackAction(a => a.OnQuoteAdded(quote));
Log.Debug("OnQuoteAdded: end.");
}
public void OnQuoteRemoved(MtQuote quote)
{
Log.Debug("OnQuoteRemoved: begin.");
ExecuteCallbackAction(a => a.OnQuoteRemoved(quote));
Log.Debug("OnQuoteRemoved: end.");
}
public void OnMtEvent(MtEvent mtEvent)
{
Log.Debug("OnMtEvent: begin.");
ExecuteCallbackAction(a => a.OnMtEvent(mtEvent));
Log.Debug("OnMtEvent: end.");
}
#endregion
@@ -154,22 +197,26 @@ namespace MTApiService
private void ExecuteCallbackAction(Action<IMtApiCallback> action)
{
Log.Debug("ExecuteCallbackAction: begin.");
try
{
mClientsLocker.AcquireReaderLock(2000);
_clientsLocker.AcquireReaderLock(2000);
List<IMtApiCallback> crashedClientCallbacks = null;
try
{
foreach (var callback in mClientCallbacks)
foreach (var callback in _clientCallbacks)
{
try
{
action(callback);
}
catch (Exception)
catch (Exception ex)
{
Log.ErrorFormat("ExecuteCallbackAction: Exception - {0}", ex.Message);
if (crashedClientCallbacks == null)
crashedClientCallbacks = new List<IMtApiCallback>();
@@ -179,29 +226,33 @@ namespace MTApiService
if (crashedClientCallbacks != null)
{
Log.WarnFormat("ExecuteCallbackAction: crashed callback count = {0}", crashedClientCallbacks.Count);
foreach (var crashedCallback in crashedClientCallbacks)
{
mClientCallbacks.Remove(crashedCallback);
_clientCallbacks.Remove(crashedCallback);
}
}
}
finally
{
mClientsLocker.ReleaseReaderLock();
_clientsLocker.ReleaseReaderLock();
}
}
catch (ApplicationException)
catch (ApplicationException ex)
{
//TODO: add logging
Log.ErrorFormat("ExecuteCallbackAction: ApplicationException - {0}", ex.Message);
}
Log.Debug("ExecuteCallbackAction: end.");
}
#endregion
#region Fields
private readonly IMtApiServer mServer;
private readonly List<IMtApiCallback> mClientCallbacks = new List<IMtApiCallback>();
private readonly ReaderWriterLock mClientsLocker = new ReaderWriterLock();
private readonly IMtApiServer _server;
private readonly List<IMtApiCallback> _clientCallbacks = new List<IMtApiCallback>();
private readonly ReaderWriterLock _clientsLocker = new ReaderWriterLock();
#endregion
}
}
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ILMerge" version="2.13.0307" targetFramework="net40" />
<package id="log4net" version="2.0.5" targetFramework="net40" />
<package id="MSBuild.ILMerge.Task" version="1.0.5" targetFramework="net40" />
</packages>
+4
View File
@@ -22,6 +22,8 @@ namespace MtApi
//Special constant
public const int NULL = 0;
public const int EMPTY = -1;
private const string LogProfileName = "MtApiClient";
#endregion
#region Private Fields
@@ -34,6 +36,8 @@ namespace MtApi
public MtApiClient()
{
LogConfigurator.Setup(LogProfileName);
_client.QuoteAdded += _client_QuoteAdded;
_client.QuoteRemoved += _client_QuoteRemoved;
_client.QuoteUpdated += _client_QuoteUpdated;
+4 -1
View File
@@ -22,6 +22,7 @@ namespace MtApi5
#endregion
private const char ParamSeparator = ';';
private const string LogProfileName = "MtApi5Client";
public delegate void QuoteHandler(object sender, string symbol, double bid, double ask);
@@ -34,6 +35,8 @@ namespace MtApi5
#region Public Methods
public MtApi5Client()
{
LogConfigurator.Setup(LogProfileName);
ConnectionState = Mt5ConnectionState.Disconnected;
_client.QuoteAdded += mClient_QuoteAdded;
@@ -1492,7 +1495,7 @@ namespace MtApi5
throw new Exception(ex.Message, ex);
}
var responseValue = response.GetValue();
var responseValue = response?.GetValue();
return responseValue != null ? (T) responseValue : default(T);
}
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
@@ -10,8 +10,9 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MtApi5TestClient</RootNamespace>
<AssemblyName>MtApi5TestClient</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
@@ -25,6 +26,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
@@ -34,6 +36,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
@@ -50,6 +53,7 @@
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<OutputPath>bin\Release\</OutputPath>
@@ -67,6 +71,7 @@
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -124,6 +129,7 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
+18 -26
View File
@@ -1,17 +1,17 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18034
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MtApi5TestClient.Properties
{
namespace MtApi5TestClient.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
@@ -22,48 +22,40 @@ namespace MtApi5TestClient.Properties
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MtApi5TestClient.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set
{
set {
resourceCulture = value;
}
}
+10 -14
View File
@@ -1,28 +1,24 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18034
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MtApi5TestClient.Properties
{
namespace MtApi5TestClient.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
public static Settings Default {
get {
return defaultInstance;
}
}
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup></configuration>