#pragma warning disable 1591 using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using MySqlConnector; using Newtonsoft.Json; // make sure to adjust the prefix with the PACKAGE_NAME from ENV using com.krohne.genericdatabaseapiservice.Models; // make sure to adjust the prefix with the PACKAGE_NAME from ENV namespace com.krohne.genericdatabaseapiservice.Services { public class DbInfoObject { public DbInfoObject(string host, string user, string password, string name) { Host = host; User = user; Password = password; Name = name; } public string Host { get; set; } public string User { get; set; } public string Password { get; set; } public string Name { get; set; } } public class DbInfoServiceException : Exception {} public class UnknownDatabaseTagException: DbInfoServiceException {} public interface IDbInfoService { DbInfoObject GetInfoByTag(string tag); string GetInfoStringByTag(string tag); } public class DbInfoService : IDbInfoService { private readonly IConfiguration Configuration; private readonly ILogger Logger; private Dictionary DbInfos; public DbInfoService(IConfiguration configuration, ILogger logger) { Configuration = configuration; Logger = logger; Console.WriteLine("Database Infofile: {0}", Configuration["Database:InfoFile"]); DbInfos = JsonConvert.DeserializeObject>(File.ReadAllText(Configuration["Database:InfoFile"])); } public DbInfoObject GetInfoByTag(string tag) { try { return DbInfos[tag]; } catch (KeyNotFoundException) { throw new UnknownDatabaseTagException(); } } public string GetInfoStringByTag(string tag) { return String.Format( "Server={0};User ID={1};Password={2};Database={3};Convert Zero Datetime=true", GetInfoByTag(tag).Host, GetInfoByTag(tag).User, GetInfoByTag(tag).Password, GetInfoByTag(tag).Name); } } public interface IDbService { Task> ReadBySelect(string databaseTag, string selectStatement, bool justOne, TIN input, bool bindingByStringReplacement); } public class DbServiceException : Exception { public DbServiceException(string msg): base(msg) { } public DbServiceException(): base() { } } public class NoDataFoundException : DbServiceException { public NoDataFoundException(string msg): base(msg) { } public NoDataFoundException(): base() { } } public class TooMuchDataFoundException : DbServiceException { public TooMuchDataFoundException(string msg): base(msg) { } public TooMuchDataFoundException(): base() { } } public class UnsupportedDataTypeException: DbServiceException { public UnsupportedDataTypeException(string msg): base(msg) { } public UnsupportedDataTypeException(): base() { } } public class StringReplacementNotAllowedException: DbServiceException { public StringReplacementNotAllowedException(string msg): base(msg) { } public StringReplacementNotAllowedException(): base() { } } public class DbService : IDbService { private readonly IConfiguration Configuration; private readonly ILogger Logger; private readonly IDbInfoService DbInfoService; public DbService(IConfiguration configuration, ILogger logger, IDbInfoService dbInfoService) { Configuration = configuration; Logger = logger; DbInfoService = dbInfoService; } async public Task> ReadBySelect(string databaseTag, string selectStatement, bool justOne, TIN input, bool bindingByStringReplacement) { var itemList = new List(); var databaseConnInfo = DbInfoService.GetInfoStringByTag(databaseTag); Logger.LogInformation("ConnInfo: {0}", databaseConnInfo); Logger.LogInformation("Statement: {0}", selectStatement); using (var conn = new MySqlConnection(databaseConnInfo)) { await conn.OpenAsync(); bool commandTextSet = false; using (var cmd = conn.CreateCommand()) { if (! bindingByStringReplacement) { cmd.CommandText = selectStatement; commandTextSet = true; } if (input != null){ foreach (var propertyInfo in typeof(TIN).GetProperties()) { Logger.LogInformation("Input Property name: {0} {1} ", propertyInfo.Name, propertyInfo.PropertyType); var attributes = propertyInfo.GetCustomAttributes(typeof(DataMemberAttribute), true); var dma = (DataMemberAttribute)attributes[0]; Logger.LogInformation("Input DataMember name: {0} {1}", dma.Name, dma.TypeId); var value = propertyInfo.GetValue(input); Type typ = value.GetType(); var isList = typ.IsGenericType && (typ.GetGenericTypeDefinition() == typeof(List<>)); if (isList) { var p1 = propertyInfo.GetValue(input) as System.Collections.IEnumerable; var p2 = new StringBuilder(); var sep = ""; foreach (var x in p1) { if (! (x is int || x is long)) { Logger.LogError("Parameter binding by string replacement is for security reasons only allowed for numbers"); throw new StringReplacementNotAllowedException(); } Logger.LogInformation("x: {0}", x); p2.Append(sep); p2.Append(x); sep = ","; } var p3 = p2.ToString(); Logger.LogInformation("Input Value: p3:{0} typ:{1} isList:{2}", p3, typ, isList); if (bindingByStringReplacement) { if (commandTextSet) { Logger.LogError("Parameter bindung by string replacement is only supported for a single parameter"); throw new StringReplacementNotAllowedException("string replacement only allowed for numeric parameters"); } var processedStatement = selectStatement.Replace(String.Format("@{0}", dma.Name), p3); cmd.CommandText = processedStatement; commandTextSet = true; Logger.LogInformation("Statement after replacement is {0}", processedStatement); } else { cmd.Parameters.AddWithValue(dma.Name, p3); } } else { if (bindingByStringReplacement) { Logger.LogError("Parameter binding by string replacement is only supported for array parameters"); throw new StringReplacementNotAllowedException("string replacement only allowed to handle lists of parameters"); } Logger.LogInformation("Input Value: {0} {1} {2}", value, typ, isList); cmd.Parameters.AddWithValue(dma.Name, value); } } } else { Logger.LogInformation("no input data"); } using (var reader = await cmd.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { var item = Activator.CreateInstance(); foreach (var propertyInfo in typeof(TOUT).GetProperties()) { Logger.LogInformation("Output Property name: {0} {1} ", propertyInfo.Name, propertyInfo.PropertyType); var attributes = propertyInfo.GetCustomAttributes(typeof(DataMemberAttribute), true); var dma = (DataMemberAttribute)attributes[0]; int ordinal = reader.GetOrdinal(dma.Name); Logger.LogInformation("Output DataMember name: {0} {1} {2} ", dma.Name, dma.TypeId, ordinal); if (await reader.IsDBNullAsync(ordinal)) { propertyInfo.SetValue(item, null); Logger.LogInformation("Output Value: null"); } else if (propertyInfo.PropertyType == typeof(System.String)) { var value = reader.GetString(ordinal); propertyInfo.SetValue(item, value); Logger.LogInformation("Output Value:{0}", value); } else if (propertyInfo.PropertyType == typeof(System.Int32) || propertyInfo.PropertyType == typeof(System.Nullable)) { var value = reader.GetInt32(ordinal); propertyInfo.SetValue(item, value); Logger.LogInformation("Output Value:{0}", (System.Int32)value); } else if (propertyInfo.PropertyType == typeof(System.Int64) || propertyInfo.PropertyType == typeof(System.Nullable)) { var value = reader.GetInt64(ordinal); propertyInfo.SetValue(item, value); Logger.LogInformation("Output Value:{0}", (System.Int64)value); } else if (propertyInfo.PropertyType == typeof(System.DateTime)) { var value = reader.GetDateTime(ordinal); propertyInfo.SetValue(item, value); Logger.LogInformation("Output Value:{0}", value); } else if (propertyInfo.PropertyType == typeof(System.Boolean) || propertyInfo.PropertyType == typeof(System.Nullable)) { var value = reader.GetBoolean(ordinal); propertyInfo.SetValue(item, value); Logger.LogInformation("Output Value:{0}", value); } else { Logger.LogError("Unsupported data type {0}", propertyInfo.PropertyType); throw new UnsupportedDataTypeException(String.Format("{0}", propertyInfo.PropertyType)); } } itemList.Add(item); Logger.LogInformation("Item is {0}", item); } } } } if (itemList.Count == 0) { Logger.LogWarning("no data found"); throw new NoDataFoundException(); } if (justOne && itemList.Count > 1) { Logger.LogWarning("too much data found"); throw new TooMuchDataFoundException(); } return itemList; } } } #pragma warning restore 1591