Вопрос

I am trying to use request elements from an ASP application in a .NET class library that is used in the application. I came across a head scratcher that I can't wrap my head around:

//Context is an ASPTypeLibrary.ScriptingContext
dynamic req = System.EnterpriseServices.ContextUtil.GetNamedProperty("Request");
Context.Response.Write(req.Form("mykey")); //this writes the value I expected
Context.Response.Write(String.Format("{0}", req.Form("mykey")));  //this writes 'System.__ComObject'

Am I going about this all wrong? I was using info I gleaned from this question.

Это было полезно?

Решение

You should note that Request.Form("someKey") is not a string. The source of your confusion, however, originates not in Request.Form("someKey") but on the other side, in Response.Write(...).

There are some automatic conversion shenanigans going on.

Request.Write(...) doesn't take a string. It takes a Variant. The method will do its darnest to output whatever you pass to it.

If the Variant holds a BSTR (a COM string), it will output that unchanged. It will also try calling VarChangeTypeEx(...) (kind-of; see note below) to try to see if it can get COM to convert it to a BSTR (that's what happens when you pass it a number). If the Variant contains an object with a default method on it ([propvalue]), and it has no better way to output it, it will call the default method and start over with the result of that. I think it has a few other tricks up its sleeve, which are not entirely clearly documented.

At a high level, it should now be clear what's happening. On the first line, req.Form("myKey") returns a COM object, which then gets passed down to Response.Write(...), which then converts that object to a BSTR string and outputs it. On the other hand, when you try to pass req.Form("myKey") to a C# method, the conversion doesn't occur and you get a generic COM object instead, with predictable consequences.

So what is the return value of Request.Form("someKey") then? It's an IRequestDictionary object. And why a dictionary? Because you can submit an http request that has multiple form elements with the same name. This can be the case, for example, when the input elements are checkboxes intended to be overlapping options.

What happens when the form has multiple entries? The conversion process returns a joined string analog to String.Join(", ", someArray) in C#.

It's not clear to me whether Response.Write has intimate knowledge of IRequestDictionary (unlikely), or whether it knows about COM Enumerator pattern (more likely) and it enumerates them to compose the string.

More interesting to me is who is responsible for the conversion process, because VBScript's CStr() will do the same conversion. I had always assumed that CStr() was a thin wrapper around VarChangeTypeEx(...), but I'm pretty sure that VarChangeTypeEx(...) does not concatenate enumerators like that. Obviously CStr() is a lot fancier than I had assumed. I believe that Response.Write simply calls internally whatever API fully implements CStr() and relies on that for the conversion.

For further exploration of the Classic ASP objects and interface, try http://msdn.microsoft.com/en-us/library/ms524856(v=vs.90).aspx instead of the usual VBScript-based descriptions.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top