How can I property output for application/x-ndjson - json

#GetMapping(produces = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_NDJSON_VALUE
})
public Flux<Some> read() {
}
When I curl with --header 'Accept: application/x-ndjson'
The outer array is gone but all new lines in each elements is not gone.
{
"some": "thing"
}
{
"some": "other"
}
How can I make them as single-line as possible?

Related

How to localize exception message for Json deserialization? An invalid parameter was passed when requesting the interface?

My development environment is.Net7 WebApi (out of the box)
Below is the relevant code. DataAnnotations I have implemented localization.
using System.ComponentModel.DataAnnotations;
namespace WebApi.Dtos
{
public class UserRegistrationDto
{
[Required(ErrorMessage = "UserNameRequiredError")]
[MinLength(6, ErrorMessage = "UserNameMinLengthError")]
[MaxLength(30, ErrorMessage = "UserNameMaxLengthError")]
public required string UserName { get; set; }
[Required(ErrorMessage = "PasswordRequiredError")]
public required string Password { get; set; }
}
}
[HttpPost]
public async Task<IActionResult> RegisterUser([FromBody] UserRegistrationDto userRegistration)
{
return Ok(1);
// IdentityResult userResult = await _userManager.CreateAsync(new IdentityUser { UserName = userRegistration.UserName }, userRegistration.Password);
// return userResult.Succeeded ? StatusCode(201) : BadRequest(userResult);
}
When the request body is invalid JSON.
curl -X 'POST' \
'https://localhost:7177/Authenticate/RegisterUser' \
-H 'accept: */*' \
-H 'Api-Version: 1.0' \
-H 'Content-Type: application/json' \
-d '{}'
{
"$": [
"JSON deserialization for type 'WebApi.Dtos.UserRegistrationDto' was missing required properties, including the following: userName, password"
],
"userRegistration": [
"The userRegistration field is required."
]
}
When the request body is Empty.
curl -X 'POST' \
'https://localhost:7177/Authenticate/RegisterUser' \
-H 'accept: */*' \
-H 'Api-Version: 1.0' \
-H 'Content-Type: application/json' \
-d ''
{
"": [
"The userRegistration field is required."
]
}
It throws exception information before binding to DTO, can this exception information be localized? If not, is it possible to capture this information for secondary processing, such as returning a fixed JSON format?
I've tried this in the Program.cs entry file, but it's not ideal.
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressModelStateInvalidFilter = false;
options.InvalidModelStateResponseFactory = context =>
{
bool knownExceptions = context.ModelState.Values.SelectMany(x => x.Errors).Where(x => x.Exception is JsonException || (x.Exception is null && String.IsNullOrWhiteSpace(x.ErrorMessage) == false)).Count() > 0;
if (knownExceptions)
{
return new BadRequestObjectResult(new { state = false, message = localizer["InvalidParameterError"].Value });
}
// ...
return new BadRequestObjectResult(context.ModelState);
};
})
I have also tried this method, but I can’t capture the exception information that failed when binding DTO alone. They will appear together with the ErrorMessage exception information in DTO like the above writing method.
.AddControllers(options =>
{
// options.Filters.Add(...);
// options.ModelBindingMessageProvider // This doesn't work either, it seems to support [FromForm]
})
Back to the topic, can it be localized? Or there is something wrong with the code. I just learned .Net not long ago. Most of the information I learned came from search engines and official documents. Thanks in advance.
Use the following method.
.AddControllers(options =>
{
// options.ModelBindingMessageProvider.Set...
})
It seems that the exception of JSON deserialization caused by passing invalid parameters can only be eliminated on the client side. So far it seems I haven't found a localization for this exception, but it's not very important to me at the moment.
Thanks #XinranShen for helping point me in the right direction.

Newtonsoft.json SelectToken Replace differs from SelectTokens Replace in foreach with a NullReferenceException

Hope anybody could guide me here. I spend some hours on it and can't understand what's going on.
Mission: Replace a json element by a jsonpath search tag. (sort of $ref feature)
In my code example below i want to replace the value of DataReaderUser by a value found by the json path search $.UsersAndGroups.Users[?(#.Name == 'OMDASAccountUser')].Username . In this case it should result in the value "contoso\SVCSCOM-DO-OMDAS"
The code below works as expected.. the issue is below this code ..
https://dotnetfiddle.net/gEjggK
using System;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string json = #"{
""SQLServer"": {
""SQLReportingServices"": {
""AccountSettings"": {
""DataReaderUser"": {""$JsonPath"": ""$.UsersAndGroups.Users[?(#.Name == 'OMDASAccountUser')].Username""},
}
}
},
""UsersAndGroups"": {
""Users"": [
{
""Name"": ""OMActionAccountUser"",
""Username"": ""contoso\\SVCSCOM-DO-OMDAS"",
},
{
""Name"": ""OMDASAccountUser"",
""Username"": ""contoso\\SVCSCOM-DO-OMDAS"",
}
]
}
}";
JObject jo = JObject.Parse(json);
var JsonPath = jo.SelectToken("..$JsonPath");
JsonPath.Parent.Parent.Replace(jo.SelectToken(JsonPath.ToString()));
Console.WriteLine(jo.ToString());
}
}
The output will be :
{
"SQLServer": {
"SQLReportingServices": {
"AccountSettings": {
"DataReaderUser": "contoso\\SVCSCOM-DO-OMDAS"
}
}
},
"UsersAndGroups": {
"Users": [
{
"Name": "OMActionAccountUser",
"Username": "contoso\\SVCSCOM-DO-OMDAS"
},
{
"Name": "OMDASAccountUser",
"Username": "contoso\\SVCSCOM-DO-OMDAS"
}
]
}
}
Now the issue:
I want to do the same for all possible jsonpaths refers. So i use the SelectTokens and an foreach . But it looks like the behavior is different , the parents are null.
https://dotnetfiddle.net/lZW3XP
using System;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
string json = #"{
""SQLServer"": {
""SQLReportingServices"": {
""AccountSettings"": {
""DataReaderUser"": {""$JsonPath"": ""$.UsersAndGroups.Users[?(#.Name == 'OMDASAccountUser')].Username""},
}
}
},
""UsersAndGroups"": {
""Users"": [
{
""Name"": ""OMActionAccountUser"",
""Username"": ""contoso\\SVCSCOM-DO-OMDAS"",
},
{
""Name"": ""OMDASAccountUser"",
""Username"": ""contoso\\SVCSCOM-DO-OMDAS"",
}
]
}
}";
JObject jo = JObject.Parse(json);
var JsonPaths = jo.SelectTokens("..$JsonPath");
foreach (var JsonPath in JsonPaths )
{
JsonPath.Parent.Parent.Replace(jo.SelectToken(JsonPath.ToString()));
}
Console.WriteLine(jo.ToString());
}
}
And the output:
Run-time exception (line 34): Object reference not set to an instance of an object.
Stack Trace:
[System.NullReferenceException: Object reference not set to an instance of an object.]
at Newtonsoft.Json.Linq.JsonPath.PathFilter.GetNextScanValue(JToken originalParent, JToken container, JToken value)
at Newtonsoft.Json.Linq.JsonPath.ScanFilter.<ExecuteFilter>d__4.MoveNext()
at Program.Main() :line 34
would be great to get some directions since i am spinning my head here.
michel
SelectTokens uses lazy evaluation and if you modify the token while enumerating all matches it can break in unexpected ways. A simple fix is to add ToArray() to force eager evaluation:
var JsonPaths = jo.SelectTokens("..$JsonPath").ToArray();

Grails 2.5 REST PUT not getting called

Grails 2.4 RESTful controller.
I have a basic question. I have a RESTful controller with simple domain class and my GET, POST works fine.
How do I send PUT JSON request?
I am using default RESTful generated controllers
url -i -X POST -H "Content-Type: application/json" -d '{"roleId":1,"username":"testuser5"}' http://localhost:8090/testapp/User
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 03 Jul 2014 02:07:13 GMT
{"id":null,"userId":79,"username":"testuser5"}
Then I tried PUT using same above JSON response (removed id:null and changed the username):
curl -i -X PUT -H "Content-Type: application/json" -d '{"userId":79,"username":"testuser6"}' http://localhost:8090/testapp/User
Request goes to index and I get list of users. What I am doing wrong? How do I invoke "update' method? If I add my own method and I do PUT, my own method gets invoked.
Domain class:
class User {
Integer userId
String username
static mapping = {
table 'user'
version false
id name:'userId', column: 'user_id'
}
static constraints = {
username blank:false, nullable:false
}
}
RESTful controller:
class UserController extends RestfulController {
static responseFormats = ['json', 'xml']
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond User.list(params), model:[userInstanceCount: User.count()]
}
def show(User userInstance) {
respond userInstance
}
def create() {
respond new User(params)
}
#Transactional
def update(User userInstance) {
println "*** in update "
if (userInstance == null) {
notFound()
return
}
if (userInstance.hasErrors()) {
respond userInstance.errors, view:'edit'
return
}
userInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'User.label', default: 'User'), userInstance.id])
redirect userInstance
}
'*'{ respond userInstance, [status: OK] }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
You're missing the call to user.validate() prior to calling hasErrors(). See
https://github.com/grails/grails-core/blob/master/grails-plugin-rest/src/main/groovy/grails/rest/RestfulController.groovy#L99

JSON.Net Serialize list with root name

I've looked and can't find anything and this is really starting to annoy me...
I've got JSON.Net and the following snippet of code
var x = insList.Select(a => new
{
ac = a.CreatedDate,
bd = a.CreatedBy
});
this.Context.Response.Write(x.ToJSON());
.ToJSON() is a simple extension method:
public static string ToJSON(this object obj)
{ return JsonConvert.SerializeObject(obj); }
The json output is
Ideally what I'd like is the highlight bits to have the same root name, rather than just {}
Can anyone help please?
Objects do not have names in JSON, properties do. (See JSON.org.) Therefore, if you want to name an object, you'll have to make it the value of a property of another containing object.
var x = insList.Select(a => new
{
rootName = new
{
ac = a.CreatedDate,
bd = a.CreatedBy
}
});
This will yield the following JSON:
[
{
"rootName": {
"ac": "0001-01-01T00:00:00",
"bd": 0
}
},
{
"rootName": {
"ac": "0001-01-01T00:00:00",
"bd": 0
}
},
{
"rootName": {
"ac": "0001-01-01T00:00:00",
"bd": 0
}
}
]

JSON model binding with XML Serialisation attributes in Web API

I have an API controller with the following action signature...
[HttpPost]
public HttpResponseMessage DoSearch(SearchParameters parameters)
SearchParameters is not something i can modify, and the decompiled source looks like this...
[DebuggerStepThrough]
[XmlRoot("SearchData", IsNullable = false, Namespace = "http://company.com/some/namespace/v1")]
[GeneratedCode("xsd", "2.0.50727.3038")]
[DesignerCategory("code")]
[XmlType(Namespace = "http://company.com/some/namespace/v1")]
[Serializable]
public class SearchParameters
{
private string[] _searchCodes;
[XmlArrayItem("SearchCode", IsNullable = false)]
public string[] SearchCodes
{
get
{
return this._searchCodes;
}
set
{
this._searchCodes = value;
}
}
}
I can call the endpoint successfully with an XML payload, but cannot get JSON to work at all. The SearchCodes property is always null.
If i replace the SearchParameters Type with a POCO that has none of the Xml Serialisation attributes on it, it works fine with JSON.
This led me to think that the JsonMediaTypeFormatter is unable to match up the property correctly due to the xml serialisation attributes (even though this shouldnt matter, as its JSON, not XML right?).
I changed the JsonFormatter to use the DataContract Serializer, but that has made no difference.
httpConfiguration.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;
I tried crafting different structures of JSON to see if i could 'help' it understand, but none of these work either...
{
"SearchData": {
"SearchCodes": {
"SearchCode": [
"SYAA113F",
"N0TEXI5T",
"SYAA112C"
]
}
}
}
{
"SearchCodes": {
"SearchCode": [
"SYAA113F",
"N0TEXI5T",
"SYAA112C"
]
}
}
{
"SearchCodes": [
"SYAA113F",
"N0TEXI5T",
"SYAA112C"
]
}
{
"SearchData": {
"SearchCode": [
"SYAA113F",
"N0TEXI5T",
"SYAA112C"
]
}
}
{
"SearchCode": [
"SYAA113F",
"N0TEXI5T",
"SYAA112C"
]
}
{
"SearchCodes": [
{ "SearchCode" : "SYAA113F" },
{ "SearchCode" : "SYAA113F" },
{ "SearchCode" : "SYAA113F" }
]
}
How can i debug this further? and what am i missing?
What is causing the JSON media formatter to behave differently due to the XML attributes?
Post this JSON and see.
{"_searchCodes":[
"SYAA113F",
"N0TEXI5T",
"SYAA112C"]
}
Remember to set Content-Type: application/json.