Custom response type in GraphQL .NET - c#

I have a service which will now consume a GraphQL API just to return an image URL for a front-end application.
This is my first time using GraphQL at all, and this is the query structure I must use:
var request = new GraphQLRequest
{
Query = #"
query($status: Status = PUBLISHED, $path: String){
brand (status: $status, where: { path: $path }, first: 1){
card {
contentItems {
... on Cartao {
imagemFrente {
urls
}
}
}
}
}
}",
Variables = new
{
path = "[EXAMPLE-PATH]"
}
};
The problem I'm struggling with is how can my class ReturnType must be so I can access the urls property from the request down below?
var graphQLResponse = Task.Run(async () => await graphQLClient.SendQueryAsync<ReturnType>(request));
I'm using the GraphQLClient package only.

Run your query somewhere where you can grab the json result, copy it into the clipboard, then in VS, Edit/Paste Special/Paste JSON as classes.
Or use on of the many JSON to C# converters online, such as https://json2csharp.com/
That will give you the C# classes ready to use in your SendQueryAsync<>.

Related

SendGrid API returning 400 when I add more JSON properties

I'm trying to use the SendGrid API to create and schedule a Single Send email to a contact list when my Azure Functions endpoint is called. Here is the minimum amount of information that I can create the single send with and have it work with a 200 response.
private static SendGridClient _client = new SendGridClient(
Environment.GetEnvironmentVariable("SendGridApiKey")
);
...
var data = new {
name = "Title",
send_to = new {
list_ids = new [] {
$"{Environment.GetEnvironmentVariable("SendGridMailingId")}",
}
},
email_config = new {
design_id = $"{Environment.GetEnvironmentVariable("SendGridDesignId")}",
}
};
var singleSendResp = await _client.RequestAsync(
method: SendGridClient.Method.POST,
urlPath: "marketing/singlesends",
requestBody: JsonConvert.SerializeObject(data)
);
return singleSendResp;
The problem is that I'd like to include the send_at: "now", suppression_group_id, and sender_id, but if I include any of them (as well as all of them), I get this response:
{
"errors": [
{
"field": "",
"message": "json could not be unmarshalled"
}
]
}
I've tried all combinations of the above, and have even tried including all the properties that can't be null (minus the subject, html_content, etc since I have design_id.
I'm using the 9.28.1 SendGrid NuGet package, which should correspond to SendGrid's v3 API. I'm doing my testing locally with Postman. I am using the free version of the API, if that matters.
Any help would be appreciated. Thank you!
EDIT: Here would be my ideal object to send, with extra fields.
var data = new {
name = "Title",
send_at = "now",
send_to = new {
list_ids = new [] {
Environment.GetEnvironmentVariable("SendGridMailingId")
}
},
email_config = new {
design_id = Environment.GetEnvironmentVariable("SendGridDesignId"),
sender_id = Environment.GetEnvironmentVariable("SendGridSenderId"),
suppression_group_id = Environment.GetEnvironmentVariable("SendGridSuppressionId")
}
};
I finally figured out the issue, and it's a dumb mistake (as always). sender_id and suppression_group_id are supposed to be integers, but I was just sending the string. Wrapping the values in an int.Parse() works.
Also, even though send_at is supposed to be allowed a value of "now", it only works with the date string. For this, I included the following to format the string
string scheduleDate = DateTime.Now
.ToUniversalTime()
.AddMinutes(5)
.ToString("yyyy-MM-ddTHH:mm:ssZ");

i want to create a simple dotnet(vb.net or c#.net) class

I have a small task. I need the a .net class library created that communicates with a RPC REST service. All I need is the basic framework. So if you can just get it to pass the API token and get back the login credential
https://simplybook.me/en/api/developer-api/tab/explorer_api
The have a sample API Key I think you can use:
company: mib
API key: f43618e37b82004066d60db3431f4a06392599a6cfcafa8268bf25becc0ec7d7
You can use JSONRPC Client as shown below Link
using (Client rpcClient = new Client("someURL"))
{
rpcClient.Headers.Add("X-Application", "MyApplicationKey");
Request request = rpcClient.NewRequest("SportsAPING/v1.0/listMarketBook");
GenericResponse response = rpcClient.Rpc(request);
if (response.Result != null)
{
JToken result = response.Result;
}
else
Console.WriteLine(string.Format("Error in response, code:{0} message:{1}",
response.Error.Code, response.Error.Message);
// Example with positional parameters
JArray parameters = JArray.Parse(#"['Small', 'Medium', 'Large' ]");
Request resuestWithPostionalParameters = rpcClient.NewRequest("SportsAPING/v1.0/listMarketBook", parameters);
// Example with named parameters
JObject namedParameters = JObject.Parse(#"{ CPU: 'Intel', }");
Request resuestWithNamedParameters = rpcClient.NewRequest("SportsAPING/v1.0/listMarketBook", namedParameters);
}

Using new Json serializer with HttpContext.Response in ASP.NET Core 3.1

When we want to serialize an object to a JSON string in ASP.NET Core's pipeline, we need to work with HttpContext.Response.Body.WriteAsync, unless I'm missing something, as there's no Result property which we can easily use to assign a JsonResult object to.
Unless there's a better alternative, how exactly is serialization achieved by using the above method?
Note: The options for the JSON serializer should be the same as the (default) ones being used in ASP.NET Core 3.1.
If desired (not in our case), they can be modified via the IServiceCollection.AddJsonOptions middleware.
Example:
app.Use( next =>
{
return async context =>
{
if (<someFunkyConditionalExample>)
{
// serialize a JSON object as the response's content, returned to the end-user.
// this should use ASP.NET Core 3.1's defaults for JSON Serialization.
}
else
{
await next(context);
}
};
});
First of all, you can use these extension methods to write strings directly to your response, for example:
await context.Response.WriteAsync("some text");
Make sure you have imported the correct namespace to give you access to these extensions:
using Microsoft.AspNetCore.Http;
Secondly, if you want to get the JSON serialiser settings that are being used by the framework, you can extract them from the DI container:
var jsonOptions = context.RequestServices.GetService<IOptions<JsonOptions>>();
So this would make your full pipeline code look a little like this:
app.Use(next =>
{
return async context =>
{
if (<someFunkyConditionalExample>)
{
// Get the options
var jsonOptions = context.RequestServices.GetService<IOptions<JsonOptions>>();
// Serialise using the settings provided
var json = JsonSerializer.Serialize(
new {Foo = "bar"}, // Switch this with your object
jsonOptions?.Value.JsonSerializerOptions);
// Write to the response
await context.Response.WriteAsync(json);
}
else
{
await next(context);
}
};
});

ElasticSearch Index/Insert with NEST fail

I'm trying to insert some JSON data into elastic search for testing.
here is the code:
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node);
settings.DefaultIndex("FormId");
var client = new ElasticClient(settings);
var myJson = #"{ ""hello"" : ""world"" }";
var response = client.Index(myJson, i => i.Index("FormId")
.Type("resp")
.Id((int)r.id)
.Refresh()
);
Nothing is inserted, and I get the following error from ES:
{Invalid NEST response built from a unsuccesful low level call on PUT: /FormId/resp/1?refresh=true}
I've tried to find some example on that but all use a predefined structure of data, instead I want to use JSON data, with unstructured data.
The above error messsage is from NEST.
Elastic replies (and write in the log) the following message:
MapperParsingException[failed to parse]; nested- NotXContentException[Compressor detection can only be called on some xcontent bytes or compressed xcontent bytes];
Failed to parse { ""hello"" : ""world"" } ????
A few observations:
the index name needs to be lowercase
the index will be automatically created when you index a document into it, although this feature can be turned off in configuration. If you'd like to also control the mapping for the document, it's best to create the index first.
use an anonymous type to represent the json you wish to send (you can send a json string with the low level client i.e. client.LowLevel if you want to, but using an anonymous type is probably easier).
The .DebugInformation on the response should have all of the details for why the request failed
Here's an example to demonstrate how to get started
void Main()
{
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(node)
// lower case index name
.DefaultIndex("formid");
var client = new ElasticClient(settings);
// use an anonymous type
var myJson = new { hello = "world" };
// create the index if it doesn't exist
if (!client.IndexExists("formid").Exists)
{
client.CreateIndex("formid");
}
var indexResponse = client.Index(myJson, i => i
.Index("formid")
.Type("resp")
.Id(1)
.Refresh()
);
}
Now if we make a GET request to http://localhost:9200/formid/resp/1 we get back the document
{
"_index": "formid",
"_type": "resp",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"hello": "world"
}
}

Content Negotiation in ASP.NET Web API

I'm migrating a web service to ASP.NET Web Api 2, and hitting trouble at almost the first hurdle.
I want to do this:
public class SomeController : ApiController
{
[Route("some\url")]
public object Get()
{
return { Message = "Hello" };
}
}
And be able to ask the service for either "application/json" or "application/xml" (or indeed any other potential format, such as Message Pack), and get a serialized response. But it seems it only works for JSON.
I've read this and seen the documentation which states clearly that the framework cannot handle serialization of anonymous types into XML (seriously) and that the solution is to not use XML (seriously).
When I attempt to call this and request XML as response type, I get
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
I'm not removing support for clients wanting to ask for XML - but I genuinely can't find a work around for this - what can I do?
Edit
I've added these:
System.Web.Http.GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
config.Formatters.Insert(0, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
config.Formatters.Insert(0, new System.Net.Http.Formatting.XmlMediaTypeFormatter());
as per Dalorzo's answer, but it made no difference.
For clarification, the service works absolutely fine when I call it using an accept header of application/json, but bombs when I call it with an accept header of application/xml.
You have 3 options:
Create a class with a proper name and return the object instead of an anonymous type.
Or if you want to return the anonymous instance, you should remove XML formatter, because anonymous types are not supported by XML Formatter
Create your own formatter inheriting from MediaTypeFormatter or BufferedMediaTypeFormatter
You can do it by following code :
public HttpResponseMessage GetTestData()
{
var testdata = (from u in context.TestRepository.Get().ToList()
select
new Message
{
msgText = u.msgText
});
return ActionContext.Request.CreateResponse(HttpStatusCode.OK, testdata);
}
// This Code Is Used To Change Contents In Api
public HttpResponseMessage GetAllcarDetails( string formate)
{
CarModel ST = new CarModel();
CarModel ST1 = new CarModel();
List<CarModel> li = new List<CarModel>();
ST.CarName = "Maruti Waganor";
ST.CarPrice = 400000;
ST.CarModeles = "VXI";
ST.CarColor = "Brown";
ST1.CarName = "Maruti Swift";
ST1.CarPrice = 500000;
ST1.CarModeles = "VXI";
ST1.CarColor = "RED";
li.Add(ST);
li.Add(ST1);
// return li;
this.Request.Headers.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));
//For Json Use "application/json"
IContentNegotiator negotiator =
this.Configuration.Services.GetContentNegotiator();
ContentNegotiationResult result = negotiator.Negotiate(
typeof(List<CarModel>), this.Request, this.Configuration.Formatters);
if (result == null) {
var response = new HttpResponseMessage(HttpStatusCode.NotAcceptable);
throw new HttpResponseException(response);
}
return new HttpResponseMessage() {
Content = new ObjectContent<List<CarModel>>(
li, // What we are serializing
result.Formatter, // The media formatter
result.MediaType.MediaType // The MIME type
)
};
}
Please browse your API route on Chrome. Chrome, by default shows output in XML format. If that doesn't happen, it means that your service is preventing XML format using media formatting.
And in that case, you should search your WebApiConfig. If nothing is present there, add this file to your project
using System.Net.Http.Formatting;
using System.Collections.Generic;
using System.Net.Http;
using System;
using System.Linq;
using System.Net.Http.Headers;
namespace ExampleApp.Infrastructure
{
public class CustomNegotiator : DefaultContentNegotiator
{
public override ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)
{
if(request.Headers.UserAgent.Where(x=>x.Product!=null&& x.Product.Name.ToLower().Equals("chrome")).Count() > 0)
{
return new ContentNegotiationResult(new JsonMediaTypeFormatter(), new MediaTypeHeaderValue("application/xml"));
}
else
{
return base.Negotiate(type, request, formatters);
}
}
}
}
and, in WebApiConfig.cs, add:
config.Services.Replace(typeof(IContentNegotiator), new CustomNegotiator());

Categories