【发布时间】: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