Home > other >  MultiThread, ApartmentState.MTA point Exception : System.PlatformNotSupportedException: COM Interop
MultiThread, ApartmentState.MTA point Exception : System.PlatformNotSupportedException: COM Interop

Time:12-03

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()

[exception point imageenter image description here

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.

  • Related