I am trying to serialize a FeatureCollection so I can pass it as a request body. To do this I am using a NetTopologySuite.IO.GeoJSON package and using the instruction they provide on their github page. The problem is, when hitting the jsonSerializer.Serialize method, I get an error saying: {"At least one element in the source array could not be cast down to the destination array type."} System.Exception {System.InvalidCastException}.
My method looks like this:
private async Task<IEnumerable<VehicleArea>> GetVehiclesInAreas(FeatureCollection areas)
{
var uri = $"www.someurl/getByArea";
using var httpClient = new HttpClient();
string stringifiedAreas;
var jsonSerializer = GeoJsonSerializer.CreateDefault();
using (var stringWriter = new StringWriter())
using (var jsonwriter = new Newtonsoft.Json.JsonTextWriter(stringWriter))
{
jsonSerializer.Serialize(jsonwriter, areas);
stringifiedAreas = stringWriter.ToString();
}
StringContent content = new StringContent(stringifiedAreas, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(uri, content);
}
The GEOSJON object I am passing in the request body of my controller, that ends up being the areas FeatureCollection provided to the given method looks like this:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": 16,
"geometry": {
"type": "GeometryCollection",
"geometries": [
{
"type": "Polygon",
"coordinates": [
[
[
12.1234,
55.1234
],
[
12.7,
55.7],
[
12.8,
55.8
],
[
12.9,
55.9
],
[
12.1234,
55.1234
]
]
]
}
]
}
},
{
"type": "Feature",
"id": 16,
"geometry": {
"type": "GeometryCollection",
"geometries": [
{
"type": "Polygon",
"coordinates": [
[
[
12.1234,
55.1234
],
[
12.7,
55.7],
[
12.8,
55.8
],
[
12.9,
55.9
],
[
12.1234,
55.1234
]
]
]
}
]
}
}
]
}
Finally, here is a snippet of how the areas object looks like during runtime:
Thanks to #FObermaier's comment, I was able to implement a solution. As he mentioned, I am using a NetTopologySuite.IO.GeoJSON4STJ package which uses the System.Text.Json. By refactoring my code to use System.Text.Json.JsonSerializer, I was able to make it work. For anyone encountering the same issue, make sure to also pass the options object with the GeoJsonConverter factory added as a converter. Here is the code example:
var options = new JsonSerializerOptions();
options.Converters.Add(new NetTopologySuite.IO.Converters.GeoJsonConverterFactory());
var serialized = JsonSerializer.Serialize(areas, options);
var stringifiedAreas = serialized.ToString();
Related
Hi,
I use Atata framework with ExtentReports, based on this project: https://github.com/atata-framework/atata-samples/tree/master/ExtentReports
Now I want switch from fluent context build to json config. My fluent context build looks like:
AtataContext.GlobalConfiguration
.UseChrome()
.WithArguments("--start-maximized")
.WithLocalDriverPath()
.WithFixOfCommandExecutionDelay()
.UseCulture("en-US")
.UseAllNUnitFeatures()
.AddDebugLogging()
.AddScreenshotFileSaving()
.WithArtifactsFolderPath()
.AddLogConsumer(new ExtentLogConsumer())
.WithMinLevel(LogLevel.Info)
.EventSubscriptions.Add(new ExtentScreenshotFileEventHandler());
AtataContext.GlobalConfiguration.AutoSetUpDriverToUse();
I can implement via json config almost all, except this line:
.EventSubscriptions.Add(new ExtentScreenshotFileEventHandler());
My config:
{
"driver": {
"type": "chrome",
"alias": "chrome",
"options": {
"arguments": [ "start-maximized" ],
"userProfilePreferences": {
"download.default_directory": "{artifacts}"
}
}
},
"culture": "en-US",
"useAllNUnitFeatures": true,
"logConsumers": [
{
"type": "nlog-file",
"folderPath": "{artifacts}",
"minLevel": "Debug"
},
{
"type": "AtataUITests1.Core.Reporting.ExtentLogConsumer, AtataUITests1",
"minLevel": "Info"
}
],
"screenshotConsumers": [
{
"type": "file",
"folderPath": "{artifacts}"
}
]
}
When I try to add new screenshotConsumer to json:
"screenshotConsumers": [
{
"type": "file",
"folderPath": "{artifacts}"
},
{
"type": "AtataUITests1.Core.Reporting.ExtentScreenshotFileEventHandler, AtataUITests1"
}
]
it shows error:
System.InvalidCastException : Unable to cast object of type 'AtataUITests1.Core.Reporting.ExtentScreenshotFileEventHandler' to type 'Atata.IScreenshotConsumer'.
My question is: is it possible to pass this custom screenshot consumer via json?
Thanks
ExtentScreenshotFileEventHandler is not a screenshot consumer but an event handler. So it should be placed in "eventSubscriptions" section as below:
"eventSubscriptions": [
{
"handlerType": "AtataUITests1.Core.Reporting.ExtentScreenshotFileEventHandler, AtataUITests1"
}
]
There is also an example on Atata.Configuration.Json / JSON Schema section.
I would like to understand how to read/write data with Adaptive cards. I can read the data from a submit action, and reply as text, but not sure how present the input data in the card. First place, I would like to add the shootValue to an array that I can carry trough the lifecycle of the card. Can somebody please let me know how to do this?
The goal of this question is to understand how to keep existing responses from the card.
Like in Battleship, I shoot "A1", type it in an input box, submit, I would like to see "A1" in the card. I add "A2", submit, then I would like to see "A1" and "A2" in the card that is sent to Teams. I understand that I need to rebuild the card from scratch at every shot, that means, I need to either carry on the shots somehow with each action.
Data card:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Hello {name}"
},
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "stretch",
"id": "",
"items": [
{
"type": "Container",
"items": [
{
"type": "Input.Text",
"placeholder": "Voorbeeld: A1",
"id": "id_shoot",
"$data": "shoot"
}
]
}
]
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": " {shoot}",
"horizontalAlignment": "Right",
"id": ""
}
],
"$data": "{shoots}",
"id": "shotcoords"
}
],
"$data": "{shots}"
},
{
"type": "Column",
"width": "stretch",
"items": [
{
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": "{status}",
"id": ""
}
],
"$data": "{shoots}",
"id": "shotstatuses"
}
],
"id": ""
}
]
},
{
"type": "ActionSet",
"id": "",
"actions": [
{
"type": "Action.Submit",
"title": "Shoot",
"id": "",
"style": "positive",
"data": {}
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
Data
{
"name": "Test shot",
"shoots": [
{
"shoot": "a1",
"status": "hit"
},
{
"shoot": "a2",
"status": "hit"
}
]
}
There is no "simple" way to do this, but there is a way. The answer will be similar to this one.
First, you'll need a way of saving state for your card so you can update the card's activity. In C# you can declare a state property accessor like this:
public IStatePropertyAccessor<Dictionary<string, (string ActivityId, List<string> Shots)>> BattleshipStateAccessor { get; internal set; }
Then you can instantiate it like this
BattleshipStateAccessor = _conversationState.CreateProperty<Dictionary<string, (string, List<string>)>>("battleshipState");
You have a few decisions to make here. First, I'm choosing to make the state property a dictionary so I can keep track of multiple cards and only update the specific card that was clicked. If you don't care about that then you don't need a dictionary and you don't need to worry about "card ID's," but saving at least one activity ID is necessary so that you'll be able to update the card. As for saving the "shots," you have a few choices here. You could save that state on the client side by updating the submit action's data with each shot that's been made, but I figure I might as well save the shots in bot state because I already need to save the activity ID in bot state anyway. Then there's the question of what information about each shot you should save. In this example I'm only saving the location of the shot that the user entered and not the status of the shot, since I figure I can always recalculate the status whenever I need to.
I've modified your submit action to look like this:
{
"type": "Action.Submit",
"title": "Shoot",
"style": "positive",
"data": {
"behavior": "Shoot",
"cardId": ""
}
}
What I've done here is added two properties to your data object, and this data will be sent to your bot along with the text input's value. The "behavior" property will help your bot route to the correct function in case your bot uses multiple types of actions that can be handled different ways. The "cardId" property is just a placeholder that your bot code will fill in when creating the card. I've stored the names of these properties in the constants KEYBEHAVIOR and KEYCARDID.
You'll want a consistent way to generate your card that you can use when you send the card initially and when you update the card.
internal static IMessageActivity CreateBattleshipCardActivity(
string cardId,
object data = null)
{
data = data ?? new
{
name = "Test shot",
shoots = new string[0],
};
JObject card = CreateAdaptiveCard("battleship", data);
foreach (var token in card.Descendants()
.Select(token => token as JProperty)
.Where(token => token?.Name == KEYCARDID))
{
token.Value = cardId;
}
return MessageFactory.Attachment(new Attachment(
AdaptiveCard.ContentType,
content: card));
}
The CreateAdaptiveCard function loads the JSON template from a file with the given name, transforms it with the given data, and deserializes it into a JObject.
Using this function, you can send the card initially like this in C#:
public async Task TestBattleshipAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
var cardId = Guid.NewGuid().ToString();
var reply = CreateBattleshipCardActivity(cardId);
var response = await turnContext.SendActivityAsync(reply, cancellationToken);
var dict = await BattleshipStateAccessor.GetAsync(
turnContext,
() => new Dictionary<string, (string, List<string>)>(),
cancellationToken);
dict[cardId] = (response.Id, new List<string>());
}
And you can update the card in response to the card's "Shoot" submit action like this:
private async Task ShootAsync(
ITurnContext turnContext,
CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
if (activity.ChannelId == Channels.Msteams)
{
var value = JObject.FromObject(activity.Value);
var cardId = Convert.ToString(value[BotUtil.KEYCARDID]);
var dict = await BattleshipStateAccessor.GetAsync(
turnContext,
() => new Dictionary<string, (string, List<string>)>(),
cancellationToken);
if (dict.TryGetValue(cardId, out var savedInfo))
{
savedInfo.Shots.Add(value["id_shoot"].ToString());
var data = new
{
name = "Test shot",
shoots = savedInfo.Shots.Select(shot => new
{
shoot = shot,
status = DetermineHit(shot),
}),
};
var update = CreateBattleshipCardActivity(cardId, data);
update.Id = savedInfo.ActivityId;
update.Conversation = activity.Conversation;
await turnContext.UpdateActivityAsync(update, cancellationToken);
}
}
}
This is the sample on Botframework v4 docs. But it does not work.
It says "Can't Render Card" on the Microsoft bot emulator.
What i'm trying to do is a carouselCard but this simple card from Microsoft's sample is already not working.
{
"type": "message",
"text": "Plain text is ok, but sometimes I long for more...",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Hello World!",
"size": "large"
},
{
"type": "TextBlock",
"text": "*Sincerely yours,*"
},
{
"type": "TextBlock",
"text": "Adaptive Cards",
"separation": "none"
}
],
"actions": [
{
"type": "Action.OpenUrl",
"url": "http://adaptivecards.io",
"title": "Learn More"
}
]
}
}
]
}
However, if i remove the top part of the code this code works:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "Hello World!",
"size": "large"
},
{
"type": "TextBlock",
"text": "*Sincerely yours,*"
},
{
"type": "TextBlock",
"text": "Adaptive Cards",
"separation": "none"
}
],
"actions": [
{
"type": "Action.OpenUrl",
"url": "http://adaptivecards.io",
"title": "Learn More"
}
]
}
This is how i call the card. Is there a better way to do this?
public class GetNameAndAgeDialog : WaterfallDialog
{
private readonly string _cards = #".\Resources\TryCarouselCard.json";
private static Attachment CreateAdaptiveCardAttachment(string filePath)
{
var adaptiveCardJson = File.ReadAllText(filePath);
var adaptiveCardAttachment = new Attachment()
{
ContentType = "application/vnd.microsoft.card.adaptive",
Content = JsonConvert.DeserializeObject(adaptiveCardJson),
};
return adaptiveCardAttachment;
}
public GetNameAndAgeDialog(string dialogId, IEnumerable<WaterfallStep> steps = null) : base(dialogId, steps)
{
AddStep(async (stepContext, cancellationToken) =>
{
var cardAttachment = CreateAdaptiveCardAttachment(_cards);
var reply = stepContext.Context.Activity.CreateReply();
reply.Attachments = new List<Attachment>() { cardAttachment };
await stepContext.Context.SendActivityAsync(reply, cancellationToken);
return await stepContext.ContinueDialogAsync();
});
}
}
The "top part" of the first block of JSON you posted is the card contained within an activity. The second block of JSON posted is indeed just the card itself and what you'd want to put into an Attachment.
As for your code, it looks correct to me. I might consider caching the attachment JSON as you probably don't want to hit the file system every time you want to display the card, but that would just be an optimization.
I'm unclear if you are experiencing any further problems or just looking for validation of the approach now. If you are still experiencing a problem please update the question with some more details and I'll update my answer to try and help.
How can I post data in RestSharp ? I am very new to RestSharp and dont quite understand the process.
I am familar with Get Requests, which I have written API tests for with no problems.
Using the below example I want to post the Order Qty:
"name": "PostToCurrentBasket",
"class": [
"PostToCurrentBasket"
],
"method": "POST",
"href": "*",
"title": "Add Product to Current Basket",
"type": "application/json",
"fields": [
{
"name": "ProductId",
"type": "text",
"value": 101112,
"title": "Product ID"
},
{
"name": "Quantity",
"type": "number",
"value": 0,
"title": "Order Qty"
}
]
}
],
What I have so far:
var request = new RestRequest("baskets/current/", Method.POST);
Do I need to be using .AddBody and if so how do I use this correctly?
request.RequestFormat = DataFormat.Json; // If you want it to be json
request.AddBody(new { Name = "Foo", LastName = "Bar" }); // Any object that can be serialized
client.Execute(request);
I am planning to write a simple SugarCrm .Net client.
Could anyone give me a pointer to a .Net wrapper/library for the SugarCrm REST api?
//lasse
Realize this is old, but in case anyone stumbles across this looking for a .NET wrapper for newer version of the web service (SugarCRM > 6.7), here is a wrapper I am currently building https://github.com/dlively1/SugarSharp
There is a wrapper that uses SOAP called CandyWrapper, which is a bit old but could help you with a starting point on building your own.
http://developers.sugarcrm.com/wordpress/2011/08/10/web-services-in-your-own-language-part-6-candywrapper-for-net/
I also realize this is old, but for SugarCRM CE 6.x I created SugarRestSharp. The sample I give below is in json, but the request would be in C# models. This implements get_entry_list SugarCrm Rest API method.
Passing request to RestSharp:
dynamic data = new
{
session = sessionId,
module_name = moduleName,
query = queryString,
order_by = string.Empty,
offset = 0,
select_fields = selectFields,
link_name_to_fields_array = string.Empty,
max_results = maxCountResult,
deleted = 0,
favorites = false
};
var client = new RestClient(url);
var request = new RestRequest(string.Empty, Method.POST);
string jsonData = JsonConvert.SerializeObject(data);
request.AddParameter("method", "get_entry_list");
request.AddParameter("input_type", "json");
request.AddParameter("response_type", "json");
request.AddParameter("rest_data", jsonData);
var response = client.Execute(request);
Request in json
{
"session": "olgg6hf5sqi6hk9u3tgpafbn66",
"module_name": "Accounts",
"query": "",
"order_by": "",
"offset": 0,
"select_fields": [
"name",
"industry",
"website",
"shipping_address_city",
"id"
],
"link_name_to_fields_array": "",
"max_results": 10,
"deleted": 0,
"favorites": false
}
Response in json
{
"result_count": 10,
"total_count": "58",
"next_offset": 10,
"entry_list": [
{
"id": "1e0eec64-8cc6-58ff-57f1-58533731b145",
"module_name": "Accounts",
"name_value_list": {
"name": {
"name": "name",
"value": "New SugarRestSharp Acccount 1 10397"
},
"industry": {
"name": "industry",
"value": "Manufacturing"
},
"website": {
"name": "website",
"value": "www.sugarrestsharp1.com"
},
"shipping_address_city": {
"name": "shipping_address_city",
"value": "Los Angeles"
},
"id": {
"name": "id",
"value": "1e0eec64-8cc6-58ff-57f1-58533731b145"
}
}
},
......... (other 9 items truncated)
],
"relationship_list": [
]
}
For more implementation and wiki check SugarRestSharp: https://github.com/mattkol/SugarRestSharp