How can I preserve the QueryString semantics when converting an MFC CHttpServer based web server to ASP.Net? - asp.net

In a legacy MFC CHttpServer based web server, we have a command parsing map something like this:
BEGIN_PARSE_MAP(MyHttpServer, CHttpServer)
ON_PARSE_COMMAND(MyPage, MyHttpServer, ITS_I4 ITS_I4 ITS_I4 ITS_I4 ITS_PSTR ITS_PSTR ITS_PSTR ITS_I4)
ON_PARSE_COMMAND_PARAMS("intParam1=11 intParam2=12 intParam3=13 intParam4=14 strParam5=s5 strParam6=s6 strParam7=s7 intParam8=18")
END_PARSE_MAP(MyHttpServer)
This defines a page accessible at http://host/path/dllname.dll?MyPage that accepts up to 8 parameters named intParam1, intParam2, intParam3, intParam4, strParam5, strParam6, strParam7, and intParam8.
The calling applications can invoke the page with the parameters in a named fashion like this:
http://host/path/dllname.dll?MyPage?intParam4=32&strParam7=somestring
But the way MFC command parsing maps work, they can also call it with unnamed parameters as long as they are provided in the order defined by the map:
http://host/path/dllname.dll?MyPage?21&22&23&24&string5&string6&string7&28
I would like to replace this old code with an ASP.Net page, but we have existing calling applications that will not be changed that invoke the page using both styles of parameter passing, named and unnamed.
I can easily manage the necessary URL rewriting to allow an ASP.Net page to respond to the URL as given above, replacing the path/dllname.dll? MyPage portion with the path to an .aspx page or .ashx handler.
The problem comes in when trying to handle the unnamed parameters in an equivalent fashion to the old MFC parameter parser. Request.QueryString treats all the unnamed parameters as being named with null and Request.QueryString[null] returns a comma-separated list of the values. This is pretty close to workable, but should one of the parameters actually contain a comma, this encoding falls apart because the extra comma is not escaped and splitting the string on the commas will end up with too many parameters.
In classic ASP, I believe Request.QueryString(...) returned a collection of all the parameters that were identically named. There seems to be no equivalent to that in ASP.Net that I can find.
As a secondary issue, the MFC command parsing map had some pretty convoluted logic for dealing with a mixture of named and unnamed parameters. Although the callers of the page in question will not be mixing their usage in this way, I am interested in perhaps duplicating the logic for completeness sake. Can anyone confirm that MFC's behavior was essentially the following?
Process all parameters in the URL from left to right, using & as separator.
If named (has an equal sign), apply the value to the parameter with the corresponding name, regardless of its position. If that parameter already assigned a value, error.
If unnamed, apply the value to the parameter at the nth position in the command parsing map, where n is the number of already processed unnamed parameters plus 1. If that parameter was already assigned a value, error.
Apply default values from command parsing map to any parameters not assigned above
If any parameters from command parsing map have not been assigned a value, error.
One more interesting note, it appears that Request.QueryString.ToString() will nearly reconstitute the original parameters on the URL, but it always moves the parameters with identical names to be together, including the unnamed parameters I am concerned with here.

Not sure if solves your problem, but you could try using Request.PathInfo. This will give you everything entered after the page, which you could then parse manually using something like a regex.
For example, if you had the URL:
http://host/path/dllname.dll?MyPage?21&22&23&24&string5&string6&string7&28
The Request.PathInfo property would return:
?MyPage?21&22&23&24&string5&string6&string7&28
Processing this into a set of values that you can work with could also be problematic as you've got both named and un-named parameters, but this should be achievable using regular expressions and/or splitting the string.

I found that Request.QueryString has a GetValues() method. This returns an array of strings and solves the problem of a comma being embedded within one of the values. It'll be even easier to use than having to split the results of Request.QueryString[null].
I still have a bit of work to use this to implement an MFC-like mapping of URL parameters that handles both named and unnamed parameters.

Related

Kusto's `parse_json` doesn't work on custom dimensions

I'm hoping to be able to analyze structured data stored in a custom dimension of a custom telemetry event emitted to application insights, and getting some weird behavior. It seems like the JSON can't be parsed normally, but if I pass it through strcat it is able to parse the json just fine.
customEvents
| where name == "PbConfigFilterComponentSaved"
| take 1
| project
jsonType=gettype(customDimensions.Json),
parsedType=gettype(parse_json(customDimensions.Json)),
strcatType=gettype(strcat('', customDimensions.Json)),
strcatParsedType=gettype(parse_json(strcat('', customDimensions.Json)))
Result:
jsonType: string
parsedType: string
strcatType: string
strcatParsedType: dictionary
Is there a better approach to getting parse_json to work on this kind of value?
Update
In case it's in any way relevant, here's the value of customDimensions.Json:
{"filterComponentKey":"CatalystAgeRange","typeKey":"TemporalConstraint","uiConfig":{"name":"Age","displayMode":"Age"},"config":{"dateSelector":"pat.BirthDTS"},"disabledForScenes":false,"disabledForFilters":false}
Could you please demonstrate a sample record that isn't parsed correctly?
Speculating (before seeing the data): Have you verified the final paragraph here doesn't apply to your case?
It is somewhat common to have a JSON string describing a property bag in which one of the "slots" is another JSON string. […] In such cases, it is not only necessary to invoke parse_json twice, but also to make sure that in the second call, tostring will be used. Otherwise, the second call to parse_json will simply pass-on the input to the output as-is, because its declared type is dynamic.
The type of customDimensions is dynamic and so accessing a property like customDimensions.json from it will return a string typed as dynamic.
You have to explicitly cast it as string and then parse it:
todynamic(tostring(customDimensions.json)).property
I think the "Notes" section in the documentation is exactly the issue, as mentioned by Yoni L. in the previous answer.

How to customize segment using query string or cookie in Adobe CQ5.6?

How to customize segment using query string or cookie in Adobe CQ5.6?
My requirement as follows:
I wanted to target querystring parameters in Segment which is added in my Experience, Teaser, Promotion, Voucher for owned site.
Thanks in advance.
You can define your own segment at outlined here: https://docs.adobe.com/docs/en/cq/5-6-1/administering/segmentation.html#Defining%20a%20New%20Segment
In step 6 where you edit the segment, you need to supply a JavaScript expression that will resolve to a boolean, true or false. You can put any JavaScript expression here that meets your need, so you can include script that will have a complex expression if you want. But rather than write a complex JavaScript expression here, it would be better to write JavaScript that exposes a function which returns true or false and then include that JavaScript function on your pages via a client library. Then, in the segment, you can simply invoke the function rather defined in your client library than try to write a complex expression.
As long as the JavaScript expression defined in the segment evaluates to true/false, the segment will be usable.
Without your own JavaScript you can easily fetch query string values of look at cookies. See these other questions for details on that:
What is the shortest function for reading a cookie by name in JavaScript?
How can I get query string values in JavaScript?

ASP.Net QueryString Sort Parameter with Dojo JsonRest Memory Store

I have made a gridx grid that uses a JsonRest Memory store from the dojo framework
http://dojotoolkit.org/reference-guide/1.10/dojo/store/JsonRest.html
the issue is I do not know how to pull out the sort parameter from the query string.
The url being formatted from the JsonRest call is
/admin/sales?sort(+DealershipName)
using the following statement gives me a null error
String sort = Request.QueryString["sort"].ToString();
Looking at the debugger I see the following (I need more rep to post images :( )
ok I can see that the following variables hold this value.
Request.QueryString = {sort(+DealershipName)}
type : System.Collections.Specialized.NameValueCollection
{System.Web.HttpValueCollection}
but the array is null.
I'm thinking I can do two thing. Parse the string myself or overload the dojo JsonRest Memory store. Parsing the string seems easier but if anyone has any idea or knows any libraries that can help me out. I would greatly appreciate it.
dojo/store/JsonRest has a sortParam property that you can set to the name of a standard query parameter to use instead of sort(...) (which it uses by default to avoid colliding with any standard query parameters).
For example, adding sortParam: 'sort' to the properties passed to the JsonRest constructor will result in the query string including sort=+DealershipName instead.
http://dojotoolkit.org/reference-guide/1.10/dojo/store/JsonRest.html#sorting
If the + also presents a problem, you can also override ascendingPrefix to be an empty string (''). Note that descending sort will still be indicated by a leading - (controllable via descendingPrefix).

How do I omit a parameter in a JScript ADO/ASP classic method call?

How do I omit a parameter in a JScript ADO/ASP classic method call?
For example, a RecordSet object has a GetString method (e.g. recordset.GetString(StringFormat, NumRows, ColumnDelimiter, RowDelimiter, NullExpr), where all parameters but the first are optional.
If I want to skip a parameter in VBScript (e.g., use the default for one parameter) I can do recordset.GetString 2, , "|", or use named parameters.
However, it doesn't seem like I can do the same with JScript. I've tried using null for the optional parameter, using an empty string (''), omitting it entirely (as with VBScript), and using JSON-style named parameters, with no luck.
Am I missing something, or is this not possible?
If you believe this statement
In VBScript, it is legal to omit parameters to function calls, by
writing a comma only, as in:
adoCmd.Execute , , adExecuteStream
In JavaScript, this is not legal, but in all cases so far, we have
been able to work around that in some way, mostly by specifying null
or zero in place of the missing parameters.
you can avoid to mix languages, if you come up with a specific strategy for each ADO method call. For your .GetString() case, the appropriate zilch value is -1. My evidence for the correctnes of this (specific) solution:
-1 'works' in VBScript too
other funny numerical values (0, -10) - and (surprisingly) undefined - throw 'Operation is not allowed' errors
"" and null throw a type error
This is not possible in pure JScript. To use the default parameter values, you need to explicitly specify these values in the method call (provided, of course, that you know what these values are).
A possible option is to use a mix of JScript and VBScript code, e.g. call the GetString function from VBScript and return its result to JScript. Some examples (that should give you the idea): WSH, HTA, ASP.

Optional Invalid Query String Variables

This is a somewhat philosophical issue. I have a .net (but could be any platform) based helper library that parses query string values. Take for example a variable that returns an Int32: my framework has an option that specifies whether this value is required or optional. If it is required but not provided, the framework throws an exception. If it is optional and not specified, it returns a null.
Now an edge case has come up based on users hacking (in a good way) our urls. If they specify a variable with either an invalidly formatted Int32 ("&ID=abc") or provide the variable but not specify a value ("&id="), should the framework throw an exception or should it return a null?
Part of me feels that invalid variables or formats should return a null. It might be valid to argue that even if the parameter is optional, an invalidly formatted query string or value should still throw an exception.
Thoughts?
Since this is philophical ...
On something like an ID, I would agree with Shawn that it is a 404, especially if you are thinking in terms of state. There is no object, so not found. But, ID may not tie directly to a resource in all cases.
If the item is truly optional, a null is okay. But optional should mean "if present it makes the call more specific" in this case and there should always be a fallback. I don't see this in ID, unless the ID is keyed to an optional part of the page.
In the long run, I think you should look at the business reason for the page and what each variable means.
I believe that if a variable is optionaly, providing the variable but not specifying the value is equivalent to ommitting the variable itself. In this case, returning null seems OK.
However, providing an invalidly formatted value ought to cause an Exception, since the intent was to provide a value. In this case the user ought to be notified through some sort of validation mechanism.
A HttpException of 404 (Not Found). Your web application framework should know how to catch these errors and redirect to the proper page.
This is actually a not found error because the resources that the ID is pointing to does not exist.
I suspect there's no "right" answer to your question. If I were a developer using your library, I would expect/hope that the public API would include in its code comments, a description of how the function behaves when the URL param includes bad (wrong type) data.
You might also be able to craft your public API to get the best of both worlds: .NET seems to have adopted the "Parse" / "TryParse" approach in many places. If I'm the caller and I want the function to throw if given invalid data, I call Parse(). If I don't want it to throw, I call TryParse(). In my opinion, that is a nice pattern to follow with your API as well.

Resources