ElasticSearch Index/Insert with NEST fail - c#

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"
}
}

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");

Custom response type in GraphQL .NET

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<>.

MS Graph API/Workbooks (Excel API): Updating a cell format in a UseRange

What's I'm doing well
I'm currently creating an dotnet core app to consume and process data from an Excel sheet stored in personal OneDrive. I'm using MSAL to create a session token and the data consumption is working great. Here's my working code:
// Get the range for data to process
var dataRangeRequest = myGraphServiceClient // an instance of GraphServiceClient
.Me.Drive.Items[fileItemId]
.Workbook
.Sheets[sheetId]
.UsedRange(valuesOnly: false)
.Request();
var dataRange = await dataRangeRequest.GetAsync(ct)
// Extract column names (headers) from the data range
var columnNames = dataRange.Text.First.ToObject<string[]>();
// Extract data cells from the data range
var lines = dataRange.Text.Skip(1).Select(line=>line.ToObject<string[]>).ToArray();
[...] // Here I process the lines using the columnNames.
// --EVERYTHING WORKS UNTIL HERE--
What I'm not doing well
Now, I want to turn red a faulty data cell in the original Excel document
var faultyCell = (row: 34, column: 5); // the row/column offset of the faulty cell in dataRange
// ---------------------------------
// --FOLLOWING CODE IS NOT WORKING--
// ---------------------------------
var changeRange = new WorkbookRange
{
RowIndex = faultyCell.row,
ColumnIndex = faultyCell.column,
RowCount = 1,
ColumnCount = 1,
Format = new WorkbookRangeFormat {Fill = new WorkbookRangeFill {Color = "red"}}
};
await dataRangeRequest.PatchAsync(changeRange, ct); // Throwing a Microsoft.Graph.ServiceException
I intercepted the HTTP request & response and it's the following:
REQUEST
PATCH https://graph.microsoft.com/v1.0/me/drive/items/<file id>/workbook/worksheets/{sheetId}/microsoft.graph.usedRange(valuesOnly=true) HTTP/1.1
{
"columnIndex": 5,
"rowIndex": 34,
"columnCount": 1,
"rowCount": 1,
"format": {
"fill": {
"color": "Red",
"#odata.type": "microsoft.graph.workbookRangeFill"
},
"#odata.type": "microsoft.graph.workbookRangeFormat"
},
"#odata.type": "microsoft.graph.workbookRange"
}
RESPONSE
400 Bad Request
{
"error": {
"code": "BadRequest",
"message": "Bad Request - Error in query syntax.",
"innerError": {
"date": "<the date>",
"request-id": "<a guid>",
"client-request-id": "<another guid>"
}
}
}
Success with a manual HTTP request
I succeed to update manually the cell using a HTTP request by following the documentation.
WORKING REQUEST:
PATCH https://graph.microsoft.com/v1.0/me/drive/items/<file id>/workbook/worksheets/{sheetId}/range(address='F35:F35')/format/fill
{"color": "red"}
Problems
I don't know how to generate this HTTP request from C# by using the Microsoft.Graph api. (the documentation is obsoleted, there's no .Format on IWorkbookWorksheetRangeRequestBuilder. This error seems documented on GitHub. Is there an easy way to use the graph SDK to send an arbritary http request?
More importantly: for this to work, I need to translate the cell offset to a range address. Is there an utility somewhere to do that? In my example I manually translated the offset 5,34 in the range to address F35.
Specifications
Packages:
Microsoft.Graph: v3.15.0 (latest release version)
Microsoft.Identity.Client: (MSAL) v4.15.0 (not the latest version, but shoudn't be a problem here)
I can confirm, that this issue with no .Format on IWorkbookWorksheetRangeRequestBuilder is frustrating for me as well ;) I've reported this issue on GitHub:
https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/233
For me the workaround was to do it like so (i was basing it on this SOF: REST call to Microsoft Graph
var requestUrl = $#"https://graph.microsoft.com/v1.0/users/{user id}/drive/items/{Consts.DriveId}/workbook/worksheets/{Consts.SheetId}/range(address='{range}')/{resource}";
string workbookRangeFill = GraphServiceClient.HttpProvider.Serializer.SerializeObject(workbookRange);
// Create the request message and add the content.
HttpRequestMessage hrm = new HttpRequestMessage(new HttpMethod(httpMethod), requestUrl);
hrm.Content = new StringContent(workbookRangeFill, System.Text.Encoding.UTF8, "application/json");
// Authenticate (add access token) our HttpRequestMessage
await GraphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
HttpResponseMessage response = await GraphServiceClient.HttpProvider.SendAsync(hrm);
Whereas workbookRange variable is of either of type: WorkbookRangeFill or WorkbookRangeFont (Depending on the need) I assume you will be interested in WorkbookRangeFill (to change the color in range/cell)
range variable is range in spreadsheet in the format: "A1:B3"
resource variable is format/fill for WorkbookRangeFill and format/font for WorkbookRangeFont
and of course {user id} is the user which owns the document (i am using client credentials flow with with application permisions For other scenarios i assume you can just change one thing in the code above. So that, instead of:
https://graph.microsoft.com/v1.0/users/{user id}/drive
to use
https://graph.microsoft.com/v1.0/me/drive

Elastic search bulk index with C# API

I want to bulk index json records to elastic search with NEST or Elasticsearch.Net API
My json data is :
{"index":{"_index":"abc","_type":"abc","_id":1}},{"Name":"ApplicationFrameHost","CPU":1.25,"Company":null,"Product":null,"Path":null},{"index":{"_index":"abc","_type":"abc","_id":2}},{"Name":"Calculator","CPU":0.5,"Company":null,"Product":null,"Path":null},{"index":{"_index":"abc","_type":"abc","_id":3}},{"Name":"chrome","CPU":142.9375,"Company":null,"Product":null,"Path":null},{"index":{"_index":"abc","_type":"abc","_id":4}},{"Name":"chrome","CPU":3336.34375,"Company":null,"Product":null,"Path":null},{"index":{"_index":"abc","_type":"abc","_id":5}},{"Name":"chrome","CPU":7.1875,"Company":null,"Product":null,"Path":null}\n\n
my code:
var connectionSettings = new ConnectionSettings(new
Uri("http://localhost:9200/"));
var client2 = new ElasticClient(connectionSettings);
var jsonPostData = new PostData<object>(myJson);
var bulkRequestParameters = new BulkRequestParameters
{
};
Func<BulkRequestParameters, BulkRequestParameters> convert = delegate
(BulkRequestParameters s)
{
s.ErrorTrace(true);
return s.Refresh(Refresh.True);
};
var response = client2.LowLevel.Bulk<VoidResponse>("abc", "abc",
jsonPostData, convert);
In the response elastic return success with no error but still, data is not available on elastic?
Debug info from elastic:Successful low level call on POST: /abc/abc/_bulk?error_trace=true&refresh=true
It would be very helpful if someone can provide any clue what I am doing wrong here?
Solved this by modifying input JSON format after each record-set it does not requires comma:
{"index":{"_index":"abc","_type":"abc","_id":1}}{"Name":"ApplicationFrameHost","CPU":1.25,"Company":null,"Product":null,"Path":null}{"index":{"_index":"abc","_type":"abc","_id":2}},{"Name":"audiodg","CPU":1.5625,"Company":null,"Product":null,"Path":null}{"index":{"_index":"abc","_type":"abc","_id":3}},{"Name":"Calculator","CPU":0.5,"Company":null,"Product":null,"Path":null}{"index":{"_index":"abc","_type":"abc","_id":4}},{"Name":"chrome","CPU":144.109375,"Company":null,"Product":null,"Path":null}{"index":{"_index":"abc","_type":"abc","_id":5}},{"Name":"chrome","CPU":3384.609375,"Company":null,"Product":null,"Path":null}

Bad Request: QUERY_ID_INVALID telegram bot api

I Want use telegram api bot . every thing is ok (in my idea) but i have stupid error that where ever is search i cant find any thing .
I am using Inline mode .
var awnser = new AnswerInlineQuery()
{
inline_query_id =model.inline_query.id,
results = new List<InlineQueryResultArticle>()
};
awnser.results.Add(new InlineQueryResultArticle() { id = Guid.NewGuid().ToString("N"), type = "article", url = "fidilio", input_message_content = new InputTextMessageContent() { message_text = "salam" }, title = "test" });
var send = SendInlineAwnser(awnser);
The send method is using restsharp
var ser = JsonConvert.SerializeObject(data);
var url = "https://api.telegram.org/bot" + telegramToken + "/answerInlineQuery";
var req = SimplePost<AnswerInlineQuery>(ser, url);
my serlization out put is this
{"inline_query_id":"302418856930797437","results":[{"type":"article","id":"fae56651b23244f8a3be94b1e6ebf6e7","title":"test","input_message_content":{"message_text":"salam"},"url":"fidilio"}]}
make sure that model.inline_query.id is correct and if so, keep in mind that you can send notify max 15 sec after inline keyboard pushed. Besides, I suggest using async method for sending inline query results.

Categories