Format JSON response using ASP.NET JsonResult Class - c#

I'm trying to integrate BlueImp jQuery file upload component into my ASP.NET 4 website. I have the file upload working and writing to disk, but the component requires that I return a JSON object from the server as confirmation of success, in a particular format:
{"files": [
{
"name": "picture1.jpg",
"size": 902604,
"url": "http:\/\/example.org\/files\/picture1.jpg",
"thumbnailUrl": "http:\/\/example.org\/files\/thumbnail\/picture1.jpg",
"deleteUrl": "http:\/\/example.org\/files\/picture1.jpg",
"deleteType": "DELETE"
},
{
"name": "picture2.jpg",
"size": 841946,
"url": "http:\/\/example.org\/files\/picture2.jpg",
"thumbnailUrl": "http:\/\/example.org\/files\/thumbnail\/picture2.jpg",
"deleteUrl": "http:\/\/example.org\/files\/picture2.jpg",
"deleteType": "DELETE"
}
]}
I'd like to use the JsonResultClass to return this object in my C#, but I'm not sure how to format the response correctly. I can probably do something like this:
var uploadedFiles = new List<object>();
uploadedFiles.Add(new { name = "picture1.jpg", size = 902604, url = "http://example.org/files/picture1.jpg", thumbnailUrl = "http://example.org/files/thumbnail/picture1.jpg", deleteUrl ="http://example.org/files/picture1.jpg", deleteType = "DELETE" });
uploadedFiles.Add(new { name = "picture2.jpg", size = 902604, url = "http://example.org/files/picture1.jpg", thumbnailUrl = "http://example.org/files/thumbnail/picture1.jpg", deleteUrl ="http://example.org/files/picture1.jpg", deleteType = "DELETE" });
return Json(uploadedFiles);
...but then I'm not sure how to wrap this in the outer 'files' object.
Can anyone point me (a .NET novice trying to learn!) in the right direction here. I've looked at the MSDN documentation but it doesn't go into detail about formatting or constructing more complex JSON objects.
Many thanks.

Replace:
return Json(uploadedFiles);
with:
return Json(new {files = uploadedFiles});
to create a new anonymous type with property "files", which has your original list as a value.

Related

Sending a json object in a post method

I am trying to create a virtual machine through a post method but I have not been able to create it since I cannot send the json file correctly.
This is my code:
// Create a json object
var deploy = new Deploy
{
name = "RandomName",
folder = "folder_3044",
resource_pool = "resgroup-4035"
};
//Change it into a json file
var deployResult = JsonConvert.SerializeObject(deploy);
//Change this file into a string so we can send it to the post method
var jsonContent = new StringContent(deployResult);
//Make post and send the needed information
var postResponse = await httpClient.PostAsync("URI", jsonContent);
return (content);
When executing my code in Postman it gives me a false positive because it sends something but it seems that it does not send the json as I wanted but the code below:
{
"headers": [
{
"key": "Content-Type",
"value": [
"text/plain; charset=utf-8"
]
},
{
"key": "Content-Length",
"value": [
"97"
]
}
]
}
Can anyone help me with this? I just need to send that json in my post like I do when sending from Postman.
Ps: I use .Net core and I can't change even if I want to.
This is the json that should be sent for it to work:
{
"name": "RandomName",
"placement": {
"folder": "folder_3044",
"resource_pool": "resgroup-4035"
}
}
Thank you to #Peter Csala's comment: When I specified the content-type as you advised, it worked. Just for future references, we need these two lines of code. (Don't forget to include the assembly System.Text on top.)
using System.Text;
new StringContent(deployResult, Encoding.UTF8, "application/json");

How to create adaptive cards with situational text values?

I am currently trying to create an adaptive card in a Waterfall Dialog for one of my bots that will display the name and search item (both strings) when rendered. Both of the values I want to use are stored in the Context.Activity.Value property of my dialog, so all I need to know is how to insert those values into my adaptive card at some point during its creation so that the "text" values of the text blocks can contain my values.
I have looked into using empty JSON objects in the adaptive card schema that I could fill somehow during the adaptive card's creation, but have not figured out how to insert said values. I'm a relative beginner with C# and Bot Framework, so I don't know what to try.
Below is the step in my Waterfall Dialog where the adaptive card is made:
private async Task<DialogTurnResult> AdaptiveCardTest(WaterfallStepContext stepContext,
CancellationToken cancellationToken)
{
var introCard = File.ReadAllText("./Content/AdaptiveCardTest.json");
var card = AdaptiveCard.FromJson(introCard).Card;
var attachment = new Attachment(AdaptiveCard.ContentType, content: card);
var response = MessageFactory.Attachment(attachment, ssml: card.Speak,
inputHint: InputHints.AcceptingInput);
await stepContext.Context.SendActivityAsync(response);
return await stepContext.NextAsync();
}
AdaptiveCardTest.json is the adaptive card's json file. At the moment it just has an image popup with some text which includes placeholders where I would like the user name and search item to go. The placeholder links are there because the actual links are ridiculously long.
{
"type": "AdaptiveCard",
"id": "NewUserGreeting",
"backgroundImage": "image_url_placeholder"
"body": [
{
"type": "Container",
"items": [
{
"type": "Image",
"url": "image_url_placeholder_2"",
"size": "Stretch"
}
]
},
{
"type": "Container",
"spacing": "None",
"backgroundImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAXCAIAAACAiijJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAqSURBVDhPY1RgL2SgDDBBaQrAqBEIMGoEAowagQCjRiDAqBEIQLERDAwAIisAxhgAwtEAAAAASUVORK5CYII=",
"items": [
{
"type": "TextBlock",
"id": "title",
"spacing": "Medium",
"size": "Large",
"weight": "Bolder",
"color": "Light",
"text": "Hi, I'm **your** Virtual Assistant",
"wrap": true
},
{
"type": "TextBlock",
"id": "body",
"size": "Medium",
"color": "Light",
"text": "The user {{Name}} would like to know more about {{SearchItem}}.",
"wrap": true
}
]
}
],
}
Any help would be greatly appreciated, thank you!
For your simple scenario I would go with #MikeP's suggestion. In the future if you want to do something more complex where a template won't suffice, then you can build the Adaptive Card dynamically using the .NET SDK once you have installed the AdaptiveCard NuGet package.
The documentation on the .NET SDK is pretty limited but the properties of the AdaptiveCard object usually align with their JSON counterparts.
An example is:
const string ISO8601Format = "yyyy-MM-dd";
string text = "dynamic-text-here;
DateTime today = DateTime.Today;
string todayAsIso = today.ToString(ISO8601Format);
// Create card
AdaptiveCard adaptiveCard = new AdaptiveCard("1.0")
{
Body =
{
new AdaptiveContainer
{
Items =
{
new AdaptiveTextBlock
{
Text = question,
Wrap = true
},
new AdaptiveDateInput
{
// This Id matches the property in DialogValueDto so it will automatically be set
Id = "UserInput",
Value = todayAsIso,
Min = today.AddDays(-7).ToString(ISO8601Format),
Max = todayAsIso,
Placeholder = todayAsIso
}
}
}
},
Actions = new List<AdaptiveAction>
{
new AdaptiveSubmitAction
{
// Data can be an object but this will require the value provided for the
// Content property to be serialised it to a string
// as per this answer https://stackoverflow.com/a/56297792/5209435
// See the attachment block below for how this is handled
Data = "your-submit-data",
Title = "Confirm",
Type = "Action.Submit"
}
}
};
// Create message attachment
Attachment attachment = new Attachment
{
ContentType = AdaptiveCard.ContentType,
// Trick to get Adapative Cards to work with prompts as per https://github.com/Microsoft/botbuilder-dotnet/issues/614#issuecomment-443549810
Content = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(adaptiveCard))
};
cardActivity.Attachments.Add(attachment);
// Send the message
context.SendActivityAsync(cardActivity);
Because Items and Actions are collections, you could have conditional logic inside your code to build up these collections based on some condition at runtime then pass the build collection to Items or Actions which will allow you more flexibility than having a JSON template that you replace placeholder tokens at a known location.
This is something that I have done in the past using Handlebars which is a nice way of replacing tokens in your adaptive card JSON with properties from a model. Just make sure the tokens in your adaptive card JSON match the model properties
Have a look at their site for more detail but it is just a case of doing:
Handlebars.Compile(<Adaptive card template>);
Handlebars is available as a Nuget package you can add into your project.

Trying to PUT string with Postman in local C# web api, always null or fails

I currently have this WEB API running locally:
// POST api/CsvParse
[HttpPut]
public void Put([FromBody]string value)
{
if (string.IsNullOrEmpty(value))
throw new Exception("Input is null or empty.");
}
I currently have it running locally, and am sending a string to the put using POSTMAN. I have selected the body tab, and have the string pasted into the raw body tab:
It states that my text is unsupported, or when I add a break point the value is null or I get the error describing the format is incorrect.
What am I doing wrong?
That's because there is no media type formatter that can serialize a raw string into your model (your route parameter with [FromBody] attribute).
A quick and dirty workaround is to directly read the body of your request as a string:
[HttpPut]
public async Task<HttpResponseMessage> Put(HttpRequestMessage request)
{
var myCsv = await request.Content.ReadAsStringAsync();
// do stuff with your string
return new HttpResponseMessage(HttpStatusCode.OK);
}
As an alternative you could implement a custom media type formatter yourself, as per this answer.
Change the media type to x-www-form-urlencoded rather than multipart/form-data.
Also, WebAPI is particular about FromBody parameters.
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
For you, I think this is the relevant part:
[FromBody] parameters must be encoded as =value
The final hurdle remaining is that Web API requires you to pass
[FromBody] parameters in a particular format. That’s the reason why
our value parameter was null in the previous example even after we
decorated the method’s parameter with [FromBody].
Instead of the fairly standard key=value encoding that most client-
and server-side frameworks expect, Web API’s model binder expects to
find the [FromBody] values in the POST body without a key name at all.
In other words, instead of key=value, it’s looking for =value.
This part is, by far, the most confusing part of sending primitive
types into a Web API POST method. Not too bad once you understand it,
but terribly unintuitive and not discoverable.
Try adding a content type of text/plain
There is a similar Q&A here
I found that solution #1 worked for me as I was trying to PUT JSON containing the Key/Value pair. So originally my JSON looked like this
{
"subscriber": {
"Id": "2",
"subscriptions":[
{
"Name": "Subscription 1",
"Id": "18",
"IsSubscribed": false
},
{
"Name": "Subscription 2",
"Id": "19",
"IsSubscribed": false
},
{
"Name": "Subscription 3",
"Id": "20",
"IsSubscribed": false
}
]
}
}
But I modified it to become
{
"Id": "2",
"subscriptions":[
{
"Name": "Subscription 1",
"Id": "18",
"IsSubscribed": false
},
{
"Name": "Subscription 2",
"Id": "19",
"IsSubscribed": false
},
{
"Name": "Subscription 3",
"Id": "20",
"IsSubscribed": false
}
]
}
And that worked. My PUT request from Postman was recognised in my C# web api using [FromBody]
Just to add my bit, there is one more solution to pass primitives into a POST or a PUT method. Just specify the model as JObject. ASP.Net core web api then binds incoming JSON object(containing primitives like string) into JObject model object.
Your code would look like this:
// POST api/CsvParse
[HttpPut]
public void Put([FromBody]JObject value)
{
//access your string data
string data = value[SPECIFY_KEY_HERE];
if (string.IsNullOrEmpty(data))
throw new Exception("Input is null or empty.");
}

String to Json convert issues

I have a Json which is converted to string and then writted in DataBase
function UpdateFilter() {
var filterOption = {
"filterTarget": "Books",
"filters": [
{ "cancelled": $("#showCancelledFilter").is(':checked') },
{ "completed": $("#showAllFilter").is(':checked') }
],
"page": page,
"sorting": sorting
};
var url = "Library/Books/UpdateFilter";
$.post(url, { pageFilters: JSON.stringify(filterOption) }, function (data) { });
}
Up until this point everything seems to be fine.
Issue starts when I am trying to get json from string:
var data = JObject.Parse(jsonString);
return Json(data, JsonRequestBehavior.AllowGet);
Seems fine BUT in:
$.get('Library/Books/GetPageFilters', null, function(data) {
filterOption = data;
}, "json");
I have received a object with 4 arrays (each on each json property, and each array has empty array inside it).
I assume that I am lacking something in converting string to json, but I can't get it.
What am I missing?
I gess your problem situated where you using $.get() jquery method. From documentation of $.get():
dataType Type: String The type of data expected from the server.
Default: Intelligent Guess (xml, json, script, or html).
Seem like Intelligent Guess can't understand what was come from server.
Try $.getJSON() insted.

Easiest way to read from a response from URL

I am new to C#, and did not find an easy piece of code to read a response from a URL. Example:
http://www.somesitehere.com/mysearch
The response is something like this ( I do not know what kind of response is this):
{ "response": {
"status": {
"code": "0",
"message": "Success",
"version": "4.2"
},
"start": 0,
"total": 121,
"images": [
{
"url": "www.someimagelinkhere.com/pic.jpg",
"license": {
"url": "",
"attribution": "",
"type": "unknown"
}
}
]
}}
After that I will to save that url "www.someimagelinkhere.com/pic.jpg" to a file. But this I know how to do. I just want to separate the url from the rest.
I saw this topic: Easiest way to read from a URL into a string in .NET
bye
Your response is of JSON Format. Use a library (NewtonSoft but there are others too) to extract the node you want.
You can use something like JSON.NET by Newton soft, which can be found and installed using NuGet Package Manager in Visual Studio.
Also you could just do this.
var jSerializer = new JavaScriptSerializer();
var result = jSerializer.DeserializeObject("YOUR JSON RESPONSE STRING");
The JSON string will not be a C# object with properties that match your names such as start, total, images, etc. If you need to you can create a strong type object and cast your converted object to that one for ease of use.
Strong typed version:
var jSerializer = new JavaScriptSerializer();
var result = (YourStrongType)jSerializer.DeserializeObject("YOUR JSON RESPONSE STRING");
var imgUrl = result.images[0].url;

Categories