Производительность и потокобезопасность ASP.NET Core MVCC#

Место общения программистов C#
Ответить
Anonymous
 Производительность и потокобезопасность ASP.NET Core MVC

Сообщение Anonymous »

Я работаю .NET C#-разработчиком чуть больше двух лет в компании-разработчике программного обеспечения. Вот уже почти год я возглавляю (в качестве руководителя группы/PM) проект, который фактически начался еще до того, как я присоединился к нему. Я справляюсь довольно хорошо, но мне не хватает опыта, особенно в вопросах производительности и потокобезопасности.
Проект построен на ASP.NET Core MVC с использованием ADO.NET (без Entity Framework) и без внешней среды (только HTML, CSS и JavaScript). Это система управления тренажерными залами, предназначенная для одновременного использования многими тренажерными залами, каждый из которых обращается к одному экземпляру SQL Server (одна общая база данных).
Мои основные сомнения связаны с настройкой программы и особенно с DataLayer, классом, который мы используем для обработки вызовов базы данных. В этом DataLayer соединение открывается в конструкторе, а затем снова открываются дополнительные соединения внутри отдельных методов (я так и не понял почему — уже было так, когда я пришел).
Сам DataLayer не зарегистрирован как сервис; вместо этого он создается внутри каждой службы. При этом сами службы регистрируются в программе как синглтоны.
Вот упрощенный пример кода:

Код: Выделить всё

class DataLayer
{
private readonly string _connectionString;
public SqlConnection _objConnection = new SqlConnection();
public SqlCommand _objCommand = new SqlCommand();
public int _intNumRecords;
private Exception _objException;
private bool _blnTrans = false;
public SqlTransaction _objTransaction;
private string _strLastSQLExecuted;
private readonly IConfiguration _configuration;

public DataLayer(IConfiguration _configuration)
{
_connectionString = _configuration.GetConnectionString("DevConnection");

if (_connectionString is null)
_connectionString = CustumConfigurationString.GetCustumStringConfiguration("DevConnection");

try
{
_objConnection = new SqlConnection(_connectionString);
_objConnection.Open();
}
catch (Exception ex)
{
Log.WriteLog(logType: LogType.Error, LogDestination.DataBase, "", "", ex);
_objConnection.Close();
}
}

public async Task ExecuteStoreGetDataTableValueAsync(string storedProcedureName, ArrayList parameters, [CallerMemberName] string callerMember = "", [CallerFilePath] string callerFile = "", [CallerLineNumber] int callerLine = 0)
{
DataTable dt = new DataTable();

SqlConnection connection = new SqlConnection(_connectionString);
SqlCommand command = new SqlCommand(storedProcedureName, connection);

try
{
command.CommandType = CommandType.StoredProcedure;

foreach (SqlParameter parameter in parameters)
{
command.Parameters.Add(parameter);
}

await connection.OpenAsync();
using SqlDataReader reader = await command.ExecuteReaderAsync();
dt.Load(reader);

}
catch (Exception ex)
{
//Aggiungo informazioni sul punto da cui è stato chiamato il metodo per facilitare il debug
string nomeClasse = System.IO.Path.GetFileNameWithoutExtension(callerFile);
string msg = $" Chiamato da Classe: [{nomeClasse}], Metodo: [{callerMember}], Linea: [{callerLine}], SP: [{storedProcedureName}]";

await Log.WriteLogAsync(LogType.Error, LogDestination.All, msg, "", ex);

throw;
}
finally
{
if (connection is object)
{
connection.Close();
connection.Dispose();
}
if (command is object)
{
command.Parameters.Clear();
command.Dispose();
}
}

return dt;
}

}
Программа:

Код: Выделить всё

builder.Services.AddSingleton();
builder.Services.AddSingleton();
...

Пример услуги:

Код: Выделить всё

public class MestiereService : IMestiereService
{
private DataLayer _dataLayer;

public MestiereService(IConfiguration configuration)
{
_dataLayer = new DataLayer(configuration);
}

public async Task  GetAll(int idMestiere, string idPalestra)
{
MestieriViewModel viewModel = new MestieriViewModel();
viewModel.ListaMestieri = await GetListaMestieri(idPalestra);

if (idMestiere != 0)
{
SqlParameter idMestiereParam = new SqlParameter("@IdMestiere", idMestiere);
SqlParameter idPalestraParam = new SqlParameter("@IdPalestra", idPalestra);

string query = "sp_Get_MestiereById_Mestiere";

DataTable dt = new DataTable();
dt = await _dataLayer.ExecuteStoreGetDataTableValueAsync(query, new ArrayList() { idMestiereParam, idPalestraParam });
viewModel.Mestiere.IdMestiere = (int)idMestiere;
viewModel.Mestiere.Nome = dt.Rows[0]["Nome"].ToString();
viewModel.Mestiere.IdPalestra = Convert.ToInt32(dt.Rows[0]["IdPalestra"]);

return viewModel;
}
else
{
return viewModel;
}

}
}
После опроса различных инструментов искусственного интеллекта (ChatGPT, Cursor, Gemini) выяснилось, что такой подход к DataLayer проблематичен — он может привести к проблемам переполнения и блокировке потоков. Рекомендуется реорганизовать его в полноценный сервис, зарегистрировать его в программе как Scoped, а также сделать другие сервисы Scoped вместо Singleton.
Поскольку это будет довольно большое изменение, которое затронет почти все в проекте, я хотел услышать мнение некоторых опытных разработчиков, прежде чем полностью полагаться на советы ИИ.

Подробнее здесь: https://stackoverflow.com/questions/798 ... t-core-mvc
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»