无法访问实体框架中已处置的对象

问题描述 投票:0回答:1

我正在创建一个中间件来存储所有传入的 API 请求和响应正文以及一些其他数据,我使用实体框架作为我的 ORM。

它运行良好,但在某些请求和响应中,响应正文没有被存储。

当我记录错误时,它显示:

对象名称:'TransactionDBContext'.第 248 行
无法访问已处置的对象。导致此错误的一个常见原因是处置从依赖项注入解析的上下文,然后尝试在应用程序的其他位置使用相同的上下文实例。如果您在上下文上调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。如果您使用依赖注入,则应该让依赖注入容器负责处理上下文实例。

我只是使用异步返回任务和等待关键字的每个方法正确使用

Middleware.cs

public class TransactionLoggingMiddleWare
{
    private readonly RequestDelegate _next;
    private TransactionLogService _transactionLogService;

    public TransactionLoggingMiddleWare(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context, TransactionLogService transactionLogService)
    {
        _transactionLogService = transactionLogService;
        Guid GUID = Guid.NewGuid();

        try
        {
            var request = context.Request;

            if (request.Path.ToString().Contains("Remittance/Post"))
            {
                var requestTime = DateTime.Now;
                var requestBodyContent = await ReadRequestBody(request);
                int bcode = requestBodyContent.IndexOf("content-disposition:");

                if (bcode > 0)
                {
                    string jung1 = requestBodyContent.Substring(0, bcode - 1);
                    requestBodyContent = requestBodyContent.Replace(jung1, "");
                }

                context.Items["Guid"] = GUID;

                requestBodyContent = requestBodyContent.Replace("content-disposition: form-data; name=", "");

                var form = await context.Request.ReadFormAsync();
                var transactionData = new RemittanceRQ();

                var properties = typeof(RemittanceRQ).GetProperties();
                int remIdValue = 0;
                long TxnRefNo = 0;
                string productcode = null;

                foreach (var property in properties)
                {
                    // Get the property name
                    var propertyName = property.Name;

                    // Check if the form data contains the key corresponding to the property name
                    if (form.ContainsKey(propertyName))
                    {
                        // Get the value from the form data
                        var value = form[propertyName];

                        // Convert and assign the value to the property
                        if (value != String.Empty)
                        {
                            // Handle different property types accordingly
                            if (property.PropertyType == typeof(int))
                            {
                                property.SetValue(transactionData, Convert.ToInt32(value));
                            }
                            else if (property.PropertyType == typeof(Int16))
                            {
                                property.SetValue(transactionData , Convert.ToInt16(value));
                            }
                            else if (property.PropertyType == typeof(long))
                            {
                                property.SetValue(transactionData, long.Parse(value));
                            }
                            else if (property.PropertyType == typeof(decimal))
                            {
                                property.SetValue(transactionData, decimal.Parse(value));
                            }
                            else if (property.PropertyType == typeof(short))
                            {
                                property.SetValue(transactionData, Convert.ToInt16(value));
                            }
                            else if (property.PropertyType == typeof(String))
                            {
                                property.SetValue(transactionData, value.ToString());
                            }

                            if (propertyName == "RemID")
                            {
                                remIdValue = Convert.ToInt32(value);
                            }

                            if (propertyName == "TxnRefNumber")
                            {
                                TxnRefNo = long.Parse(value);
                            }
                        }
                    }
                }

                // to store only request body
                await _transactionLogService.AddTransaction(new TransactionLogItem
                {
                    TransactionGuid = GUID.ToString(),
                    CreatedDate = requestTime,
                    APIRequest = JsonConvert.SerializeObject(transactionData),
                    RemId = remIdValue,
                    TxnNumber = TxnRefNo,
                    


                });

                // reading the response



                var orginalBodyStream = context.Response.Body;

                var originalBodyCode = context.Response.StatusCode;
           
                
                try
                {


                    using (var responseBody = new MemoryStream())
                    {
                        //context.Response.Body = responseBody;
                        var response = context.Response;
                        response.Body = responseBody;

                        await _next(context);

                        responseBody.Seek(0, SeekOrigin.Begin);
                        var responseBodyContent = await new StreamReader(responseBody).ReadToEndAsync();

                        var responseData = JsonConvert.DeserializeObject<ResponseData>(responseBodyContent);
                        
                        if (responseData != null)
                        {
                            var txnReferenceNo = responseData.Data?.TxnReferenceNo;
                                                        }
                            await _transactionLogService.UpdateTransactionLog(new TransactionLogItem
                            {

                                TransactionGuid = GUID.ToString(),
                                
                                APIResponse = responseBodyContent,
                                Status_Code = response.StatusCode,
                                TxnNumber = responseData.Data?.TxnReferenceNo,
                                TransactionStatus = responseData.IsSuccess,
                                XPIN = responseData.Data?.TTNUM,
                            });
                        
                        responseBody.Seek(0, SeekOrigin.Begin);
                        await responseBody.CopyToAsync(orginalBodyStream);
                    }
                   
                    // end of reading response body
                    //await _next(context);


                }
                catch (Exception ex)
                {
                    await _transactionLogService.UpdateTransactionLog(new TransactionLogItem
                    {
                        TransactionGuid = GUID.ToString(),
                        ExceptionMsg = ex.Message
                    });

                    File.AppendAllText("loggerMiddlewareException.txt",ex.Message.ToString()+"line no 231"+$"{GUID}"+"\n");
                }
            }
                

            else
            {
                await _next(context);
            }


        }
        catch (Exception ex)
        {
            bool translogGuid = context.Items.TryGetValue("Guid", out var requestIdObj);
            var request = context.Request;
            var requestTime = DateTime.Now;
            File.AppendAllText("loggerMiddlewareException.txt", ex.Message.ToString() + "line no 248" + "\n");
            var requestBodyContent = await ReadRequestBody(request);
            await _transactionLogService.UpdateTransactionLog(new TransactionLogItem
            {
                TransactionGuid = GUID.ToString(),
                ExceptionMsg = ex.Message,
            });
            await _next(context);

        }
    }

    private async Task<string> ReadRequestBody(HttpRequest request)
    {
        request.EnableBuffering();

        var buffer = new byte[Convert.ToInt32(request.ContentLength??0)];
        await request.Body.ReadAsync(buffer, 0, buffer.Length);
        var bodyAsText = Encoding.UTF8.GetString(buffer);
        request.Body.Seek(0, SeekOrigin.Begin);

        return bodyAsText;
    }
}

服务寄存器:

 services.AddDbContext<TransactionDBContext>(options => options.UseSqlServer(connectionString));

DbContext

public class TransactionDBContext:DbContext{
public TransactionDBContext(DbContextOptions<TransactionDBContext> options):base(options)
{

}
public DbSet<TransactionLogItem> tblt_TransactionLogs { get; set; }}

服务.cs:

public class TransactionLogService{
private readonly TransactionDBContext _dbContext;
public int TransactionId { get; set; }
public TransactionLogService(TransactionDBContext transactionDBContext)
{
    _dbContext = transactionDBContext;
}
public async Task AddTransaction(TransactionLogItem transactionLogItem)
{
    _dbContext.tblt_TransactionLogs.Add(transactionLogItem);
    await _dbContext.SaveChangesAsync();
    //TransactionId = transactionLogItem.TransactionLogID;
}
public async Task UpdateTransactionLog(TransactionLogItem LogItem)
{
    var existingLog = await _dbContext.tblt_TransactionLogs.FirstOrDefaultAsync(t => t.TransactionGuid == LogItem.TransactionGuid);
    if (existingLog != null)
    {
        existingLog.EngineCode = LogItem.EngineCode = string.IsNullOrEmpty(LogItem.EngineCode) ? existingLog.EngineCode : LogItem.EngineCode; ;
        existingLog.APIResponse = LogItem.APIResponse=string.IsNullOrEmpty(LogItem.APIResponse)? existingLog.APIResponse: LogItem.APIResponse;
        existingLog.Status_Code = LogItem.Status_Code==0?existingLog.Status_Code:LogItem.Status_Code;
        existingLog.TxnNumber= LogItem.TxnNumber == null || LogItem.TxnNumber == 0 ? existingLog.TxnNumber:LogItem.TxnNumber;
        existingLog.XPIN = LogItem.XPIN=string.IsNullOrEmpty(LogItem.XPIN)?existingLog.XPIN:LogItem.XPIN;
        existingLog.MTORequest=LogItem.MTORequest=string.IsNullOrEmpty(LogItem.MTORequest)?existingLog.MTORequest:LogItem.MTORequest;
        existingLog.MTOResponse=LogItem.MTOResponse=string.IsNullOrEmpty(LogItem.MTOResponse)?existingLog.MTOResponse:LogItem.MTOResponse;
        existingLog.ExceptionMsg = LogItem.ExceptionMsg = string.IsNullOrEmpty(LogItem.ExceptionMsg) ? existingLog.ExceptionMsg : LogItem.ExceptionMsg;
        existingLog.TransactionStatus = LogItem.TransactionStatus;



    }
    await _dbContext.SaveChangesAsync();

}
}

它在几乎 80% 的情况下工作正常,但在某些情况下它无法仅存储响应。

如何解决?生产中的问题

c# entity-framework .net-core asp.net-core-webapi asp.net-core-middleware
1个回答
0
投票

您描述的问题似乎与服务(可能是 TransactionLogService)的生命周期有关。 请注意,DbContext 始终具有作用域(为每个请求创建一个新作用域),因此如果您有依赖它的单例服务(具有更长的生命周期并且在请求之间保持不变)。在某些情况下,可能会发生这样的情况:当 dbcontext 已被访问时,它会尝试访问它。 已经处置了。 一些可能的解决方案:

  1. 检查如何将其添加到 Program.cs 中的依赖注入容器中,并研究考虑到 dbcontext 将是范围的服务的适当生命周期。

  2. 确保它不会发生的更机械/确定的方法是,不直接注入 DbContext 类,而是注入 IServiceScopeFactory ,并在使用上下文的每个方法中,使用工厂创建一个新作用域并获取一个新副本从中获取 DbContext。这使您可以完全控制 dbcontext 实例的生命周期,并且不会发生这些错误(唯一的缺点是 dbcontext 数据可能在 SaveChanges 调用之间不一致)。

我希望您觉得这有帮助。

让我知道您是否需要 2 解决方案的示例代码,我稍后会尝试添加它们。

© www.soinside.com 2019 - 2024. All rights reserved.