public async Task <IActionResult> Step1Submit(List <IFormFile> files)
        {
            CreateJobStep1ViewModel result;

            var file = files.FirstOrDefault();

            if (file?.Length > 0)
            {
                string filePath = createJobControllerUtils.GetFilePath(file.FileName);

                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    await file.CopyToAsync(stream);
                }

                result = createJobControllerUtils.ListStratProperties(filePath);
            }
            else
            {
                result = new CreateJobStep1ViewModel()
                {
                    Message = "No content was uploaded",
                    Success = false
                };
            }

            return(View("Step1", result));
        }
        internal async Task <CreateJobStep1ViewModel> DuplicateJob(string jobNameToDuplicate)
        {
            logger.Info($"Will attempt to duplicate job {jobNameToDuplicate}");

            var jobGroup = await jobGroupsControllerUtils.Get(jobNameToDuplicate);

            if (jobGroup != null && jobGroup.Strategy != null)
            {
                string dllPath = jobGroup.Strategy.StrategyDllPath;

                if (File.Exists(dllPath))
                {
                    var result = new CreateJobStep1ViewModel()
                    {
                        Message  = $"Duplicate of {jobNameToDuplicate}",
                        Settings = new BacktestJobSettingsModel()
                        {
                            AlgorithmClass        = jobGroup.Strategy?.AlgoTypeName,
                            CrossesAndTicketSizes = jobGroup.Strategy.CrossesAndTicketSizes,
                            EndDate          = jobGroup.EndDate.LocalDateTime,
                            EndTime          = jobGroup.EndTime.LocalDateTime,
                            NewFileName      = dllPath,
                            OriginalFileName = jobGroup.Strategy.StrategyDllPath,
                            Parameters       = jobGroup.Strategy.Parameters.ToBacktestJobStrategyParameterModels("Param"),
                            StartDate        = jobGroup.StartDate.LocalDateTime,
                            StartTime        = jobGroup.StartTime.LocalDateTime,
                            StrategyClass    = jobGroup.Strategy.StrategyTypeName,
                            StrategyName     = jobGroup.Strategy.Name,
                            StrategyVersion  = jobGroup.Strategy.Version,
                            UseHistoDatabase = jobGroup.UseHistoDatabase
                        },
                        Success = true
                    };

                    result.Settings.JobName = AssignJobNameAndAddToDictionary(result.Settings);

                    return(result);
                }
                else
                {
                    logger.Error($"Unable to the DLL file used for previous job {jobNameToDuplicate} ({dllPath}). Will create a new job instead");
                    return(new CreateJobStep1ViewModel());
                }
            }
            else
            {
                logger.Error($"Unable to retrieve details of job {jobNameToDuplicate}. Will create a new one instead");
                return(new CreateJobStep1ViewModel());
            }
        }
        public CreateJobStep1ViewModel ListStratProperties(string dllPath)
        {
            CreateJobStep1ViewModel result = new CreateJobStep1ViewModel();

            result.Settings.NewFileName = dllPath;

            try
            {
                logger.Debug($"Loading DLL from {dllPath}");

                Assembly assembly = Assembly.LoadFile(dllPath);

                // 1. Strategy
                Type strategyType = assembly.GetTypes()?.Where(t => t.Name.EndsWith(StrategySuffix)).FirstOrDefault();

                IStrategy strategyInstance = null;

                if (strategyType != null)
                {
                    result.Settings.StrategyClass = strategyType.FullName;

                    strategyInstance = Activator.CreateInstance(strategyType) as IStrategy;

                    if (strategyInstance != null)
                    {
                        result.Settings.StrategyName    = strategyInstance.Name;
                        result.Settings.StrategyVersion = strategyInstance.Version;
                    }
                    else
                    {
                        string err = "Failed to instanciate strategy from DLL";
                        logger.Error(err);

                        result.Success = false;
                        result.Message = err;

                        return(result);
                    }
                }
                else
                {
                    string err = $"Failed to load strategy type from DLL. The name of the strategy class must end with suffix '{StrategySuffix}' to be taken into account";
                    logger.Error(err);

                    result.Success = false;
                    result.Message = err;

                    return(result);
                }

                // 2. Algorithm
                Type algorithmType = assembly.GetTypes()?.Where(t => t.Name.EndsWith(AlgorithmSuffix)).FirstOrDefault();

                if (algorithmType != null)
                {
                    result.Settings.AlgorithmClass = algorithmType.FullName;

                    // Try to instanciate the algorithm to get the default value of its properties
                    object algoInstance = null;

                    try
                    {
                        algoInstance = Activator.CreateInstance(algorithmType);
                    }
                    catch (Exception ex)
                    {
                        logger.Error($"Failed to instanciate algorithm of type {algorithmType.FullName}. Won't be able to determine the default value of its properties", ex);
                    }

                    List <BacktestJobStrategyParameterModel> properties = (from p in algorithmType.GetProperties()
                                                                           where p.Name.StartsWith(ParamKey)
                                                                           select new BacktestJobStrategyParameterModel()
                    {
                        Name = p.Name.Remove(0, ParamKey.Length),
                        Value = algoInstance != null ? p.GetValue(algoInstance).ToString() : null
                    })?.OrderBy(p => p.Name).ToList();

                    if (!properties.IsNullOrEmpty())
                    {
                        IEnumerable <Tuple <string, string> > tooltips = (from p in algorithmType.GetProperties()
                                                                          where p.Name.StartsWith(TooltipKey)
                                                                          select new Tuple <string, string>(
                                                                              p.Name.Remove(0, TooltipKey.Length),
                                                                              algoInstance != null ? p.GetValue(algoInstance) as string : null))
                                                                         .Where(t => !string.IsNullOrEmpty(t.Item2));

                        if (!tooltips.IsNullOrEmpty())
                        {
                            foreach (Tuple <string, string> tooltip in tooltips)
                            {
                                var param = properties.FirstOrDefault(p => p.Name == tooltip.Item1);

                                if (param != null)
                                {
                                    param.Tooltip = tooltip.Item2;
                                }
                            }
                        }

                        result.Settings.Parameters = properties;
                        result.Success             = true;

                        AssignJobNameAndAddToDictionary(result.Settings);

                        return(result);
                    }
                    else
                    {
                        string err = $"No strategy parameter found. Is this intentional? Param names must start with prefix '{ParamKey}' to be listed here";
                        logger.Error(err);

                        result.Success = false;
                        result.Message = err;

                        return(result);
                    }
                }
                else
                {
                    string err = $"Failed to load algorithm type from DLL. The name of the algorithm class must end with suffix '{AlgorithmSuffix}' to be taken into account";
                    logger.Error(err);

                    result.Success = false;
                    result.Message = err;

                    return(result);
                }
            }
            catch (Exception ex)
            {
                logger.Error($"Failed to load properties for type {AlgorithmSuffix} from DLL {dllPath}", ex);

                string err = $"Failed to retrieve list of strat params: {ex.Message}";

                result.Success = false;
                result.Message = err;

                return(result);
            }
        }