I am using multi-thread method while saving my email data to database with dapper. There was no problem in my local tests, but it gave an error when I published it on the server.
See my method here, the class I used and the error I got.
How can I solve it? (project is ASP.NET Core 3.1 MVC)
private MailBoxResultDto SaveMails(MailBoxResultDto modelResult)
{
var savedMails = new List<IncomingMailDto>();
var processCount = 0;
int threadCount = 0, maxThreadCount = 50;
foreach (var mail in modelResult.MailList)
{
while (threadCount >= maxThreadCount)
{
Thread.Sleep(100);
}
threadCount ;
var thread = new Thread(() =>
{
// Mail daha önce alınmışsa kaydetme, atla
//var isExistMail = _incomingMailRepository.GetAll()
// .Any(a => a.Date == mail.Date && a.Subject == mail.Subject && a.From == JsonConvert.SerializeObject(mail.MailFrom));
var orm = new DapperOrm(new SqlConnection());
var getMail = orm.QuerySingleOrDefault<IncomingMail>(SqlQueryString.IncomingMailIsExistQueryString(mail.Date, mail.Subject, mail.MailFrom.SerializeObject()));
if (getMail == null)
{
// save mail
var willBeInsertMail = mail.SelectEmailToEntity(attch => attch.SelectAttachmentToEntity(), false);
willBeInsertMail.TenantId = AbpSession.TenantId.Value;
willBeInsertMail.UserId = AbpSession.UserId.Value;
long savedMailID = 0;
//try { savedMailID = _incomingMailRepository.InsertAndGetId(willBeInsertMail); }
orm = new DapperOrm(new SqlConnection());
try { savedMailID = orm.InsertReturnId(willBeInsertMail); }
catch (Exception ex) { threadCount--; processCount ; return; }
// save mail attachments
foreach (var attachment in willBeInsertMail.Attachments)
{
// isim, boyut, değiştirme tarihi, contentType
//var isExistMailAttach = _incomingMailAttachmentRepository.GetAll()
// .Any(a => a.Name == attachment.Name && a.Size == attachment.Size && a.LastModifiedTime == attachment.LastModifiedTime && a.ContentType == attachment.ContentType);
orm = new DapperOrm(new SqlConnection());
var getMailAttachment = orm.QuerySingleOrDefault<IncomingMailAttachment>(SqlQueryString.IncomingMailAttachmentIsExistQueryString(attachment.Name, attachment.Size, attachment.LastModifiedTime, attachment.ContentType));
if (getMailAttachment == null)
{
attachment.MailId = savedMailID;
attachment.TenantId = AbpSession.TenantId.Value;
attachment.Id = 0;
//try { _incomingMailAttachmentRepository.Insert(attachment); }
orm = new DapperOrm(new SqlConnection());
try { orm.Insert(attachment); }
catch (Exception ex) { threadCount--; processCount ; return; }
}
}
var incomingMailDto = willBeInsertMail.SelectEmailToDTO(attach => attach.SelectEmailAttachmentToDTO(), false);
savedMails.Add(incomingMailDto);
}
threadCount--;
processCount ;
});
thread.SetApartmentState(ApartmentState.MTA); // <-- at the this point
thread.Priority = ThreadPriority.Highest;
thread.Start();
}
while (processCount < modelResult.MailList.Count)
{
Thread.Sleep(500);
}
if (savedMails.Count > 1)
return MailBoxResult.Success("Kaydedilen Mail Listesi Getirildi", savedMails);
else
return MailBoxResult.Warning($"Mailler Kaydedilemedi{(string.IsNullOrEmpty(modelResult.ErrorMessage) ? "" : $" : {modelResult.ErrorMessage}")}", null);
}
My Dapper Orm Class
public class DapperOrm
{
public SqlConnection SqlConnection { get; }
public string ConnectionString { get; } = "...sqlconnectionString...";
public DapperOrm(SqlConnection sqlConnection)
{
SqlConnection = sqlConnection;
SqlConnection.ConnectionString = ConnectionString;
}
public DapperOrm(SqlConnection sqlConnection, string connectionString)
{
SqlConnection = sqlConnection;
SqlConnection.ConnectionString = connectionString;
}
public IEnumerable<T> GetQuery<T>(string sqlQuery)
{
IEnumerable<T> result = null;
using (SqlConnection)
{
if (SqlConnection.State != System.Data.ConnectionState.Open)
{
SqlConnection.Close();
SqlConnection.Open();
}
result = SqlConnection.Query<T>(sqlQuery);
SqlConnection.Close();
}
return result;
}
public T QuerySingleOrDefault<T>(string sqlQuery)
{
T result;
using (SqlConnection)
{
if (SqlConnection.State != System.Data.ConnectionState.Open)
{
SqlConnection.Close();
SqlConnection.Open();
}
result = SqlConnection.QuerySingleOrDefault<T>(sqlQuery);
SqlConnection.Close();
}
return result;
}
public bool Insert<T>(T model) where T : IMustHaveTenant
{
bool result = false;
using (SqlConnection)
{
if (SqlConnection.State != System.Data.ConnectionState.Open)
{
SqlConnection.Close();
SqlConnection.Open();
}
var fieldModellessAndListLess = model.GetType().GetProperties()
.Where(s => (
s.PropertyType.BaseType.Name == "ValueType" ||
s.PropertyType.BaseType.Name == "Array" ||
s.PropertyType.Name == "String"
) && s.Name != "Id")
.ToList(); // model ve liste olan propertyler hariç
var tableFields = fieldModellessAndListLess.Select(s => s.Name).ToList();
var fieldNames = $"[{tableFields.Aggregate((a, b) => $"{a}], [{b}")}]";
var valueNames = $"@{tableFields.Aggregate((a, b) => $"{a}, @{b}")}";
result = SqlConnection.Execute($"INSERT INTO {SqlQueryString.GetTableName(model)} ({fieldNames}) VALUES({valueNames})", model) > 0;
SqlConnection.Close();
}
return result;
}
public long InsertReturnId<T>(T model) where T : IMustHaveTenant
{
long result = 0;
using (SqlConnection)
{
if (SqlConnection.State != System.Data.ConnectionState.Open)
{
SqlConnection.Close();
SqlConnection.Open();
}
var fieldModellessAndListLess = model.GetType().GetProperties()
.Where(s => (
s.PropertyType.BaseType.Name == "ValueType" ||
s.PropertyType.BaseType.Name == "Array" ||
s.PropertyType.Name == "String"
) && s.Name != "Id")
.ToList(); // model ve liste olan propertyler hariç
var tableFields = fieldModellessAndListLess.Select(s => s.Name).ToList();
var fieldNames = $"[{tableFields.Aggregate((a, b) => $"{a}], [{b}")}]";
var valueNames = $"@{tableFields.Aggregate((a, b) => $"{a}, @{b}")}";
result = SqlConnection.ExecuteScalar<long>($"INSERT INTO {SqlQueryString.GetTableName(model)} ({fieldNames}) OUTPUT Inserted.ID VALUES({valueNames})", model);
SqlConnection.Close();
}
return result;
}
}
public class SqlQueryString
{
public static string GetTableName<T>(T entity)
{
return $"{entity.GetType().Name}s";
}
public static string IncomingMailIsExistQueryString(DateTime mailDate, string subject, string mailFrom)
{
return $"SELECT TOP 1 Id FROM IncomingMails WHERE [Date] = '{mailDate:yyyy-MM-dd HH:mm:ss}' AND [Subject] = '{subject.Replace("'", "''")}' AND [From] = '{mailFrom.Replace("'", "''")}'";
}
public static string IncomingMailAttachmentIsExistQueryString(string name, int size, DateTime modifiedTime, string contentType)
{
return $"SELECT TOP 1 Id FROM IncomingMailAttachments WHERE [Name] = '{name}' AND [Size] = {size} AND [LastModifiedTime] = '{modifiedTime:yyyy-MM-dd HH:mm:ss}' AND [ContentType] = '{contentType.Replace("'", "''")}'";
}
}
Exception
System.PlatformNotSupportedException: COM Interop is not supported on this platform.
at CFCRM.Mails.Mailbox.MailBoxAppService.SaveMails(MailBoxResultDto modelResult) in /opt/crm/src/CFCRM.Application/Mails/Mailbox/MailBoxAppService.cs:line 343
at CFCRM.Mails.Mailbox.MailBoxAppService.SyncInboxMail() in /opt/crm/src/CFCRM.Application/Mails/Mailbox/MailBoxAppService.cs:line 151
at lambda_method(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
CodePudding user response:
Yes, we found the problem; Our project was running on linux server and I didn't know about it. EWS (Exchange Web Service) also gave an error because there is no linux server support.
Thanks for the comments guys.