Microsoft Blazor客户端Razor端内存不足

huangapple go评论133阅读模式
英文:

Microsoft Blazor OutOfMemory on Client Razor Side

问题

我有一个Microsoft Blazor应用程序,其中包含一些视图、控制器、接口和服务(约30个)。突然间,我开始在客户端(razor组件)上收到**"OutOfMemory"**异常,所以我开始检查问题出在哪里!

从服务开始,输出列表被计算并返回11个对象,然后控制器使用此列表响应,最后razor抛出异常。

以下是服务代码:

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进行处理
            // ...

            // 创建两个列表,然后使用foreach处理性能
            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 (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;
    }
}

以下是控制器代码:

[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; }
}

以下是我的Razor代码:

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)
    {
        ShowTheExceptionModal(e.Message);
    }
}

为了解决这个问题,我还尝试了一些事情:

  1. 从razor组件中删除了将响应暴露到表格(主/详细信息)中的所有代码(datamodel_stgList)。
  2. 在Visual Studio中检查了此响应期间的内存,约为200-250MB。
  3. 从.NET6升级到.NET7,以防万一。

有什么建议吗?

英文:

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&lt;VirtualDataModel_STG_Ind&gt; GetDataModel_STGs(int datamodel_id, bool isselectedobject)
{
	try
	{
		List&lt;VirtualDataModel_STG_Ind&gt; datamodel_stgs = new();
		DataModel? dataModel = _dbContext.DataModels.Where(x =&gt; x.datamodel_id == datamodel_id).FirstOrDefault();
		if (dataModel != null)
		{
			//dataModel = DataSecurity.ObjectFilter(dataModel, &quot;view&quot;, _dbContext, _httpContextAccessor);

			//PROVISION TWO LISTS AND THEN FOREACH TO HANDLE PERFORMANCE
			List&lt;DataModel_STG_Table_Ind&gt; datamodel_stg_tables_ind = _dbContext.DataModel_STG_Tables_Ind
				.Where(x =&gt; x.datamodel_id == datamodel_id)
				.OrderBy(x =&gt; x.datamodel_stg_table_schm)
				.ThenBy(x =&gt; x.datamodel_stg_table_name)
				.ToList();
			List&lt;DataModel_STG_Field_Ind&gt; datamodel_stg_fields_inds = _dbContext.DataModel_STG_Fields_Ind
				.Where(x =&gt; x.datamodel_id == datamodel_id)
				.OrderBy(x =&gt; x.datamodel_stg_table_schm)
				.ThenBy(x =&gt; x.datamodel_stg_table_name)
				.ThenBy(x =&gt; x.datamodel_stg_field_name)
				.ToList();

			//IF SENSITIVEOBJECT
			if (isselectedobject)
			{
				datamodel_stg_fields_inds = datamodel_stg_fields_inds.Where(x =&gt; 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&lt;DataModel_STG_Field_Ind&gt; datamodel_stg_fields_ind = datamodel_stg_fields_inds
						.Where(x =&gt; x.datamodel_id == datamodel_stg_table_ind.datamodel_id &amp;&amp; x.datamodel_stg_table_schm == datamodel_stg_table_ind.datamodel_stg_table_schm &amp;&amp; x.datamodel_stg_table_name == datamodel_stg_table_ind.datamodel_stg_table_name)
						.OrderBy(x =&gt; x.datamodel_stg_table_schm)
						.ThenBy(x =&gt; x.datamodel_stg_table_name)
						.ThenBy(x =&gt; x.datamodel_stg_field_name).ToList();

					if (datamodel_stg_fields_ind != null)
					{
						if (datamodel_stg_fields_ind.Count() &gt; 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(&quot;/api/datamodel/view/{datamodel_id:int}/stg/view/{isselectedobject:bool}&quot;)]
public async Task&lt;List&lt;VirtualDataModel_STG_Ind&gt;&gt; GetDataModel_STGs(int datamodel_id, bool isselectedobject)
{
	try {
		List&lt;VirtualDataModel_STG_Ind&gt; 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&lt;List&lt;VirtualDataModel_STG_Ind&gt;&gt;(&quot;/api/datamodel/view/&quot; + datamodel_id + &quot;/stg/view/&quot; + isSelectedObject );
					Loading_Stop();
	}
	catch (Exception e)
	{
		Sawait ShowTheExceptionModal(e.Message);
	}
}

In order to resolve this I tried also a couple of things,

  1. removed all the code from razor component which is exposing into table (master/detail) the response of the controller (datamodel_stgList)
  2. checked the memory during this response in Visual Studio and is around 200-250mb
  3. upgraded to .NET7 from .NET6 just in case

Any ideas?

答案1

得分: 1

感谢@H H的评论,我能够修复这个“OutOfMemory”问题。
在我的情况下,List<T>中的T是一个引用了一些子元素的对象,而这些子元素又引用了父元素,从而创建了一个循环。

我不得不在Shared Project中创建一些带有JSON选项的公共静态变量,就像下面这样,在那些有这个特殊对象的razor组件中调用它。

Shared Project中的类:

public class Parameters
{
    public static JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
    {
        ReferenceHandler = ReferenceHandler.Preserve,
        PropertyNameCaseInsensitive = true
    };
}

客户端组件中的方法:

protected async Task GetDataModel_STG(int datamodel_id)
{
    try
    {
        Loading_Start();
        datamodel_stgList = await Http.GetFromJsonAsync&lt;List&lt;VirtualDataModel_STG_Ind&gt;&gt;(
                   &quot;/api/datamodel/view/&quot; + datamodel_id + &quot;/stg/view/&quot; + 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);
    }
}

这样我就不需要在每个地方声明相同的变量,只需引用它。

英文:

Thanks to @H H comment, I was able to fix this Issue "OutOfMemory".
In my case, the List<T> 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&lt;List&lt;VirtualDataModel_STG_Ind&gt;&gt;(
                   &quot;/api/datamodel/view/&quot; + datamodel_id + &quot;/stg/view/&quot; + 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.

huangapple
  • 本文由 发表于 2023年6月1日 15:06:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76379430.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定