views:

69

answers:

2

I have a WebClient instance that receives data from a remote website. I referenced a DownloadProgressChanged event handler and I am trying to access InnerBuffer, which is an internal field in the DownloadBitsState nested class (set as private) in WebClient.

I am using the following code right in the DownloadProgressChanged event handler:

WebClient c = (WebClient)sender;
Type t = typeof(WebClient).GetNestedType("DownloadBitsState", BindingFlags.NonPublic);

FieldInfo m = t.GetField("InnerBuffer",BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);

Debug.WriteLine(m.GetValue(c).ToString());

I get a runtime error: FieldAccessException (System.Net.WebClient+DownloadBitsState.InnerBuffer)

Is there any way I can read this field or I simply cannot read the contents of internal fields?

+1  A: 

The instance is incorrect.

You cannot pass a WebClient type instance when the FieldInfo expects a DownloadBitsState instance.

leppie
I'm curious - how would I pass the actual WebClient instance, rather than t - which is just a type without actual data?
Dennis Delimarsky
Even if I use Debug.WriteLine(m.GetValue(c.GetType().GetNestedType("DownloadBitsState", BindingFlags.NonPublic)).ToString()); - it still throws the same exception.
Dennis Delimarsky
@Dennis Delimarsky: Well now it's a `Type` instance. What are you trying to do? I didn't see any instance of `DownloadBitsState` inside `WebClient`.
leppie
`DownloadBitsState` is a private class inside `WebClient`. I want to access its internal byte buffer to get the data while it is being downloaded, so that's why I need to get the array contents for `InnerBuffer`, which is a field marked as `internal` in `DownloadBitsState`
Dennis Delimarsky
@Dennis Delimarsky:That still does not give you an instance to grab hold of, to pass to `FieldInfo.GetValue`.
leppie
Any suggestions on what I might try to get the actual instance? For now Reflection is the only way I can think of, but I might be missing something.
Dennis Delimarsky
@Dennis Delimarsky: I cant even see a way to do it with reflection. If possible at all, it will be extremely tricky, and probably very fragile. Is there no other way to get to this information? Maybe a native call or WMI, etc?
leppie
I don't think I can access the `WebClient` buffer via WMI and it seems like there is no documented way to actually get it other than wait till it's completed. In my case - it never completes.
Dennis Delimarsky
What exactly are you trying to do? Why not just call WebClient.OpenRead() and read from the stream? That will also give you the bytes that you need.
feroze
Windows Phone 7 doesn't support synchronous operations for WebClient, therefore I have to work with the Async version. I need to read the obtained stream before the download completes (it actually is never completed - it's a continuous stream) - therefore read it while WebClient is still downloading.
Dennis Delimarsky
@Dennis Delimarsky: This is the first time you mention Windows Phone 7. Please specify that in the question, as I have based all answers on normal .NET 3.5.
leppie
A: 

It's possible that the field you want is write only. Use reflector to look at the source to see what is going on. If it's write only then you will need to access the private field.

Also: He IS passing in the reference using m.GetValue(c) as c is the instance of sender cast as Webclient.

BTW: Make sure WebClient is not null.

--Edit: After posting my answer I realize that you're trying to access a property of a type that isnt instantiated. Doh! Does Webclient have a property that has an instance of DownloadBitsState? Use that, THEN pull the property

--Edit: Looking at the code, the only method in webclient that instantiates DownloadBitsState is private byte[] DownloadBits()

private byte[] DownloadBits(WebRequest request, Stream writeStream, CompletionDelegate completionDelegate, AsyncOperation asyncOp)
{
    WebResponse response = null;
    DownloadBitsState state = new DownloadBitsState(request, writeStream, completionDelegate, asyncOp, this.m_Progress, this);
    if (state.Async)
    {
        request.BeginGetResponse(new AsyncCallback(WebClient.DownloadBitsResponseCallback), state);
        return null;
    }
    response = this.m_WebResponse = this.GetWebResponse(request);
    int bytesRetrieved = state.SetResponse(response);
    while (!state.RetrieveBytes(ref bytesRetrieved))
    {
    }
    state.Close();
    return state.InnerBuffer;
}

So, you can't really do what you want in the way you want.

DustinDavis
This has been all discussed in the comments of my answer. Also, it appears now, this is for Windows Phone 7.
leppie
Ieppie, some of it yes but i've given him an exact answer of 'No' he can't do it that way because of how DownloadBitsState is being used.
DustinDavis