.Net Core InvokeCoreAsync has null result - signalr.client

Using Postman WebSockets I get the expected response to this message sent to the hub:
{
"type": 1,
"target": "RequestAuthToken",
"arguments": [
"123456"
]
}
e.g. {"type":1,"target":"AuthResultReceived","arguments":["{"Token":"KWFRMHUkTVL74Gsxqf...
but when I use a .Net 6 client I get a null result.
_Hub = new HubConnectionBuilder().WithUrl("https://localhost:44379/api").Build();
await _Hub.StartAsync();
RequestAuthTokenResponse result = await _Hub.InvokeCoreAsync<RequestAuthTokenResponse>("RequestAuthToken", new string[] { "123456" });
Any thoughts on what I'm missing? I've tried changing the type to "object" and "string" to try to get around any de-serialization issue. The hub side seems happy in either case.

Related

Why doesn't GraphQL.NET honour the errors.extensions schema?

I recently rewrote some GraphQL services from Java to .NET Core.
In Java, I was able to provide custom error messages to the clients using the errors.extensions in the response, ie:
{
"data": {
"someMutation": null
},
"errors": [{
"cause": null,
"message": "Unauthorized",
"httpStatusCode": 0,
"extensions": {
"uiMessage": "Oh no, your session expired. You'll need to login again to continue.",
"httpStatusDescription": "Unauthorized",
"httpStatusCode": 401
},
"errorType": "ValidationError",
"path": null,
"localizedMessage": "Unauthorized",
"suppressed": []
}
]
}
However, in .NET, I don't seem to be able to replicate this format.
ErrorInfo.Extensions is added to the root of the response, not to the the Errors object itself, eg:
{
"data": {
"someMutation": null
},
"errors": [{
"message": "Auth token not provided"
}
],
"extensions": {
"httpStatusCode": 401,
"httpStatusDescription": null,
"uiMessage": "Oh no, your session expired. You'll need to login again to continue.",
}
}
The GraphQL spec reads (ref https://spec.graphql.org/October2021/#sec-Errors, https://spec.graphql.org/October2021/#example-8b658):
GraphQL services may provide an additional entry to errors with key
extensions. This entry, if set, must have a map as its value. This
entry is reserved for implementors to add additional information to
errors however they see fit, and there are no additional restrictions
on its contents.
eg:
{
"errors": [
{
"message": "Name for character with ID 1002 could not be fetched.",
"locations": [{ "line": 6, "column": 7 }],
"path": ["hero", "heroFriends", 1, "name"],
"extensions": {
"code": "CAN_NOT_FETCH_BY_ID",
"timestamp": "Fri Feb 9 14:33:09 UTC 2018"
}
}
]
}
I created a new test project (.NET Core 3.1) using the latest versions of the libraries (GraphQL 7.1.1 et al) but am still unable to add custom properties to errors.extensions.
This is the test mutation which intentionally throws an exception:
Field<StringGraphType>("greet")
.Argument<NonNullGraphType<StringGraphType>>("name")
.Resolve(context => {
try {
throw new Exception("Invalid input");
return "Hello " + context.GetArgument<String>("name");
} catch(Exception ex) {
// This doesn't seem to get returned anywhere in the response
Dictionary<String, object> extraData = new Dictionary<string, object>();
extraData.Add("error1", "message1");
// Add the error to the response using the overloaded constructor
context.Errors.Add(new ExecutionError("Oh dear, that went wrong", extraData));
// This gets added to the root of the response
context.OutputExtensions.Add("error2", "message2");
return null;
}
});
the mutation to invoke it:
mutation {greet(name:"Chewbacca")}
and the response (I don't know where errors.extensions.details comes from):
{
"errors": [
{
"message": "Oh dear, that went wrong",
"extensions": {
"details": "GraphQL.ExecutionError: Oh dear, that went wrong"
}
}
],
"data": {
"greet": null
},
"extensions": {
"error2": "message2"
}
}
I would imagine that the GraphQL.NET library would expose an Extensions dictionary on the ExecutionError object so one could add custom values in the usual manner, eg:
ExecutionError executionError = new ExecutionError("Oh dear, that went horribly wrong");
executionError.Extensions.Add("customError", "Your custom error here")
context.Errors.Add(executionError);
Which would result in a response similar to this:
{
"data": {
"someMutation": null
},
"errors": [{
"message": "Oh dear, that went horribly wrong",
"extensions": {
"customError": "Your custom error here"
}
}
]
}
I am hopeful that some bright individual in the community can (slap me upside the head and) point me in the right direction.

NSwag generated client still serializes string for text/plain body

UPDATE: I went ahead and created an issue on NSwag after looking through its code. You can see it here: https://github.com/RicoSuter/NSwag/issues/3824
I have a functioning api endpoint that accepts "text/plain" as the body. The user of this endpoint is a third-party that controls the content type so I can't change that. I'm using NSwag to generate a c# client based on a swagger.json.
My main problem is that the generated client's function for calling this endpoint still serializes the string body, which causes the endpoint to fail to parse. I'm not 100% certain if this is a bug in my swagger.json or if it's something unintentional, because the json is also generated. This is why I'm not posting this on the NSwag github issues currently.
Here's what the swagger.json looks like:
{
"openapi": "3.0.1",
"info": {
"title": "PlainTextParser",
"version": "1.0"
},
"paths": {
"/api/v1/text": {
"post": {
"tags": [
"TextEvent"
],
"summary": "Parses a plain text body",
"operationId": "PostTextEvent",
"requestBody": {
"description": "Accepts a plain text body",
"content": {
"text/plain": {
"schema": {
"type": "string",
"nullable": true
}
}
}
},
"responses": {
"202": {
"description": "Success"
}
}
}
}
},
"components": { }
}
When I run nswag on it, I get this inside of the generated client:
public virtual async System.Threading.Tasks.Task PostTextEventAsync(string body, System.Threading.CancellationToken cancellationToken)
{
//...
var content_ = new System.Net.Http.StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(body, _settings.Value));
content_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/plain");
//...
}
The SerializeObject method call is what is causing the issue. When I removed it everything worked fine. You can even see on the second line there that it understands the content type, which is why I'm confused why it's trying to serialize it.
So is there something I'm missing in the swagger.json or is there a bug in NSwag?
I do realize I can work around this by making my API endpoint reformat the string to its intended state, but that feels like a hack.

How can I pass the Session ID in API Request via Apps Script?

I am trying to access the API of our CRM Documentation through Google Sheets / Apps Script.
When accessing the API through Postman I have no issues and get the desired results using the following setup:
POST: https://api.sharpspring.com/pubapi/v1.2/?accountID={{accountID}}&secretKey={{secretKey}}
BODY:
{
"id":"12345678912345678999",
"method": "getOpportunities",
"params": {
"where": {},
"limit":"500",
"offset": "0"
}
}
Now, when I try to replicate the same in Apps Script I get the following result:
{ result: null,
error: { code: 102, message: 'Header missing request ID', data: [] },
id: null }
The function that I am running is as below:
function myFunction() {
var URL = "https://api.sharpspring.com/pubapi/v1.2/?accountID={{accountID}}&secretKey={{secretKey}}"
var body = {
"method": "POST",
"body": raw,
"headers": {"Content-Type": "application/json"},
"redirect": "follow"
}
var raw = {
"method": "getOpportunities",
"id": "12345678912345678999",
"params": {
"where": {},
"limit":"500",
"offset": "0"
}
}
var results = UrlFetchApp.fetch(URL, body).getContentText();
var data = JSON.parse(results);
console.log(data);
}
In both I am passing a random session ID "12345678912345678999". I tried finding a session ID in the cookie but that didn't work and I assume that I am on the wrong path there. Passing the id in the header directly didn't work either.
Any ideas? Thanks a lot in advance!

Return string from Web API .NET Core get operation

I have a get operation that I want to return a string from. An example would be
"000875"
When I return this string from a controller in my Web API Controller in full .NET, it formats it like this:
{
"Property": "000875"
}
When I return the string in my converted .NET Core Controller it returns this:
{
"$id": "1",
"$type": "System.Net.Http.HttpResponseMessage, System.Net.Http",
"Version": "1.1",
"Content": {
"$id": "2",
"$type": "System.Net.Http.StringContent, System.Net.Http",
"Headers": [
{
"Key": "Content-Type",
"Value": [
"application/json; charset=utf-8"
]
}
]
},
"StatusCode": "OK",
"ReasonPhrase": "OK",
"Headers": [],
"TrailingHeaders": [],
"RequestMessage": null,
"IsSuccessStatusCode": true
}
It is interesting to note that the value is not even in there!
I am running some interesting JSON Serialization to make BreezeJs work with .NET Core. It is possible that it is the cause of this weirdness:
.AddNewtonsoftJson(opt =>
{
// Let Breeze say how we serialize. This adds in the Type and Id options the way breeze expects
var jsonSerializerSettings = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings);
......
I am hoping for a way to get strings through without all this mess. Can that be done?
I get the impression that the subject action definition returns HttpResponseMessage.
public HttpResponseMessage MyAction(....
HttpRequestMessage is no longer a first class citizen in asp.net-core framework and will be treated as a normal model and serialized.
That explains the JSON you are seeing with your controller
The syntax needs to be updated to return IActionResult derived responses
public IActionResult MyAction() {
//...
return Ok("000875");
}
ActionResult<T>
public ActionResult<string> MyAction() {
//...
if(somecondition)
return NotFound();
return "000875";
}
or the model itself.
public string MyAction() {
//...
return "000875";
}
Reference Controller action return types in ASP.NET Core Web API

Log data from dataPower to splunk

The question might be looking easy but I am quite struck on this.
I have a requirement whereby I have to store data regarding Timestamp,latency,serviceName etc in a variable and then log that into splunk.
However I am unable to call splunk through datapower xslt.
How can we call splunk through datapower using XSLT
Thanks
Splunk has several interfaces, but XSLT is not one of them. Lucky for you, there's already a Splunk app that can collect data from Datapower and index it. See https://splunkbase.splunk.com/app/3517/.
I would consider using the Splunk HTTP Event Collector.
You can use XSLT ou Gatewayscript, in conjunction with the Datapower urlopen function (available in both language), to make a simple http call to the collector.
I found here (Code under Apache license) that the call is as simple as a call to https://SPLUNK_SVR:8088/services/collector/event/1.0 with the following body:
{
"source": "chicken coop",
"sourcetype": "httpevent",
"index": "main",
"host": "farm.local",
"event": {
"message": {
"chickenCount": 500
"msg": "Chicken coup looks stable.",
"name": "my logger",
"put": 98884,
"temperature": "70F",
"v": 0
},
"severity": "info"
}
}
I think it would work better on the datapower by using gateway script, an example of such a call can be found here. Look for the first example. You will find similar code, in which I modified the "Data" section:
//Could be added to a library
var urlopen = require('urlopen');
var jsonData = '{
"source": "Datapower",
"sourcetype": "SOMETHING DYNAMIC",
"index": "main",
"host": "GET_THIS_FROM_DP_VARIABLES",
"event": {
"message": {
"SOMECOUNTER": 500
"msg": "SOME INTERESTING INFORMATION.",
"name": "GET_THIS_FROM_DP_VARIABLES",
"put": 3333,
"yadayada": "foo",
"bar": 0
},
"severity": "info"
}
}';
var options = {
target: 'https://SPLUNK_SVR:8088/services/collector/event/1.0',
method: 'POST',
headers: { },
contentType: 'text/plain',
timeout: 60,
sslClientProfile: 'AN_EXISTING_SSL_PROFILE_ON_DATAPOWER',
data: jsonData};
urlopen.open(options, function(error, response) {
if (error) {
// an error occurred during the request sending or response header parsing
console.error("Splunk Logging - urlopen error: "+JSON.stringify(error));
} else {
// get the response status code
var responseStatusCode = response.statusCode;
var responseReasonPhrase = response.reasonPhrase;
console.log("Splunk Logging - status code: " + responseStatusCode);
console.log("Splunk Logging - reason phrase: " + responseReasonPhrase);
// no need to read response data - This is just logging
}
});