I have an ASP.NET site that uses a third-party reporting component. This component is misbehaving by throwing a NullReferenceException
whenever the client browser is not specifying a User-Agent
in the request headers.
It's basically an odd scenario that I'm just trying to come up with a workaround for. I do not know who/what client is not specifying a User-Agent, which seems like bad form IMO, but we have to deal with the exceptions it is generating. I have logged a support ticket with the third-party regarding the bug in their reporting component, but I have my doubts about how fruitful that route is going to be. So my thought was just to detect when the User-Agent
is blank and default it to something just to appease the reporting component. However, I can't seem to change anything in the Request.Headers collection. I get the following exception:
Operation is not supported on this platform.
I'm starting to believe I'm not going to be able to do this. I understand why ASP.NET wouldn't allow this, but I haven't come up with any other workaround.
Update: At penfold's suggestion, I tried to add the User-Agent
to the Request.Headers
collection using an HttpModule
. This got it added to the Headers
collection, but did nothing to update the Request.UserAgent
property, which is what is causing the reporting component to fail. I've been looking through .NET Reflector to determine how that property is set so that I can update it, but I haven't come up with anything yet (there isn't just a private field that drives the property that I can find).
I think the best way of handling this is to use a http module that will check the header and inject the user agent if necessary.
As you have found out you cannot use the set method on the Headers object. Instead you will have to inject the user agent string into the header via protected properties that can be accessed through reflection as outlined in the answer to this question.
UPDATE
Unfortunately Request.UserAgent
doesn't use the information held in Request.Headers
, instead it calls the method GetKnownRequestHeader
in HttpWorkerRequest. This is an abstract class and from looking at the decompiled library code the actual implementation varies depending on the hosting environment. Therefore I cannot see a way to replace the user agent string in a reliable manner via reflection. You could roll your own WorkerRequest class but for the amount of effort I don't think the payoff would be worth it.
Sorry to be negative but I think its just not possible to set the user agent within the web application in a simple manner. Your best option at the moment would be to perform a pre-check for a user agent, and if the request doesn't have one return a browser not supported error message.
You could also investigate injecting something earlier on, i.e. in IIS or at your proxy server if you use one.
Also I would recommend that this issue is reported to SAP. I know they are actively working on the Viewer at the moment and who knows they might fix it and maybe even add support for Opera!
Recently I also facing similar problem same as you. I overcome the problem
of Request.UserAgent by using a mock HttpWorkerRequest.
(Assuming you already solve the agent string in Request.Headers with custom HttpModule)
Here is the sample code:
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
then, in your custom HttpApplication.BeginRequest handler, do this
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
Note: this method still does not replace the user agent value in ServerVariables, but it should able to solve what you need(and my problem too)
Hope this help :)
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;
}
}
}