【问题标题】:Code analysis issue in Visual StudioVisual Studio 中的代码分析问题
【发布时间】:2015-09-20 01:48:47
【问题描述】:

请找到以下代码:

private static void HandleValidationError(ILogger logger, HttpRequestMessage requestMessage, HttpStatusCode statusCode, string message)
        {
        logger.LogError(LoggingSources.API, message);
throw new HttpResponseException(requestMessage.CreateErrorResponse(statusCode, message));
   }
            }

我收到以下 CA 问题:

CA2000 在方法中丢失范围之前处理对象 'ControllerHelper.HandleValidationError(ILogger, HttpRequestMessage, HttpStatusCode, string)', 对象 'HttpRequestMessageExtensions.CreateErrorResponse(requestMessage, statusCode, message)' 不会沿所有异常路径进行处理。称呼 System.IDisposable.Dispose 对象 'HttpRequestMessageExtensions.CreateErrorResponse(requestMessage, statusCode, message)' 在所有对它的引用都超出之前 范围。 Tasks.Application.Web.API ControllerHelper.cs 106

上述函数的调用者是:

public static void CheckForValidDelimitedIntegerInput(ILogger logger, HttpRequestMessage request, char delimiter, string input)
        {
            if (!string.IsNullOrEmpty(input))
            {
                try
                {
                    string[] idList = input.Split(delimiter);
                    for (int i = 0; i < idList.Length; i++)
                    {
                        int result;
                        if (!int.TryParse(idList[i], out result) || result <= 0)
                        {
                            HandleValidationError(logger, request, HttpStatusCode.BadRequest, InvalidIntegerOrShort);
                        }
                    }
                }
                catch (HttpResponseException)
                {
                    throw;
                }
            }
            else
            {
                HandleValidationError(logger, request, HttpStatusCode.BadRequest, InvalidParameter);
            }
        }

我在Do I need to dispose an HttpResponseException from Request.CreateResponse()? 之前的帖子中尝试过*,但没有成功。

【问题讨论】:

  • 您不需要在finally 块中调用Dispose。它被包裹在 using 中,它会被处理掉。
  • 是的,我知道。但我仍然遇到同样的 CA 问题。
  • 您确定要在方法中处理requestMessage 吗?它正在传入;调用方法不应该处理生命周期吗?
  • 您正在处理传递给方法的HttpRequestMessage,但您没有处理通过调用requestMessage.CreateErrorResponse 创建的HttpRequestMessage
  • 也许把logger.LogError(LoggingSources.API, message);放在try块里面。

标签: c# .net httprequest code-analysis


【解决方案1】:

阅读this article 以了解“处置模式”。另外,请阅读this post 以了解何时应处置对象。在您的特定情况下,当调用者仍然具有对函数的引用时,它看起来像 anti-pattern 来处理函数的参数。

为了解决您收到的警告,requestMessage.CreateErrorResponse(...) 创建了一个HttpResponseMessage,它实现了IDisposable。在方法返回之前,这超出了范围(因为您没有对它进行引用)。这意味着代码分析工具发现此对象上的Dispose 从未被调用。

编辑:

要解决此问题,只需删除 using 指令,并按如下方式简化您的代码。

private static void HandleValidationError(ILogger logger, HttpRequestMessage requestMessage, HttpStatusCode statusCode, string message)
{
    logger.LogError(LoggingSources.API, message);
    throw new HttpResponseException(requestMessage.CreateErrorResponse(statusCode, message));
}

这似乎对我有用。不过,这会将对象交给调用者处理。

编辑:

啊哈!我发现了这个stack overflow post,这似乎是你的确切问题。为了完整起见,它基本上说您不需要处理 HttpResponseMessage 对象。但是,如果您改用构造函数,则此警告已被抑制,因此您无需自己抑制它。

试试这个:

private static void HandleValidationError(ILogger logger, HttpRequestMessage requestMessage, HttpStatusCode statusCode, string message)
{
    logger.LogError(LoggingSources.API, message);
    throw new HttpResponseException(new HttpResponseMessage(statusCode){
        ReasonPhrase = message
    });
}

注意:因为我无法重现这个问题,所以我无法测试以确保它有效。

【讨论】:

  • 感谢您的回复。除了在 Suppression file 中抑制此错误之外,还有其他解决方案吗?
  • 它不工作。我已经用 Caller 函数更新了这个问题。如果您有任何答案,请告诉我
  • 你是否遇到和以前一样的代码分析错误?
  • 非常感谢约翰。感谢您在这方面的帮助。
  • 没问题,很高兴我能帮上忙 :)
【解决方案2】:

经过一番分析,我终于找到了答案。

private static void HandleValidationError(ILogger logger, HttpRequestMessage requestMessage, HttpStatusCode statusCode, string message)
    {
        logger.LogError(LoggingSources.API, message);
        using (var errorResponse = requestMessage.CreateErrorResponse(statusCode, message))
        {
            throw new HttpResponseException(errorResponse);
        }
    }    

这将解决 CA 问题。我还要感谢约翰的帮助。

【讨论】:

  • 以后处理他的异常时,您是否仍然可以访问errorResponse?如果是这种情况,那么它可能会在尝试访问已处置的对象时抛出异常。
  • 嗯,是的,但我认为这种情况不适用于这里。
【解决方案3】:

使用 using 会导致 500 内部服务器错误。

我的解决方案是RegisterForDispose 所以它变成:

var errorResponse = requestMessage.CreateErrorResponse(statusCode, message));
this.request.RegisterForDispose(errorResponse);
throw new HttpResponseException(errorResponse);

您仍然需要抑制 CA2000 警告,但我相信这是正确的处置方式,因此 CA2000 需要允许这种处置模式。

【讨论】: