Fetch nested query parameters in URL - asp.net

I have a URL which which has a query parameter that itself contains a query string with other parameters. E.g:
https://discovery.com/disco.ashx?entityId=www.test.com&return=https://myidp.com/?param1=myvalue
How do I get the value of the nested param1?
I have tried something like this but it doesn't work:
var returnParam = context.Request.QueryString["return"];
var test = HttpUtility.ParseQueryString(returnParam);
var value = test["param1"];

you can try this - var u = new Uri(returnParam); var newparams = u.Query;

HttpUtility.ParseQueryString expects only the query string as input.
Extract the query string from the url using Uri and then pass that to HttpUtility.ParseQueryString
var uri = new Uri(Request.QueryString["return"]);
var queryParams = HttpUtility.ParseQueryString(uri.Query);
var value = queryParams["param1"];

Related

How to set the id of document of firestore using google sheets

I've got a table in google sheets which I want to upload to the firstore using a custom document id to prevent data duplication. How can I change the id of the document.
Full Code:
function classRoutineFunction() {
var firestore = FirestoreApp.getFirestore (email, key, projectId);
// get document data from ther spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Sheet1";
var sheet = ss.getSheetByName(sheetname);
// get the last row and column in order to define range
var sheetLR = sheet.getLastRow(); // get the last row
var sheetLC = sheet.getLastColumn(); // get the last column
var dataSR = 2; // the first row of data
// define the data range
var sourceRange = sheet.getRange(2,1,sheetLR-dataSR+1,sheetLC);
// get the data
var sourceData = sourceRange.getValues();
// get the number of length of the object in order to establish a loop value
var sourceLen = sourceData.length;
// Loop through the rows
for (var i=0;i<sourceLen;i++){
if(sourceData[i][1] !== '') {
var data = {};
var dateSt = sourceData[i][0].toString();
var stDate = new Date(dateSt);
var stringfied = JSON.stringify(stDate);
var updatedDt = stringfied.slice(1,11);
data.date = updatedDt;
data.time = sourceData[i][1];
data.batch = sourceData[i][2];
data.topic = sourceData[i][3];
data._id = dateStr + batch; // Want to set a custom id
firestore.createDocument("classRoutine",data);
}
}
}
You can pass the name of the new document into the string argument when calling createDocument. From the documentation on creating documents in Firestore from your script:
Alternatively, we can create the document in the FirstCollection collection called FirstDocument:
firestore.createDocument("FirstCollection/FirstDocument", data)
Here FirstDocument is the name of the document in FirstCollection.
So for you this would look something like:
firestore.createDocument("classRoutine/yourCustomId",data);

SqlQuerySpec parameterized query returns no results

I'm not sure whether it is an emulator issue or not but i have a really simple query
var collectionUri = UriFactory.CreateDocumentCollectionUri(Constants.CosmosDbName, CollectionName);
var spec = new SqlQuerySpec()
{
QueryText = "SELECT * FROM Users u WHERE u.firstName = #firstname",
Parameters = new SqlParameterCollection
{
new SqlParameter{
Name = "#firstname",
Value = value
}
}
};
var query = client.CreateDocumentQuery<User>(collectionUri, spec);
var users = await query.ToListAsync();
the parametrized query returns no results i.e. 0 users
while the same plain query below retuns 1 user that matches the WHERE condition:
spec.Parameters.Clear();
spec.QueryText = $"SELECT * FROM Users u WHERE u.firstName = '{value}'";
query = client.CreateDocumentQuery<User>(collectionUri, spec);
users = await query.ToListAsync(); // returns 1 user
do I need somehow explicitly enable parameterized queries
or am I doing something wrong above with a parameterized query?
According to the Syntax, your query should be like this,
SqlQuerySpec sqlQuerySpec = new SqlQuerySpec
{
QueryText = #"SELECT *
FROM Users u
WHERE u.u.firstName = #firstname",
Parameters = new SqlParameterCollection
{
new SqlParameter("#firstname", value)
}
};
The issue is a kind of var pitfall
the SqlParameter value was taken from an Azure function HttpRequest request:
var value = req.Query["firstname"];
which is
Microsoft.Extensions.Primitives.StringValues value = req.Query["firstname"];
When SqlParameter is created with value of StringValues type it makes slightly different query:
SELECT * FROM Users u WHERE u.firstName = ['Dima']
the brackets ['Dima'] here are excess
the correct query must be without brackets
SELECT * FROM Users u WHERE u.firstName = 'Dima'
so to fix the parameterized query the parameter value should be a string
new SqlParameter("#firstname",value.ToString())

parsing dynamo db queryresponse to object

I'm using DynamoDB to query a table with the following commands
QueryRequest request = new QueryRequest
{
TableName = "Events",
ExclusiveStartKey = startKey,
KeyConditions = keyConditions,
IndexName = "Title-index" // Specify the index to query against
};
// Issue request
QueryResponse result = client.Query(request);
The ExclusiveStartKey and Keyconditions are predefined
The issue is that the QueryResult result variable is not parsed to my native object, when I use the DynamoDB.Context you cast the method with the expected type, but in this case I need to parse the QueryResult...
Is there any other way to do this?
Or should I parse the object?
I ended up using something like:
using System.Linq;
...
// Issue request
QueryResponse result = AmazonDynamoDBClient.Query(request);
var items = result.Items.FirstOrDefault();
var doc = Document.FromAttributeMap(items);
var myModel = DynamoDBContext.FromDocument<MyModelType>(doc);
What you want is some sort of ORM - a nice read is Using Amazon DynamoDB Object Persistence Framework. Also check out the API reference that also shows samples
Take a look at the examples from Querying Tables Using the AWS SDK for .NET Low-Level API documentation
In your handling method
var response = client.Query(request);
var result = response.QueryResult;
foreach (Dictionary<string, AttributeValue> item in response.QueryResult.Items)
{
// Process the result.
PrintItem(item);
}
PrintItem implementation
private static void PrintItem(Dictionary<string, AttributeValue> attributeList)
{
foreach (KeyValuePair<string, AttributeValue> kvp in attributeList)
{
string attributeName = kvp.Key;
AttributeValue value = kvp.Value;
Console.WriteLine(
attributeName + " " +
(value.S == null ? "" : "S=[" + value.S + "]") +
(value.N == null ? "" : "N=[" + value.N + "]") +
(value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") +
(value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]")
);
}
Console.WriteLine("************************************************");
}
I was stuck on the same issue, and found that by using Table.Query with a QueryOperationConfig I could specify the index that I wanted to use. Because the Document object returned from this query has a "ToJson()" method on it, I was able to convert the results of the query to Json, and then use Json.Net to Deserialize it back into my object which worked flawlessly for my totally flat object.
var queryFilter = new QueryFilter(indexedColumnName, QueryOperator.Equal, targetValue);
Table table = Table.LoadTable(client, Configuration.Instance.DynamoTable);
var search = table.Query(new QueryOperationConfig { IndexName = indexName, Filter = queryFilter });
List<MyObject> objects = new List<MyObject>();
List<Document> documentSet = new List<Document>();
do
{
documentSet = search.GetNextSetAsync().Result;
foreach (var document in documentSet)
{
var record = JsonConvert.DeserializeObject<MyObject>(document.ToJson());
objects .Add(record);
}
} while (!search.IsDone);
Hope it helps you out!

ASP.NET calling stored proc with LINQ and passing in DataTable

What am I doing wrong?
Trying to pass in my DataTable to a stored proc using LINQ. Below is my code.
var sqlCommand = new System.Data.SqlClient.SqlCommand {
CommandType = System.Data.CommandType.StoredProcedure,
CommandText = "UserIdList"
};
var dataTable = new System.Data.DataTable("IdList");
dataTable.Columns.Add("AttributeIds", typeof(Int32));
dataTable.Rows.Add(26);
dataTable.Rows.Add(40);
dataTable.Rows.Add(41);
dataTable.Rows.Add(45);
dataTable.Rows.Add(78);
dataTable.Rows.Add(33);
dataTable.Rows.Add(36);
//The parameter for the SP must be of SqlDbType.Structured
var parameter = new System.Data.SqlClient.SqlParameter {
ParameterName = "#AttributeIds",
SqlDbType = System.Data.SqlDbType.Structured,
TypeName = "ecs.IDList",
Value = dataTable,
};
sqlCommand.Parameters.Add(parameter);
var user = myDC.DC.ExecuteQuery("exec ecs.udpUserAttributeDetails {0}, {1}", sqlCommand, userId).SingleOrDefault();
This seems to be the problem
var user = myDC.DC.ExecuteQuery("exec ecs.udpUserAttributeDetails {0}, {1}", sqlCommand, userId).SingleOrDefault();
In your code, you are passing a sqlCommand object as the first parameters and the userId as the 2nd parameter.
A data context ExecuteQuery method has 2 overloads
ExecuteQuery<TResult>(String, Object[])
ExecuteQuery(Type, String, Object[])
You seem to be using Overload 1 - i.e. ExecuteQuery<TResult>(String, Object[]) but in that case you need to specify the type of the returned object
eg :-
var customers = db.ExecuteQuery<Customer>(#"SELECT CustomerID, CompanyName, ContactName FROM dbo.Customers WHERE City = {0}", "London");
NOTE: db.ExecuteQuery<Customer> in the above example is what I am referring to.
I think this might be the cause of the error as the compiler is mapping your request to overload 2 instead which doesnt return any values but takes in 3 parameters resulting in your A query parameter cannot be of type 'System.Data.SqlClient.SqlCommand error.

NameValueCollection to URL Query?

I know i can do this
var nv = HttpUtility.ParseQueryString(req.RawUrl);
But is there a way to convert this back to a url?
var newUrl = HttpUtility.Something("/page", nv);
Simply calling ToString() on the NameValueCollection will return the name value pairs in a name1=value1&name2=value2 querystring ready format. Note that NameValueCollection types don't actually support this and it's misleading to suggest this, but the behavior works here due to the internal type that's actually returned, as explained below.
Thanks to #mjwills for pointing out that the HttpUtility.ParseQueryString method actually returns an internal HttpValueCollection object rather than a regular NameValueCollection (despite the documentation specifying NameValueCollection). The HttpValueCollection automatically encodes the querystring when using ToString(), so there's no need to write a routine that loops through the collection and uses the UrlEncode method. The desired result is already returned.
With the result in hand, you can then append it to the URL and redirect:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);
Currently the only way to use a HttpValueCollection is by using the ParseQueryString method shown above (other than reflection, of course). It looks like this won't change since the Connect issue requesting this class be made public has been closed with a status of "won't fix."
As an aside, you can call the Add, Set, and Remove methods on nameValues to modify any of the querystring items before appending it. If you're interested in that see my response to another question.
string q = String.Join("&",
nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
Make an extension method that uses a couple of loops. I prefer this solution because it's readable (no linq), doesn't require System.Web.HttpUtility, and it supports duplicate keys.
public static string ToQueryString(this NameValueCollection nvc)
{
if (nvc == null) return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (string key in nvc.Keys)
{
if (string.IsNullOrWhiteSpace(key)) continue;
string[] values = nvc.GetValues(key);
if (values == null) continue;
foreach (string value in values)
{
sb.Append(sb.Length == 0 ? "?" : "&");
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
}
}
return sb.ToString();
}
Example
var queryParams = new NameValueCollection()
{
{ "order_id", "0000" },
{ "item_id", "1111" },
{ "item_id", "2222" },
{ null, "skip entry with null key" },
{ "needs escaping", "special chars ? = &" },
{ "skip entry with null value", null }
};
Console.WriteLine(queryParams.ToQueryString());
Output
?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
This should work without too much code:
NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
The idea is to use HttpUtility.ParseQueryString to generate an empty collection of type HttpValueCollection. This class is a subclass of NameValueCollection that is marked as internal so that your code cannot easily create an instance of it.
The nice thing about HttpValueCollection is that the ToString method takes care of the encoding for you. By leveraging the NameValueCollection.Add(NameValueCollection) method, you can add the existing query string parameters to your newly created object without having to first convert the Request.QueryString collection into a url-encoded string, then parsing it back into a collection.
This technique can be exposed as an extension method as well:
public static string ToQueryString(this NameValueCollection nameValueCollection)
{
NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty);
httpValueCollection.Add(nameValueCollection);
return httpValueCollection.ToString();
}
Actually, you should encode the key too, not just value.
string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
Because a NameValueCollection can have multiple values for the same key, if you are concerned with the format of the querystring (since it will be returned as comma-separated values rather than "array notation") you may consider the following.
Example
var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");
Turn into: key1=val1&key2[]=val2&empty&key2[]=val2b rather than key1=val1&key2=val2,val2b&empty.
Code
string qs = string.Join("&",
// "loop" the keys
nvc.AllKeys.SelectMany(k => {
// "loop" the values
var values = nvc.GetValues(k);
if(values == null) return new[]{ k };
return nvc.GetValues(k).Select( (v,i) =>
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(v), i)
);
})
);
or if you don't like Linq so much...
string qs = nvc.ToQueryString(); // using...
public static class UrlExtensions {
public static string ToQueryString(this NameValueCollection nvc) {
return string.Join("&", nvc.GetUrlList());
}
public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) {
foreach(var k in nvc.AllKeys) {
var values = nvc.GetValues(k);
if(values == null) { yield return k; continue; }
for(int i = 0; i < values.Length; i++) {
yield return
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(values[i]), i);
}
}
}
}
As has been pointed out in comments already, with the exception of this answer most of the other answers address the scenario (Request.QueryString is an HttpValueCollection, "not" a NameValueCollection) rather than the literal question.
Update: addressed null value issue from comment.
The short answer is to use .ToString() on the NameValueCollection and combine it with the original url.
However, I'd like to point out a few things:
You cant use HttpUtility.ParseQueryString on Request.RawUrl. The ParseQueryString() method is looking for a value like this: ?var=value&var2=value2.
If you want to get a NameValueCollection of the QueryString parameters just use Request.QueryString().
var nv = Request.QueryString;
To rebuild the URL just use nv.ToString().
string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
If you are trying to parse a url string instead of using the Request object use Uri and the HttpUtility.ParseQueryString method.
Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
I always use UriBuilder to convert an url with a querystring back to a valid and properly encoded url.
var url = "http://my-link.com?foo=bar";
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("yep", "foo&bar");
uriBuilder.Query = query.ToString();
var result = uriBuilder.ToString();
// http://my-link.com:80/?foo=bar&yep=foo%26bar
In AspNet Core 2.0 you can use QueryHelpers AddQueryString method.
As #Atchitutchuk suggested, you can use QueryHelpers.AddQueryString in ASP.NET Core:
public string FormatParameters(NameValueCollection parameters)
{
var queryString = "";
foreach (var key in parameters.AllKeys)
{
foreach (var value in parameters.GetValues(key))
{
queryString = QueryHelpers.AddQueryString(queryString, key, value);
}
};
return queryString.TrimStart('?');
}
This did the trick for me:
public ActionResult SetLanguage(string language = "fr_FR")
{
Request.UrlReferrer.TryReadQueryAs(out RouteValueDictionary parameters);
parameters["language"] = language;
return RedirectToAction("Index", parameters);
}
You can use.
var ur = new Uri("/page",UriKind.Relative);
if this nv is of type string you can append to the uri first parameter.
Like
var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);

Resources