I have a Microsoft Blazor application which has a few views, controllers, interfaces and services (around 30). Suddenly, I started getting "OutOfMemory" Exception on Client side (razor component), so I started checking where is the issue!
Starting from the Service, the output list is calculated and returns 11 objects, then the controller responds with this list and finally the razor is throwing the exception.
Here is the Service Code:
public List<VirtualDataModel_STG_Ind> GetDataModel_STGs(int datamodel_id, bool isselectedobject)
{
try
{
List<VirtualDataModel_STG_Ind> datamodel_stgs = new();
DataModel? dataModel = _dbContext.DataModels.Where(x => x.datamodel_id == datamodel_id).FirstOrDefault();
if (dataModel != null)
{
//dataModel = DataSecurity.ObjectFilter(dataModel, "view", _dbContext, _httpContextAccessor);
//PROVISION TWO LISTS AND THEN FOREACH TO HANDLE PERFORMANCE
List<DataModel_STG_Table_Ind> datamodel_stg_tables_ind = _dbContext.DataModel_STG_Tables_Ind
.Where(x => x.datamodel_id == datamodel_id)
.OrderBy(x => x.datamodel_stg_table_schm)
.ThenBy(x => x.datamodel_stg_table_name)
.ToList();
List<DataModel_STG_Field_Ind> datamodel_stg_fields_inds = _dbContext.DataModel_STG_Fields_Ind
.Where(x => x.datamodel_id == datamodel_id)
.OrderBy(x => x.datamodel_stg_table_schm)
.ThenBy(x => x.datamodel_stg_table_name)
.ThenBy(x => x.datamodel_stg_field_name)
.ToList();
//IF SENSITIVEOBJECT
if (isselectedobject)
{
datamodel_stg_fields_inds = datamodel_stg_fields_inds.Where(x => x.datamodel_stg_field_is_selected == true).ToList();
}
foreach (DataModel_STG_Table_Ind datamodel_stg_table_ind in datamodel_stg_tables_ind)
{
if (datamodel_stg_table_ind != null)
{
List<DataModel_STG_Field_Ind> datamodel_stg_fields_ind = datamodel_stg_fields_inds
.Where(x => x.datamodel_id == datamodel_stg_table_ind.datamodel_id && x.datamodel_stg_table_schm == datamodel_stg_table_ind.datamodel_stg_table_schm && x.datamodel_stg_table_name == datamodel_stg_table_ind.datamodel_stg_table_name)
.OrderBy(x => x.datamodel_stg_table_schm)
.ThenBy(x => x.datamodel_stg_table_name)
.ThenBy(x => x.datamodel_stg_field_name).ToList();
if (datamodel_stg_fields_ind != null)
{
if (datamodel_stg_fields_ind.Count() > 0)
{
VirtualDataModel_STG_Ind virtualdatamodel_stg_ind = new()
{
datamodel_stg_table = datamodel_stg_table_ind,
datamodel_stg_table_fields = datamodel_stg_fields_ind,
};
datamodel_stgs.Add(virtualdatamodel_stg_ind);
}
}
}
}
}
return datamodel_stgs;
}
catch
{
throw;
}
}
Here is the Controller Code:
[HttpGet, Route("/api/datamodel/view/{datamodel_id:int}/stg/view/{isselectedobject:bool}")]
public async Task<List<VirtualDataModel_STG_Ind>> GetDataModel_STGs(int datamodel_id, bool isselectedobject)
{
try {
List<VirtualDataModel_STG_Ind> obj = await Task.FromResult(_IDataModel.GetDataModel_STGs(datamodel_id, isselectedobject));
return obj;
}
catch { throw; }
}
Here is my Razor Code:
protected async Task GetDataModel_STG(int datamodel_id)
{
try
{
Loading_Start();
datamodel_stgList = await Http.GetFromJsonAsync<List<VirtualDataModel_STG_Ind>>("/api/datamodel/view/" + datamodel_id + "/stg/view/" + isSelectedObject );
Loading_Stop();
}
catch (Exception e)
{
Sawait ShowTheExceptionModal(e.Message);
}
}
In order to resolve this I tried also a couple of things,
Any ideas?
Thanks to @H H comment, I was able to fix this Issue "OutOfMemory". In my case, the List where the T was an abject which was referencing some child elements, and those child elements were referencing the parent, which was creating a loop (cycle).
I had to make some public static variable with JSON options into Shared Project, like the following and call it on the razor components where there was this special object.
The Class into Shared Project:
public class Parameters
{
public static JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
{
ReferenceHandler = ReferenceHandler.Preserve,
PropertyNameCaseInsensitive = true
};
}
The method into Client Component:
protected async Task GetDataModel_STG(int datamodel_id)
{
try
{
Loading_Start();
datamodel_stgList = await Http.GetFromJsonAsync<List<VirtualDataModel_STG_Ind>>(
"/api/datamodel/view/" + datamodel_id + "/stg/view/" + isSelectedObject,
Parameters.jsonSerializerOptions);
if (datamodel_stgList != null)
{ datamodel_stgResultList = datamodel_stgList.ToList(); }
FilterDataModel_STG();
await ExpandDataModel_STG();
Loading_Stop();
}
catch (Exception e)
{
await ShowTheExceptionModal(e.Message);
}
}
This way I do not have to declare same variable everywhere, just reference it.