I'm new to dialogflow and trying to use permission handler to ask for location permission using .NET core webapi. I've created intent, entities and event(google.assistent.permission) in dialogflow console. Now I want to send a request from my webapi to send the request to access location.
Can somebody please provide a code sample how to send request to access location from my webhook?
You need to include the helper intent DialogFlow JSON as part of the payload:
WebhookResponse response;
Struct payload;
response.Payload = payload;
Alternatively, it can be added as a fulfillment message with the payload type1.
The payload struct can be parsed from JSON:
response.Payload = Struct.Parser.ParseJson(#"{
""google"": {
""expectUserResponse"": true,
""systemIntent"": {
""intent"": ""actions.intent.PLACE"",
""data"": {
""#type"": ""type.googleapis.com/google.actions.v2.PlaceValueSpec"",
""dialogSpec"": {
""extension"": {
""#type"": ""type.googleapis.com/google.actions.v2.PlaceValueSpec.PlaceDialogSpec"",
""permissionContext"": ""To find a location"",
""requestPrompt"": ""Where would you like to go?""
}
}
}
}
}
}");
Or created using the Protobuf API (slightly faster due to skipping the parsing step and type safe, but incredibly ugly):
response.Payload = new Struct
{
Fields =
{
["google"] = Value.ForStruct(new Struct
{
Fields =
{
["expectUserResponse"] = Value.ForBool(true),
["systemIntent"] = Value.ForStruct(new Struct
{
// ... and so on
})
}
})
}
};
Keep in mind that including any message in the payload (which is necessary to call the helper) will override any other messages you added previously and ignore anything added afterwards (they are still part of the returned object, but stripped out by DialogFlow). That means: If you want any other rich response, it currently also needs to be manually added to the payload. At that point, you might as well create the entire JSON response from scratch.
Related
I'm trying to use the Bulk Import API endpoint within Marketo to fetch the warnings and failures associated with a bulk job I created within Marketo.
The output of these jobs is stated as an ObservableOfInputStreamContent, yet the response of these endpoints returns a csv string (with header column), that's not a JSON object. To compound to this problem, we are using the generated swagger files with the swagger definition file provided by Marketo. These generated c# client side files have the ObservableOfInputStreamContent object, but it's an empty object. I'm not sure if this is intended, or a mistake on Marketo's side. The generated files will attempt to use Newtonsoft.Json.JsonConvert.DeserializeObject<ObservableOfInputStreamContent>(responseText, JsonSerializerSettings); to deserialize the API response to the ObservableOfInputStreamContent.
Generated code that deserializes the API response:
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " + typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception);
}
Problem one is that the API does not return JSON to begin with (eg):
address,city,country,
123 lane, new york, USA
745 street, new york, USA
This call will return this error because of this:
Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: a. Path '', line 0, position 0.
The second issue is that ObservableOfInputStreamContent is defined as an empty object to begin with in the generated files. So if the API response was valid JSON, I don't think it would know how to convert to that empty ObservableOfInputStreamContent object. The good news about the generated code is that it gives me an option to extend the ObservableOfInputStreamContent because it's defined as a partial class.
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.11.0 (Newtonsoft.Json v11.0.0.0)")]
public partial class ObservableOfInputStreamContent
{
}
That said, is there any possible way I can use the JsonSerializerSettings to get around this issue? Could I extended the ObservableOfInputStreamContent class to hold a string property and then create my own JsonConverter to convert the string returned from the API into the new ObservableOfInputStreamContent?
ControllerBase contains methods such as Conflict() that return a ConflictResult object (representing an HTTP 409 response) that is derived from StatusCodeResult. The resulting response body has content type application/problem+json and looks like this:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"traceId": "0HLO99QHFC9QI:00000001"
}
There is no in-built method/class for an HTTP 410 response, so I made one:
[DefaultStatusCode(410)]
public class GoneResult : StatusCodeResult
{
public GoneResult() : base(410)
{}
}
...
public static class ControllerBaseExtensions
{
public static GoneResult Gone(this ControllerBase controllerBase) // this doesn't give all the problem+JSON attributes
{
return new GoneResult();
}
}
However, this gives
{
"type": "about:blank",
"status": 410
}
i.e., the type value is different and the title and traceId fields are missing.
I'd also like to create a custom class for an HTTP 500 response that includes a message field with the error message. I've tried returning StatusCode(StatusCodes.Status500InternalServerError), which gives me the same minimal application/problem+json response as my Gone() method; I've also tried returning StatusCode(StatusCodes.Status500InternalServerError, message), which gives me my error message but formats the response as text/plain.
The code that generates the ProblemDetails response isn't aware of the 410 status-code, so it doesn't have an associated Link and Title property to use when building the response object. To add this awareness, configure ApiBehaviorOptions in ConfigureServices, like this:
services.Configure<ApiBehaviorOptions>(options =>
{
options.ClientErrorMapping[410] = new ClientErrorData
{
Title = "Gone",
Link = "https://tools.ietf.org/html/rfc7231#section-6.5.9"
};
});
ClientErrorMapping is a dictionary of int (status-code) to ClientErrorData. Note that the value I've used for Link above does point to the correct section of the RFC.
Simply, you have to actually return a ProblemDetails response body. I'd have to dig through the code to be sure, but I think ASP.NET Core is doing this via middleware only for particular results. They say anything in the 4xx range, but I think that's actually just confined to the built-in result types that return status codes in that range, not any result with a 4xx status code. Again, this is conjecture, as I haven't looked at exactly what they're doing, although it's not happening as part of the actual result class.
For your purposes, there's a few different ways you can handle this. You can write your own middleware to catch outbound responses and rewrite them. You can use an custom exception handler. You could simply inherit from ObjectResult instead, and then just create a ProblemDetails instance yourself and drop that into the base. You could even just return ProblemDetails directly from your action (though, that's obviously the least optimal way).
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?
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 am using RestKit from an iOS app to connect to a Web API service that we are building in C# .Net 4.
I am having the same issue from here: RestKit non-kvc object mapping
Basically C# returns something like:
formatted raw
BODY
[
{
"Id":6,
"Guid":"00000000-0000-0000-0000-000000000000",
"Owner":null,
"Message":"Testing Wom#10",
"HashTags":null,
"createdtime":"2012-10-28T00:00:00",
"PlayedCount":100,
"DurationInSecs":150.0,
"FileSizeInBytes":20000,
"FileUrl":"http://www.wom.com"
}
]
While the standard format expected by RestKit is
{"woms": [
{
"Id":6,
"Guid":"00000000-0000-0000-0000-000000000000",
"Owner":null,
"Message":"Testing Wom#10",
"HashTags":null,
"createdtime":"2012-10-28T00:00:00",
"PlayedCount":100,
"DurationInSecs":150.0,
"FileSizeInBytes":20000,
"FileUrl":"http://www.wom.com"
}
]
I don't care using a way or another, however, it seems that it would be easier from the iOS side to make C# return the "customers" class name.
How can I tell C# to return that?
Thanks.
This is the current code in my ApiController in C#:
namespace WomWeb.Controllers.Apis
{
[Authorize]
public class WomsController : ApiController
{
private WomContext db = new WomContext();
// GET api/Woms
public IEnumerable<Wom> GetWoms()
{
return db.Woms.AsEnumerable();
}
I've had some issues like this when trying to serialize JSON in C#. I think the easiest way is wrap the customer in another class. If you only need to serialize in one place you can do something like var temp = new Object { customer customer = new customer(); } right before making the call to serialize it.
This is the best solution I have found so far. Basically replace the IEnumerable by HttpResponseMessage and use the Request.CreateResponse to respond (code below).
While it works it is less than ideal: I lose the abstraction, and now the controller respond with Json regardless of the request headers (that logic was resolved automatically, but when using the CreateResponse I am writing directly to the output).
// GET api/Woms
//public IEnumerable<Wom> GetWoms()
public HttpResponseMessage GetWoms()
{
//return db.Woms.Include("Owner").AsEnumerable();
return Request.CreateResponse(HttpStatusCode.OK, new { woms = Include("Owner").AsEnumerable() });
}