我有一个使用第三方报告组件的ASP.NET站点。每当客户端浏览器未在请求标头中指定NullReferenceException
时,此组件就会抛出User-Agent
行为不正常。
基本上这是一个奇怪的场景,我只想尝试解决方法。我不知道是谁/什么客户端没有指定用户代理,这似乎是IMO的错误形式,但我们必须处理它产生的异常。我已经与第三方记录了关于其报告组件中的错误的支持票,但我对这条路线的成效有疑问。所以我的想法只是检测User-Agent
何时为空,并将其默认为只是为了安抚报告组件。但是,我似乎无法更改Request.Headers集合中的任何内容。我得到以下异常:
Operation is not supported on this platform.
我开始相信我无法做到这一点。我理解为什么 ASP.NET不允许这样做,但我没有提出任何其他解决方法。
更新:根据penfold的建议,我尝试将User-Agent
添加到Request.Headers
集合using an HttpModule
。这将它添加到Headers
集合中,但没有更新Request.UserAgent
属性,这是导致报告组件失败的原因。我一直在寻找.NET Reflector以确定如何设置该属性以便我可以更新它,但我还没有提出任何东西(不仅有一个私有字段驱动我可以找到的属性)。
答案 0 :(得分: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中的用户代理值,但它应该能够解决您需要的问题(以及我的问题)
希望这有帮助:)
答案 1 :(得分: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;
}
}
}
答案 2 :(得分:2)
我认为处理此问题的最佳方法是使用一个http模块来检查标头并在必要时注入用户代理。
如您所知,您无法在Headers对象上使用set方法。相反,您必须通过受保护的属性将用户代理字符串注入标头,这些属性可以通过this question的答案中概述的反射来访问。
不幸的是Request.UserAgent
不使用Request.Headers
中包含的信息,而是调用HttpWorkerRequest中的方法GetKnownRequestHeader
。这是一个抽象类,通过查看反编译的库代码,实际实现会根据托管环境而有所不同。因此,我无法通过反射以可靠的方式看到替换用户代理字符串的方法。你可以滚动你自己的WorkerRequest类,但是为了努力,我认为收益不值得。
很抱歉是否定的,但我认为不可能以简单的方式在Web应用程序中设置用户代理。目前您最好的选择是对用户代理执行预检查,如果请求没有,则返回浏览器不支持的错误消息。
您还可以调查先前注入的内容,例如在IIS或您的代理服务器上,如果您使用它。
另外,我建议将此问题报告给SAP。我知道他们现在正在积极研究Viewer,谁知道他们可能会修复它,甚至可能会增加对Opera的支持!