6

我有一个使用第三方报告组件的 ASP.NET 站点。每当客户端浏览器未在请求标头中NullReferenceException指定 a 时,此组件就会抛出异常。User-Agent

这基本上是一个奇怪的场景,我只是想想出一个解决方法。我不知道谁/哪个客户端没有指定用户代理,这似乎是 IMO 的错误形式,但我们必须处理它产生的异常。我已经向第三方记录了一份关于他们报告组件中的错误的支持票,但我怀疑这条路线会有多大的成果。所以我的想法只是检测何时User-Agent为空白并将其默认为只是为了安抚报告组件。但是,我似乎无法更改 Request.Headers 集合中的任何内容。我得到以下异常:

Operation is not supported on this platform.

我开始相信我无法做到这一点。我理解为什么ASP.NET 不允许这样做,但我还没有想出任何其他解决方法。

更新:User-Agent在penfold 的建议下,我Request.Headers尝试使用HttpModule. 这使它添加到Headers集合中,但没有更新Request.UserAgent属性,这就是导致报告组件失败的原因。我一直在查看 .NET Reflector 以确定如何设置该属性以便我可以更新它,但我还没有想出任何东西(我可以找到的不仅仅是一个驱动属性的私有字段)。

4

3 回答 3

3

最近我也遇到了和你一样的问题。我通过使用模拟 HttpWorkerRequest 克服了 Request.UserAgent 的问题。

(假设您已经使用自定义 HttpModule 解决了 Request.Headers 中的代理字符串)

这是示例代码:

Friend Class MockedRequestWorker
    Inherits HttpWorkerRequest

    Private ReadOnly _BaseHttpWorkerRequest As HttpWorkerRequest
    Private ReadOnly _UserAgent As String

    Friend Sub New(ByVal base As HttpWorkerRequest, 
        ByVal UserAgent As String)
        _BaseHttpWorkerRequest = base
        _UserAgent = UserAgent
    End Sub

    Public Overrides Sub EndOfRequest()
        _BaseHttpWorkerRequest.EndOfRequest()
    End Sub

    Public Overrides Sub FlushResponse(ByVal finalFlush As Boolean)
        _BaseHttpWorkerRequest.FlushResponse(finalFlush)
    End Sub

    'Note: remember to override all other virtual functions by direct invoke functions
    'from _BaseHttpWorkerRequest, except the following function

    Public Overrides Function GetKnownRequestHeader(ByVal index As Integer) As String

        'if user is requesting the user agent value, we return the 
        'override user agent string
        If index = HttpWorkerRequest.HeaderUserAgent Then
            Return _UserAgent
        End If

        Return _BaseHttpWorkerRequest.GetKnownRequestHeader(index)
    End Function

End Class

然后,在您的自定义 HttpApplication.BeginRequest 处理程序中,执行此操作

Private Sub BeginRequestHandler(ByVal sender As Object, ByVal e As EventArgs)

    Dim request As HttpRequest = HttpRequest.Current.Request
    Dim HttpRequest_wrField As FieldInfo = GetType(HttpRequest).GetField("_wr", BindingFlags.Instance Or BindingFlags.NonPublic)

    Dim ua As String = "your agent string here"
    Dim _wr As HttpWorkerRequest = HttpRequest_wrField.GetValue(request)
    Dim mock As New MockedRequestWorker(_wr, ua)

    'Replace the internal field with our mocked instance
    HttpRequest_wrField.SetValue(request, mock)

End Sub

注意:此方法仍然不能替换 ServerVariables 中的用户代理值,但它应该能够解决您需要的问题(也是我的问题)

希望这有帮助:)

于 2014-01-23T15:12:36.777 回答
3
protected void Application_BeginRequest(Object sender, EventArgs e) {
    const string ua = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
    Request.Headers["User-Agent"] = ua;
    var httpWorkerRequestField = Request.GetType().GetField("_wr", BindingFlags.Instance | BindingFlags.NonPublic);
    if (httpWorkerRequestField != null) {
        var httpWorkerRequest = httpWorkerRequestField.GetValue(Request);
        var knownRequestHeadersField = httpWorkerRequest.GetType().GetField("_knownRequestHeaders", BindingFlags.Instance | BindingFlags.NonPublic);
        if (knownRequestHeadersField != null) {
            string[] knownRequestHeaders = (string[])knownRequestHeadersField.GetValue(httpWorkerRequest);
            knownRequestHeaders[39] = ua;
        }
    }
}
于 2015-01-24T08:09:24.757 回答
2

我认为处理这个问题的最好方法是使用一个 http 模块,该模块将检查标头并在必要时注入用户代理。

正如您发现的那样,您不能在 Headers 对象上使用 set 方法。相反,您将不得不通过受保护的属性将用户代理字符串注入标头,这些属性可以通过反射访问,如该问题的答案中所述。

更新

不幸的是Request.UserAgent,它没有使用 HttpWorkerRequest 中保存的信息Request.Headers,而是调用HttpWorkerRequestGetKnownRequestHeader中的方法。这是一个抽象类,通过查看反编译的库代码,实际实现会因托管环境而异。因此,我看不到通过反射以可靠方式替换用户代理字符串的方法。您可以推出自己的 WorkerRequest 课程,但我认为付出的努力并不值得。

很抱歉是否定的,但我认为不可能以简单的方式在 Web 应用程序中设置用户代理。目前最好的选择是对用户代理执行预检查,如果请求没有,则返回浏览器不支持的错误消息。

您还可以调查在更早的时候注入一些东西,即在 IIS 中或在您的代理服务器上(如果您使用一个)。

另外,我建议将此问题报告给 SAP。我知道他们目前正在积极开发 Viewer,谁知道他们可能会修复它,甚至可能会添加对 Opera 的支持!

于 2013-03-05T22:32:36.033 回答