I am using the Bing Maps Api to calculate the route between two points.
I use the Rest Services in combination with the RestSharp library.
Problem is that I don't know how I can access the Route results.
The results are of type Resource. Route derives of Resource.
The Resource class is decorated with the KnownType attribute.
FYI I use the JSON datacontracts from msdn
Can someone help me?
Here is my code to calculate the route:
public static double CalculateDistanceKm(string street, string postalCode, string city, string country)
{
var client = new RestClient(BingMapsApiUrl);
var request = new RestRequest("Routes/Driving", Method.GET);
request.AddParameter("wp.0", Address);
request.AddParameter("wp.1", String.Format("{0},{1} {2},{3}", street, postalCode, city, country));
request.AddParameter("ul", "50.7541313,4.2486601");
request.AddParameter("key", BingMapsApiKey);
var response = client.Execute(request);
if (response.ResponseStatus == ResponseStatus.Completed)
{
var result = JsonConvert.DeserializeObject<Response>(response.Content);
if (result != null && result.StatusCode == 200 & result.ResourceSets.Any() && result.ResourceSets[0].Resources.Any())
{
//How to get to the Route instead of just Resource...
var test = result.ResourceSets.First().Resources.First();
}
}
return 0;
}
I switched the api from Bing to Google Maps.
The api is a lot easier to use and it gave me the right results.
With Bing I had a 9/10 change to get a "Not_found" error, tested with the SAME address!
So sometimes it works (1/10 chance).
With Google I get a correct result on each try...
Don't make the same mistake as I did, if you want to lookup address in another language than english then use Google Maps API.
Related
BACKGROUND
currently I am in a side project where I am building a Xamarin based mobile App for easy movie and tv show searching and navigation based on user preferences (e.g. based on movie genre etc).
To do this the mobile app acts as a client to the https://www.themoviedb.org/documentation/api online movie database's Web API service.
PROBLEM
I am looking for an easy and well supported package to wrap API Uri paths and query parameters into a web api query. I have looked a bit on RestSharp .
I like the syntax very much with the pattern based query path:
var request = new RestRequest("resource/{id}");
request.AddParameter("name", "value");
request.AddUrlSegment("id", "123");
but I am not sure about the packages future. Also if there is an alternative from MS, I would take that.
So have also looked Web-API tailored at MS alternatives but I am unsure what is recommended there. I only can find docs and examples for the server side (ASP.NET CORE MVC).
I need to be pointed to a well functioning .NET Standard 2.0 package from Microsoft or from a 3rd party to send Web API request from my Xamarin client.
Where am I
I have already written a lot of code based on pure HttPClient and AspNetcore.WebUtilituies for assembling a query string. But the gazillions of API path segments are getting out of my hand. I really need something to manage API path templates like RestSharp does
Code sample:
here I declare all of the path segments which I assemble manually ==> ugly AF
public static class WebApiPathConstants
{
public const string BASE_Address = "https://api.themoviedb.org";
public const string BASE_Path = "/3";
public const string CONFIG_Path = "/configuration";
public const string GENRE_LIST_Path = "/genre/movie/list";
...
lot of lines here
....
public const string PAGE_Key = "page";
public const string INCLUDE_Adult_Key = "include_adult";
public const string API_KEY_Key = "api_key";
public const string RECOMMENDATIONS_Path = "/recommendations";
public const string SIMILARS_Path = "/similar";
}
Here I assemble a query and kick of a task to get movie details based on the query from the server: The assembly of the Url path is my main problem. It looks too error prone.
public async Task<FetchMovieDetailsResult> FetchMovieDetails(int id, string language = null, int retryCount = 0, int delayMilliseconds = 1000)
{
string baseUrl = BASE_Address + BASE_Path + MOVIE_DETAILS_Path + "/" + id;
var query = new Dictionary<string, string>();
query.Add(API_KEY_Key, apiKeyValue);
if (!string.IsNullOrEmpty(language))
query.Add(LANGUAGE_Key, language);
string requestUri = QueryHelpers.AddQueryString(baseUrl, query);
FetchMovieDetailsResult result = await GetResponse<FetchMovieDetailsResult>(retryCount, delayMilliseconds, requestUri);
return result;
}
The result is a POCO class with the HttpStatusCode and (if successful ) a Json object. The client accesses the Json object only if the StatusCode == 2xx.
Prepared to be shot down in flames here, if this doesn't match your use-case, but it looks like the TheMovieDb site itself has a list of client libraries. It's available here: https://www.themoviedb.org/documentation/api/wrappers-libraries. They're obviously a layer higher than you're asking for here, in that they completely wrap the API, such that you need not even know what you're calling or how you're calling it, but in the interests of getting the job done, they seem like they'd do the trick.
I have .NET Web API Project for the fulfillment API as our webhook in my Dialogflow agent. In our Post method of the controller, after getting the request from Dialogflow, I implement the explicit authentication as shown in the Google Cloud documentation for C#.
//jsonFileName is the name of the serviceAccountKey json generated from the Google Cloud Platform that's encrypted internally
public bool AuthExplicit(string projectId, string jsonFileName)
{
try
{
string JsonCredential = DecryptHelper.Decrypt(jsonFileName);
var credential = GoogleCredential.FromJson(JsonCredential).CreateScoped(LanguageServiceClient.DefaultScopes);
var channel = new Grpc.Core.Channel(
LanguageServiceClient.DefaultEndpoint.ToString(),
credential.ToChannelCredentials());
var client = LanguageServiceClient.Create(channel);
AnalyzeSentiment(client);
if (client != null)
{
return true;
}
else
{
return false;
}
}
internal void AnalyzeSentiment(LanguageServiceClient client)
{
var response = client.AnalyzeSentiment(new Document()
{
Content = "Authenticated.",
Type = Document.Types.Type.PlainText
});
var sentiment = response.DocumentSentiment;
string score = $"Score: {sentiment.Score}";
string magnitude = $"Magnitude: {sentiment.Magnitude}";
}
The difference with the code is that after getting the client, when we call the AnalyzeSentiment() method, it doesn't do anything, and the projectId parameter is never used to authenticate. GCP docs are quite confusing, since when there is an AuthExplicit() that uses projectId, it uses it as a parameter for the buckets and only prints this on the console.
It works fine, until we test the service account key with a different agent. Expected output is that authentication would fail, but somehow it still passes.
Once the Post method goes through the AuthExplicit() method, it would only return a boolean. Is this the right way to authenticate? Or is there something else needed to invoke?
The difference with the code is that after getting the client, when we call the AnalyzeSentiment() method, it doesn't do anything,
Does client.AnalyzeSentiment() return an empty response? Does the call hang forever?
It works fine, until we test the service account key with a different agent.
What is a different agent? A different User-Agent header?
Once the Post method goes through the AuthExplicit() method, it would only return a boolean. Is this the right way to authenticate? Or is there something else needed to invoke?
What does 'the Post method' refer to? What is the 'it' that would only return a boolean?
I am very new to dialogflow and WebAPIs, and having trouble with a simple dialogflow fulfillment webhook written in C# and hosted on Azure. I am using dialogflow V2.0 API version.
Currently my fulfillment works and returns a simple response but has no regard to the intent and parameters. I am trying to now parse the JSON get the intent do a simple select case and return the value of the parameters recevied. And this is giving me lot of trouble. The webhook link, my code and the error message returned in the "catch" block are given below
public JsonResult Post(string value)
{
try
{
dynamic obj = JsonConvert.DeserializeObject(value);
string Location = string.Empty;
switch (obj.intent.displayName)
{
case "getstock":
Location = obj.outContexts[0].parameters[0].Location;
break;
}
WebhookResponse r = new WebhookResponse();
r.fulfillmentText = string.Format("The stock at {0} is valuing Rs. 31 Lakhs \n And consists of items such as slatwall, grid and new pillar. The detailed list of the same has been email to you", Location);
r.source = "API.AI";
Response.ContentType = "application/json";
return Json(r);
} catch(Exception e)
{
WebhookResponse err = new WebhookResponse();
err.fulfillmentText = e.Message;
return Json(err);
}
}
The error message :
Value cannot be null.
Parameter name: value
The above function is called via POST, you can use POSTMAN and you will get the JSON response.
Moreover i am using ASP.Net Web Api with Visual Studio 2017 with Controllers
First install the nuget package Google.Apis.Dialogflow.v2 and its dependencies. It'll save you a lot of work later on as it has dialogflow response/request c# objects which will make navigating the object graph easier.
Second add the using for the package using Google.Apis.Dialogflow.v2.Data;
Change your method to something like
public GoogleCloudDialogflowV2WebhookResponse Post(GoogleCloudDialogflowV2WebhookRequest obj)
{
string Location = string.Empty;
switch (obj.QueryResult.Intent.DisplayName)
{
case "getstock":
Location = obj.QueryResult.Parameters["Location"].ToString();
break;
}
var response = new GoogleCloudDialogflowV2WebhookResponse()
{
FulfillmentText = $"The stock at {Location} is valuing Rs. 31 Lakhs \n And consists of items such as slatwall, grid and new pillar. The detailed list of the same has been email to you",
Source = "API.AI"
};
return response;
}
I think your main issue in your code is "obj.outContexts[0]" outContexts isn't where you'll find your parameters, and unless you've setup an output content this will be null. You need to look in queryResult for your parameters.
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 write a Web Api 2 Project and within one Method (POSTing a new Location), I want to retrieve some Information, the user not provides (Country, City, region).
I found a solution in the Google Maps API:
http://maps.googleapis.com/maps/api/geocode/json?latlng=38.91845,1.44315&sensor=true
This meens, I must only provide the lat and lon coords within this URL.
How can I send this request and process the result within my own API Method?
My method is till now:
public string PostNewLocation(string mName, decimal mLat, decimal mLot)
{
// Here should be the calling and resolving of the Google API
// string mCity = ...
// string mCountry = ...
// Adding new location to database follows here and works fine...
}
public string PostNewLocation(string mName, decimal mLat, decimal mLot)
{
//do a get request to http://maps.googleapis.com/maps/api/geocode/json?latlng=38.91845,1.44315&sensor=true
//deserialize the json response to your own object and do stuff with it
var response = googleAPIService.Get(mLat, mLot);
//do something with the response
}