Actions on google correct response - c#

My C# web API has successfully received a request from my Actions on google dialog flow. But I am having issues understanding what the response format should be.
{
"responseId": "96ee6c11-8f73-409f-8dac-8b6141d08483",
"queryResult": {
"queryText": "History",
"action": "tell.fact",
"parameters": {
"category": "history"
},
"allRequiredParamsPresent": true,
"fulfillmentMessages": [
{
"text": {
"text": [
""
]
}
}
],
"outputContexts": [
{
"name": "projects/project--6162817918903295576/agent/sessions/1530877719318/contexts/google_assistant_input_type_touch",
"parameters": {
"category.original": "History",
"category": "history"
}
},
{
"name": "projects/project--6162817918903295576/agent/sessions/1530877719318/contexts/actions_capability_screen_output",
"parameters": {
"category.original": "History",
"category": "history"
}
},
{
"name": "projects/project--6162817918903295576/agent/sessions/1530877719318/contexts/choose_fact-followup",
"lifespanCount": 2,
"parameters": {
"category.original": "History",
"category": "history"
}
},
{
"name": "projects/project--6162817918903295576/agent/sessions/1530877719318/contexts/actions_capability_audio_output",
"parameters": {
"category.original": "History",
"category": "history"
}
},
{
"name": "projects/project--6162817918903295576/agent/sessions/1530877719318/contexts/actions_capability_media_response_audio",
"parameters": {
"category.original": "History",
"category": "history"
}
},
{
"name": "projects/project--6162817918903295576/agent/sessions/1530877719318/contexts/actions_capability_web_browser",
"parameters": {
"category.original": "History",
"category": "history"
}
}
],
"intent": {
"name": "projects/project--6162817918903295576/agent/intents/4a35cf33-e446-4b2b-a284-c70bc4dfce17",
"displayName": "choose_fact"
},
"intentDetectionConfidence": 1,
"languageCode": "en-us"
},
"originalDetectIntentRequest": {
"source": "google",
"version": "2",
"payload": {
"isInSandbox": true,
"surface": {
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
},
"requestType": "SIMULATOR",
"inputs": [
{
"rawInputs": [
{
"query": "History",
"inputType": "TOUCH"
}
],
"arguments": [
{
"rawText": "History",
"textValue": "History",
"name": "text"
}
],
"intent": "actions.intent.TEXT"
}
],
"user": {
"lastSeen": "2018-07-06T11:44:24Z",
"locale": "en-US",
"userId": "AETml1TDDPgKmK2GqQ9ugHJc5hQM"
},
"conversation": {
"conversationId": "1530877719318",
"type": "ACTIVE",
"conversationToken": "[]"
},
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
}
]
}
},
"session": "projects/project--6162817918903295576/agent/sessions/1530877719318"
}
attempt one
The documentation webhook states that my response should look like that
{"fulfillmentText":"Hello from C# v2","fulfillmentMessages":[{"card":{"title":"card title","subtitle":"sub title","imageUri":"https://assistant.google.com/static/images/molecule/Molecule-Formation-stop.png","buttons":[{"text":"button text","postback":"https://assistant.google.com/"}]}}],"source":"example.com","payload":{"google":{"expectUserResponse":true,"richResponse":{"items":[{"simpleResponse":{"textToSpeech":"Thi sis a simple response "}}]}},"facebook":{"text":"Hello facebook"},"slack":{"text":"Hello facebook"}},"outputContexts":[{"name":"projects/project--6162817918903295576/agent/sessions/2a210c67-4355-d565-de81-4d3ee7439e67","lifespanCount":5,"parameters":{"param":"parm value"}}],"followupEventInput":{"name":"event name","languageCode":"en-Us","parameters":{"param":"parm value"}}}
This results in the following error
MalformedResponse 'final_response' must be set.
Failed to parse Dialogflow response into AppResponse because of empty speech response
attempt 2
So i went on to try simple response
{
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "this is a simple response"
}
}
]
}
}
}
}
Which also results with
MalformedResponse 'final_response' must be set.
Failed to parse Dialogflow response into AppResponse because of empty speech response
I can verify that my requests are being sent as application/json
Does anyone know the proper response format?

The root problem is actually ASP.NET Core by default uses transfer-encoding: chunked for ActionResult and for some reason Dialogflow does not support parsing chunked transfer
The following response is accepted by actions.
[HttpPost]
public ContentResult Post([FromBody] FulfillmentRequst data)
{
var response = new FulfillmentResponse
{
fulfillmentText = "Hello from C# v2",
};
return Content(JsonConvert.SerializeObject(response), "application/json");
}

Here is the JSON response format: https://github.com/dialogflow/fulfillment-webhook-json/blob/master/responses/v2/response.json

Related

How to validate Json With schema C#

I am trying to validate JSON (API response) with a JSON schema with
string data = File.ReadAllText(#"C:\Users\Aman.Sharma\Source\Repos\Validator\Validator\testData.json");
string schema = File.ReadAllText(#"C:\Users\Aman.Sharma\Source\Repos\Validator\Validator\V2JsonSchema.json");
var model = JObject.Parse(data);
var json_schema = JSchema.Parse(schema);
bool valid = model.IsValid(json_schema, out IList<string> messages);
But the problem just throws an error with the first occurrence of error and skips the other part.
Is there any way to compare the whole JSON with schema and throw errors for each record?
Also this method If I change the schema always pass the JSON.
Sample Data
{
"id": "e1110047-b606-4fb3-84c6-28f7d5456e11",
"accountInactiveDate": "0001-01-01T00:00:00Z",
"accountOpenDate": "0001-01-01T00:00:00Z",
"accountTypeIds": [ 4000 ],
"address": {
"city": "vVjEKwUP",
"addressTypeId": 1000,
"countryISOCode": "GBR",
"street1": "xTMksdLL",
"zipCode": "12345"
},
"annualRevenue": 0.0,
"email": {
"emailTypeId": 1000,
"email": "zvvzwsdv#yopmail.com"
},
"homeLocationNumber": "316",
"industryTypeId": 0,
"isDeleted": false,
"name": "AccounttxecJizQ",
"parentAccountId": "00000000-0000-0000-0000-000000000000",
"phone": {
"phoneTypeId": 1000,
"number": "+44 123456"
},
"productsTypeIds": [ 3000 ],
"timeStamp": "\"2e001932-0000-0d00-0000-63315d8e0000\"",
"links": [
{
"href": "https://api-test.QA.cloud/companies/api/v2/accounts/e1110047-b606-4fb3-84c6-28f7d5456e11",
"rel": "Self"
}
],
"isBlocked": false,
"isComplete": true,
"createDate": "2022-09-26T08:06:38.2263447Z",
"systemCaller": "qa-user2-automationtests",
"originSystemCaller": "qa-user2-automationtests",
"originCreateDate": "2022-09-26T08:06:38.2263447Z"
}
Schema
{
"type": "object",
"properties": {
"searchMode": {
"enum": [
"Any",
"All"
],
"type": "string"
},
"queryType": {
"enum": [
"Simple",
"Full"
],
"type": "string"
},
"select": {
"type": "array",
"items": {
"type": "string"
}
},
"searchFields": {
"type": "array",
"items": {
"type": "string"
}
},
"orderBy": {
"type": "array",
"items": {
"type": "string"
}
},
"highlightPreTag": {
"type": "string"
},
"highlightPostTag": {
"type": "string"
},
"highlightFields": {
"type": "array",
"items": {
"type": "string"
}
},
"filter": {
"type": "string"
},
"facets": {
"type": "array",
"items": {
"type": "string"
}
},
"scoringProfile": {
"type": "string"
},
"scoringParameters": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"values": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"page": {
"format": "int32",
"type": "integer"
},
"pageSize": {
"format": "int32",
"type": "integer"
},
"includeTotalResultCount": {
"type": "boolean"
}
}
}
I had similar errors with such approach.
Try add .Replace("\r", "").Replace("\n", "") at the end of code that reads data from files.
If it works - replace with less rude approach of ignoring of \r and \n.

Is it possible to convert HttpResponseMessage json to object?

need to mock the HttpResponseMessage in my Unit Test.
using .net core 3.1/
getting the following error:
Newtonsoft.Json.JsonSerializationException : Could not create an
instance of type System.Net.Http.HttpContent. Type is an interface or
abstract class and cannot be instantiated. Path
'httpResponseMessage.Content.Headers', line 206, position 16.
Deserialize Code:
public static T GetObjectFromFile<T>(string fileName) where T : class
{
var directory = AppDomain.CurrentDomain.BaseDirectory;
var path = string.Format("{0}\\Stubs\\{1}", directory, fileName);
string stubContent = System.IO.File.ReadAllText(path);
T res = JsonConvert.DeserializeObject<T>(stubContent, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new PrivateResolver(),
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
});
return res;
}
T is (for the example):
public class ResponseWithHttpResponseMessage
{
public HttpResponseMessage HttpResponseMessage { get; set; }
}
JSON example:
{
"HttpResponseMessage": {
"Version": "1.1",
"Content": {
"Headers": [
{
"Key": "Content-Type",
"Value": [ "application/json" ]
}
]
},
"StatusCode": 200,
"ReasonPhrase": "OK",
"Headers": [
{
"Key": "X-Backside-Transport",
"Value": [ "OK OK,FAIL FAIL,OK OK" ]
},
{
"Key": "Connection",
"Value": [ "Keep-Alive" ]
},
{
"Key": "Transfer-Encoding",
"Value": [ "chunked" ]
},
{
"Key": "Date",
"Value": [ "Wed, 23 Dec 2020 14:04:56 GMT" ]
},
{
"Key": "X-Global-Transaction-ID",
"Value": [ "1fd23d895fe34e870c0158c2" ]
},
{
"Key": "User-Agent",
"Value": [ "IBM-APIConnect/5.0" ]
},
{
"Key": "Access-Control-Expose-Headers",
"Value": [ "APIm-Debug-Trans-Id, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-Global-Transaction-ID" ]
},
{
"Key": "Access-Control-Allow-Origin",
"Value": [ "*" ]
},
{
"Key": "Access-Control-Allow-Methods",
"Value": [ "GET" ]
},
{
"Key": "X-RateLimit-Limit",
"Value": [ "name=rate-limit,92;" ]
},
{
"Key": "X-RateLimit-Remaining",
"Value": [ "name=rate-limit,81;" ]
}
],
"TrailingHeaders": [],
"RequestMessage": {
"Version": "1.1",
"Content": null,
"Method": { "Method": "GET" },
"RequestUri": "https://EXAMLE?F=I,C,",
"Headers": [
{
"Key": "M-ID",
"Value": [ "1" ]
}
],
"Properties": {}
},
"IsSuccessStatusCode": true
}
}
seems that the headers class is sealed and therefore it is not possible to mock it.
but is there any chance that a workaround is exist?

how should i get the json references inline rather than getting it references - should NOT have additional properties additionalProperty: definitions

I am new to JsonSchema, I am trying to generate swagger(3.0) JSON. I am using NJsonSchema.
It has successfully generated the JSON schema for models. The only problem is that the JSON has references to the complex type. I tried the generated JSON in http://editor.swagger.io/ and the UI is generated fine, but I have a lot of structural error.
Structural error at paths./xyz/asd/abc/.schema
should NOT have additional properties
additionalProperty: definitions
following is the sample JSON which can be tested on the above link.
{
"openapi": "3.0.1",
"info": {
"title": "SomeTitle",
"description": "someDescription",
"version": "v1"
},
"paths": {
"/Device": {
"get": {
"summary": "someSummary",
"tags": [
"Device"
],
"parameters": [
{
"name": "id",
"in": "query",
"description": "deviceId",
"required": true,
"schema": {
"type": "string",
"nullable": false
}
}
],
"responses": {
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"title": "SomeTitleAgain",
"type": "object",
"additionalProperties": false,
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"udiCarrier": {
"$ref": "#/paths/~1Device/get/responses/200/content/application~1json/schema/definitions/ListOfUdiCarrierComponent"
}
},
"definitions": {
"ListOfUdiCarrierComponent": {
"type": "array",
"items": {
"$ref": "#/paths/~1Device/get/responses/200/content/application~1json/schema/definitions/UdiCarrierComponent"
}
},
"UdiCarrierComponent": {
"type": "object",
"additionalProperties": false,
"properties": {
"carrierHRF": {
"type": "string"
}}}}}}}}}}}},
"components": { }
}
I don't think NJsonSchema gives a way to get rid of schema reference handling.
So JSON generated always has these references.
Is there any way to process this schema and get the references inline?
I also looked for NewtonsoftJson's IReferenceResolver examples on the internet but could not get a clear picture of how can I use it.
Thanks in Advance.
I have corrected you JSON file with the correct way to use schema and $ref attribute:
{
"openapi": "3.0.1",
"info": {
"title": "SomeTitle",
"description": "someDescription",
"version": "v1"
},
"paths": {
"/Device": {
"get": {
"summary": "someSummary",
"tags": [
"Device"
],
"parameters": [
{
"name": "id",
"in": "query",
"description": "deviceId",
"required": true,
"schema": {
"type": "string",
"nullable": false
}
}
],
"responses": {
"200": {
"description": "Success.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ListOfUdiCarrierComponent"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ListOfUdiCarrierComponent": {
"title": "SomeTitleAgain",
"type": "object",
"additionalProperties": false,
"required": [
"id"
],
"properties": {
"id": {
"type": "string"
},
"udiCarrier": {
"type": "array",
"items": {
"$ref": "#/components/schemas/UdiCarrierComponent"
}
}
}
},
"UdiCarrierComponent": {
"type": "object",
"additionalProperties": false,
"properties": {
"carrierHRF": {
"type": "string"
}
}
}
}
}
}

DialogFlow not triggering Event Intent when sending action via ASP.NET Webhook

I am building a .NET Webhook following this tutorial, dialogflow fulfillment with c and app engine.
Everything works fine except when I want to set up DailyUpdates with a RegisterUpdate Intent.
When the "setup_notification_update" intent calls the webhook I sendthis kind of JSON in response:
{
"fulfillmentText": "Notifica programmata",
"fulfillmentMessages": [
{
"card": {
"title": "Notifica programmata",
"subtitle": "Notifica programmata con successo",
"imageUri": "https://assistant.google.com/static/images/molecule/Molecule-Formation-stop.png",
"buttons": [
{
"text": "Valutami",
"postback": "https://macoev.com/"
}
]
}
}
],
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Questa รจ la risposta di avvenuto successo per la programmazione della notifica"
}
}
]
},
"systemIntent": {
"intent": "actions.intent.REGISTER_UPDATE",
"data": {
"#type": "type.googleapis.com/google.actions.v2.RegisterUpdateValueSpec",
"intent": "get_stats_notification",
"arguments": [
{
"name": "category",
"textValue": "Daily_lowest_temperature"
}
],
"triggerContext": {
"timeContext": {
"frequency": "DAILY"
}
}
}
}
}
}
}
The problem is that the intent that has REGISTER_UPDATE as its event does not get triggered, resulting in the notification not being scheduled.
This is the response that I set when that event get triggered:
{
"responseId": "",
"queryResult": {
"queryText": "",
"action": "",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentText": "",
"fulfillmentMessages": [],
"outputContexts": [],
"intent": {
"name": "finish_update_setup",
"displayName": "finish_update_setup"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {},
"languageCode": ""
},
"originalDetectIntentRequest": {
"source": "google",
"version": "2",
"payload": {
"isInSandbox": true,
"surface": {
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
},
"inputs": [
{
"rawInputs": [],
"intent": "",
"arguments": [
{
"name": "REGISTER_UPDATE",
"extension": {
"#type": "type.googleapis.com/google.actions.v2.RegisterUpdateValue",
"status": "OK"
}
},
{
"name": "text",
"rawText": "04:10pm",
"textValue": "04:10pm"
}
]
}
],
"user": {},
"conversation": {},
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
}
]
}
},
"session": ""
}
Any idea why? Any help will be appreciated. Thanks in advance.

Bind Model to JSON API on other server

I'm new to ASP.NET MVC and have an existing API which returns JSON. This API exists on another server and I need to make a server-to-server call to API and bind the resultant data to a Model so that it can be used within other parts of this web app I'm making.
I tried searching for this and it seems like it exists but I can't find the basic documentation for it or how to implement it.
I could make each component (make HTTP request, parse the JSON, set a model to use the data), but I'd hate to re-invent the wheel (and probably do it poorly) if this is something that is already in the library.
Example of the API call:
http://example.info/feeds/feed.aspx?alt=json-in-script
response:
{
"version": "1.0",
"encoding": "UTF-8",
"feed": {
"updated": {
"$t": "2014-07-08T13:58:21-05:00"
},
"id": {
"$t": "http://example.info/feeds/feed.aspx"
},
"title": {
"type": "text",
"$t": "Example Calendar of Events"
},
"link": [
{
"rel": "alternate",
"type": "text/html",
"href": "http://feed.example.edu/search/"
},
{
"rel": "alternate",
"type": "application/json",
"title": "JSON",
"href": "http://example.info/feeds/feed.aspx?alt=json"
},
{
"rel": "alternate",
"type": "text/calendar",
"title": "iCal",
"href": "http://example.info/feeds/feed.aspx?alt=ical"
},
{
"rel": "self",
"type": "application/atom+xml",
"title": "ATOM Feed",
"href": "http://example.info/feeds/feed.aspx"
}
],
"author": [
{
"name": {
"$t": "Example!!"
},
"email": {
"$t": "web#example.edu"
}
}
],
"gd$where": [
{
"valueString": "Chicago, IL, US"
}
],
"gCal$timezone": {
"value": "America/Chicago"
},
"entry": [
{
"category": [
{
"scheme": "http://schemas.google.com/g/2005#kind",
"term": "http://schemas.google.com/g/2005#event"
},
{
"term": "Current Students"
},
{
"term": "Faculty"
},
{
"term": "Staff"
}
],
"published": {
"$t": "2012-03-06T20:57:24+00:00"
},
"updated": {
"$t": "2012-03-06T20:57:24+00:00"
},
"id": {
"$t": "http://example.info/feed/?eventid=74289"
},
"gCal$uid": {
"value": "e72724e9-34eb-41dd-a75a-78d1577cb98a.127924#feed.example.edu"
},
"title": {
"type": "text",
"$t": "Last Day of Sessions 1 & 4 Classes"
},
"content": {
"type": "html",
"$t": "<p>Session 1 & 4 period ends today.</p>"
},
"summary": {
"type": "text",
"$t": "Session 1 & 4 period ends today."
},
"author": [
{
"name": {
"$t": "Office"
},
"email": {
"$t": "registrar#example.edu"
}
}
],
"gd$who": [
{
"rel": "http://schemas.google.com/g/2005#event.organizer",
"valueString": "Registrar, Office of the"
},
{
"rel": "http://schemas.google.com/g/2005#event.attendee",
"valueString": "Current Students"
},
{
"rel": "http://schemas.google.com/g/2005#event.attendee",
"valueString": "Faculty"
},
{
"rel": "http://schemas.google.com/g/2005#event.attendee",
"valueString": "Staff"
}
],
"gd$organization": [
{
"label": "Campus",
"primary": "true",
"gd$orgName": {
"$t": "Chicago"
}
}
],
"gd": {
"value": "http://schemas.google.com/g/2005#event.opaque"
},
"link": [
{
"rel": "alternate",
"type": "text/html",
"href": "http://feed.example.edu/viewevent.aspx?eventid=74289&occurrenceid=127924"
}
],
"gCal$sequence": {
"value": "0"
},
"gd$when": [
{
"startTime": "2014-07-30",
"endTime": "2014-07-31"
}
],
"gd$where": [
{
"valueString": "Classes administered by the Chicago Campus"
}
]
},
...
]
}
}
Edit:
I just now found this article on Calling a Web API From a .NET Client, which is in-line with what I'm trying to ask with this question, but I need to know how to do this in an ASP.NET MVC context, not a console application.
To call an external API you can use the HttpClient. Personally, I would wrap the calls to the API in their own class akin to the repository pattern.
public class ApiCaller
{
/*
this is the repository that can wrap calls to the API
if you have many different types of object returned
from the API it's worth considering making this generic
*/
HttpClient client;
public SomeClass Get()
{
SomeClass data;
string url = "http://example.info/feeds/feed.aspx?alt=json-in-script";
using (HttpResponseMessage response = client.GetAsync(url).Result)
{
if (response.IsSuccessStatusCode)
{
data = JsonConvert.DeserializeObject<SomeClass>(response.Content.ReadAsStringAsync().Result);
}
}
return data;
}
}
Then in the controller I would call the ApiCaller to get the object required at which point in this instance I'm just passing it to a view:
public class MyController : Controller
{
ApiCaller caller;
public MyController()
{
//maybe inject this dependency
ApiCaller = new ApiCaller();
}
public ActionResult Index()
{
SomeClass model = ApiCaller.Get();
//do something with the instance if required
return View(model);
}
}
The ApiCaller can then be extended if required to support posts, puts etc. If you have many different entities on the API that you wish to handle you can make an ApiCaller per entity or you could potentially use generics.
You must change from ActionResult to JsonResult. Also you can create a derived class as I did or use native class JsonResult.
public JsonResult CheckTimeout()
{
return Json(new JsonReturn { Success = true, ResponseData = new object() });
}
[Serializable]
public class JsonReturn : JsonResult
{
public JsonReturn()
{
Success = true;
Message = string.Empty;
ResponseData = null;
}
public JsonReturn(object obj)
{
Success = true;
Message = string.Empty;
ResponseData = obj;
}
public bool Success { get; set; }
public string Message { get; set; }
public object ResponseData { get; set; }
}
}

Categories

Resources