I am having some issues finding information about adding some logic field in my RestRequest using V 107. I am trying to add a filter to my GET query
dl_document_indexed_date gt '2020-12-07T08:30:42.483Z'
There are a few other queries in the call which i am using Dictionary<string, string> to store them, and it works great however it only works if i am looking for something equal to, as adding it to the parameters it seems by default its equal to and i am not finding any way to add any other logic, gt/ge/lt/le etc. using the older version i would just append the url adding the logic i need, but i am not seeing a way to append the url either. Looking over their documentation i either missed it, cant find it, or its not there. Any help would be greatly appreciated! My method looks like this
public static async Task<string> GET_API(String RequestUrl, string RequestObject, Dictionary<string, string> parameters)
{
var request = new RestRequest(RequestObject);
var options = new RestClientOptions(RequestUrl)
{
ThrowOnAnyError = true,
Timeout = -1
};
var client = new RestClient(options);
client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator("Bearer " + TokenManager.GetAccessTokenString("TRN"));
foreach (var parameter in parameters)
{
request.AddQueryParameter(parameter.Key, parameter.Value);
}
var response = await client.GetAsync(request);
return response.Content.ToString();
}
I send the BaseURL , the RequestObject would be table i am calling in the base URL, and my dictionary item contains the Field name, and the field values that i am dynamically generating on another method that would append the string. and example would be
parameters.Add("dl_document_name", "TableA");
which would append the URL with dl_document_name eq 'TableA'
it would call the API after i add the OAuth Token i create and return the data i need and send it back. or another option i guess could be appending the string with the logic i need to return the data
You should use OData, it's easy to implement and it has different kind of filters, you also can set which filters are usable and which aren't.
https://www.odata.org/
I figured out a work around, if i only have one i can add it to the first parameter and adding the filter as the first key, which will work unless i have multiple conditions that are not eq
parameters.Add("filter","dl_document_indexed_date gt '2020-12-07T08:30:42.483Z'");
Related
I'm trying to generate an url like,
www.example.com/Example?someOption=true&anotherOption=false&filter=testFilter&filter=testFilter2&filter=testFilter3
I have been using StringBuilder so far for the task but I'd like to think it's not the appropriate way of doing it. As a result, I came to conclusion that I should be generating this link using Uri class and not StringBuilder or any string extensions. Soon after, I came across QueryHelpers.AddQueryString. The issue with that is, it's using Dictionaries to add query parameters and adding an identical parameter ('filter' in my example) is just not possible.
Just wondering is there any other built in function or library that I can use to cleanly generate my urls with identical query parameters?
One of the overloads to QueryHelpers.AddQueryString takes an enumerable of key/value pairs. This means you can create your own 'dictionary' like this:
var filters = new List<KeyValuePair<string, string>>
{
new KeyValuePair("filter","testFilter1"),
new KeyValuePair("filter","testFilter2"),
new KeyValuePair("filter","testFilter3"),
}
Then you can call
var uri = QueryHelpers.AddQueryString("www.example.com", filters);
A little more elegant:
public async Task<HttpResponseMessage> GetAsync(string url, Action<HttpRequestHeaders> headers, Action<HttpRequestParameters> parameters)
{
using (var client = new HttpClient())
{
var _httpRequestParameters = new HttpRequestParameters();
headers?.Invoke(client.DefaultRequestHeaders);
if (parameters != null)
{
parameters.Invoke(_httpRequestParameters);
var query = _httpRequestParameters.GetQueryString();
url += query;
}
return await client.GetAsync(url);
}
}
I have an Excel file loaded into Office 365 that is accessible via the Microsoft Graph API with many named ranges, some are individual values, some are blocks of cells.
I can successfully update individual values using the API, but when I try to update multiple cells at the same time, I run into problems.
For this example, consider a single 3-cell array from F10:F12
I would like to populate as follows:
F10 = A
F11 = B
F12 = C
So, I create list of strings that ends up looking like this...
[ ["A"], ["B"], ["C"] ]
and I pass it to the Graph API using the following code...
public static async Task<WorkbookRange> UpdateRangeArray(string strItemId, string strSheetName, string strRangeName, List<string> strRangeValues, string strSessionId)
{
string[][] strValueArray = new string[strRangeValues.Count][];
try
{
int i = 0;
foreach (var val in strRangeValues)
{
strValueArray[i] = new string[1] { val };
i++;
}
}
var jsonValueArray = JsonConvert.SerializeObject(strValueArray);
var rangeUpdate = new Microsoft.Graph.WorkbookRange();
rangeUpdate.Values = jsonValueArray;
var result = await graphClient.Users[_strUserId].Drive.Items[strItemId].Workbook.Worksheets[strSheetName]
.Range(strRangeName)
.Request()
.Header("workbook-session-id", strSessionId)
.PatchAsync(rangeUpdate).ConfigureAwait(false);
return result;
}
So I am able to update the values in the range, EXCEPT instead of the expected values, what I get is this...
F10 = [ ["A"],["B"],["C"] ]
F11 = [ ["A"],["B"],["C"] ]
F12 = [ ["A"],["B"],["C"] ]
Instead of the Graph API putting the first value in the first cell, second value in the second cell, and so forth... It puts the entire array of data in each cell.
I assume this is some sort of formatting error, maybe my JSON is malformed or perhaps I'm submitting it using the wrong Graph API endpoint or something.
Any help would be greatly appreciated...
UPDATE 1:
I also tried doing this with the RANGE (ie - .Range("F10:F12")) instead of using the NAME and I get the same result.
UPDATE 2:
Cross-posted on GitHub in case this is a bug not just a user error.
https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/695
UPDATE 3:
I can successfully PATCH via the Graph API Explorer to the following URL...
https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/workbook/worksheets/INPUTS/range(address='F10:F12')
with this body...
{"values":[["Hello"],["How"],["Are You?"]]}
...and it works.
but still can't get it to work via the MSGraph-SDK-dotnet
UPDATE 4:
I AM able to get it to work correctly using Postman and the resulting RestSharp code that works looks like this...
public static async Task TestUpdatePostman()
{
var client = new RestClient("https://graph.microsoft.com/v1.0/users/{USER-ID}/drive/items/{ITEM-ID}/workbook/worksheets/INPUTS/range(address='F10:F12')");
client.Timeout = -1;
var request = new RestRequest(Method.PATCH);
request.AddHeader("Authorization", "Bearer {INSERT-TOKEN}");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\"values\":[[\"Hello\"],[\"How\"],[\"Are You?\"]]}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
This again makes me believe there's an issue with the way the SDK wrapper implements the API call.
It might not be a SDK issue. When updating the range, rangeUpdate.Values should be a JToken type instead of a string.
Try using:
JArray jsonValueArray = JArray.FromObject(strValueArray);
I have a GET end point which will take user name as parameter. Below is the action
[Route("user/{userName}")]
public User GetUserByName([FromUri] string userName)
{
// logic here
}
This is how i make the request.
var restClient = new RestClient("uri");
var request = new RestRequest("user/" + userName);
var response = restClient.Execute(request);
It worked fine for all cases till a user with name containing forward slash came.
Eg: Akbar/Badhusha
Then the request will looks like user/Akbar/Badhusha
This causing the request to return Not Fount error
I tried to add the parameter with AddQueryParameter method. All returning Not found error.
I also tried HttpUtility.UrlEncode
Also tried replacing / with %2f
Also tried user?userName=Akbar/Badhusha
All of them failed.
Is there any way to make it work?
Try removing [FromUri] from the parameter as shown below,
[Route("user")]
public User GetUserByName(string userName)
{
// logic here
}
And the request may look like,
user?userName=Akbar/Badhush
We're working on developing an application that uses Plivo for sending and receiving SMS messages. For every request that Plivo sends, they also send a signature in the HTTP header so that we can verify the request came from Plivo and not from a random user.
https://www.plivo.com/docs/xml/request/#validation
To do this validation, we require the POST content as a query string (eg: To=15555555555&From=11234567890&TotalRate=0&Units=1&Text=Text!&TotalAmount=0&Type=sms&MessageUUID=2be622bc-79f8-11e6-8dc0-06435fceaad7).
Current solution
This is what we have so far:
private bool VerifyPlivo(object thing, HttpRequestMessage Request)
{
if (Request.Headers.Contains("X-Plivo-Signature"))
{
Dictionary<string, string> reqParams = (from x in thing.GetType().GetProperties() select x).ToDictionary(x => x.Name, x => (x.GetGetMethod().Invoke(thing, null) == null ? "" : x.GetGetMethod().Invoke(thing, null).ToString()));
IEnumerable<string> headerValues = Request.Headers.GetValues("X-Plivo-Signature");
string signature = headerValues.FirstOrDefault();
return XPlivoSignature.Verify(Request.RequestUri.ToString(), reqParams, signature, plivoToken);
}
else
{
return false;
}
}
[Route("RecieveSMS")]
[HttpPost]
public HttpResponseMessage RecieveSMS(PlivoRecieveSMS req)
{
if (!VerifyPlivo(req, Request))
{
return new HttpResponseMessage(HttpStatusCode.Forbidden);
}
... // do actual work here
}
This works by using the object that it maps to PlivoRecieveSMS and doing some reflection to get the properties and values, and sticking them in a Dictionary. This works well especially given our lack of the preferred solution...
Preferred solution
Right now, we require a model (PlivoRecieveSMS) to map the data, and then do introspection to find the key/values. We would like to move the logic to an extension of System.Web.Http.AuthorizeAttribute, so that we can do something as simple as:
[AuthorizedPlivoApi]
[Route("RecieveSMS")]
[HttpPost]
public HttpResponseMessage RecieveSMS(PlivoRecieveSMS req)
{
... // do actual work here
}
The actual authorization is done in AuthorizedPlivoApi - if it's not valid, the request never reaches the controller. But we cannot do this at the moment because we can't map it to a specific object inside of AuthorizedPlivoApi.
I would like to access the POST key's / values directly, or perhaps map it to a dynamic object that isn't pre-defined before hand. If I can do that, we can then achieve our preferred solution.
tl;dr: is there any way to push application/x-www-form-urlencoded data from a POST request into a Dictionary<string,string>() without using a specific model?
I'm working with a rather large query string(~30+ parameters) and am trying to pass them to a WCF service I've setup.
I've run into a few issues specifically with the UriTemplate field. This service is setup to access a third party Api, so the query string may or may not contain all parameters. I'm curious if the best approach is to build a query string and pass that to the WCF service or to pass each parameter(and in some cases String.Empty) individually.
I've currently tried to dynamically build up a query string, however have hit a wall with either a 403 error when I try to pass the entire string( "?prm1=val&prm2=val" ) into the uritemplate of "ApiTool.jsp{query}", or I hit an invalid uritemplate response due to the fact I don't have name/value pairs listed.
I am pretty sure you'll need to list the parameters individually. Otherwise, UriTemplate will end up escaping things for you:
var ut = new UriTemplate("Api.jsp{query}");
var u = ut.BindByName(new Uri("http://localhost"), new Dictionary<string, string>() { { "query", "?param1=a¶m2=b" } });
Console.WriteLine(u); // http://localhost/Api.jsp%3Fparam1=a¶m2=b
You can 'unescape' querystring with IClientMessageInspector.
public class UriInspector: IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// change/replace request.Headers.To Uri object;
return null;
}
}
See MSDN how to add this to your Endpoint object.