【问题标题】:MultiThread, ApartmentState.MTA point Exception : System.PlatformNotSupportedException: COM Interop is not supported on this platform多线程,ApartmentState.MTA 点异常:System.PlatformNotSupportedException:此平台不支持 COM 互操作
【发布时间】:2022-01-03 11:53:47
【问题描述】:

我正在使用多线程方法,同时使用 dapper 将我的电子邮件数据保存到数据库。我本地测试没有问题,但是在服务器上发布的时候报错了。

在这里查看我的方法,我使用的类和我得到的错误。

我该如何解决? (项目为 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);
}

我的 Dapper Orm 类

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("'", "''")}'";
    }
}

例外

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

[1

【问题讨论】:

  • 从异常中可以明显看出,CFCRM.Mails 似乎使用了 COM,而这不适用于您的平台。那么,您的服务器在哪个平台上运行?您是否尝试过禁用邮件功能或使用其他库?
  • 我编辑了我的问题。上面,您可以看到该服务已包含在我们的系统中。我们发布的网站在亚马逊网络服务上运行。
  • AWS 有大量不同的服务。您需要检查您正在使用什么特定服务,以及它支持什么。值得注意的是,我不希望任何基于 linux 的东西支持 COM。
  • 请不要像 DapperOrm 类那样编写 SQL 连接“帮助”类。它强制所有查询作为单个字符串传入,这意味着您不能使用参数,并且可能会遇到 SQL 注入问题。
  • @Damien_The_Unbeliever Dapper 支持 SqlConnection 上的纯查询语句,就像在 Ado Net 中一样。不幸的是,无法使用 Linq 等工具。那么你会建议什么方式呢?

标签: c# sql-server multithreading exception


【解决方案1】:

是的,我们发现了问题;我们的项目在linux服务器上运行,我不知道。 EWS(Exchange Web Service)也报错,因为没有linux服务器支持。

感谢 cmets 伙计们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 2019-10-30
    • 2021-01-27
    相关资源
    最近更新 更多