.NET 6 web api project needs to export XML and JSON - json

I have a web api project that has some actions (most) that need to export JSON, and some (only a few) that need to export as XML.
Since XML isn't supported by default, i've added the
services.AddControllers(options =>
{
options.OutputFormatters.Add(new Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerOutputFormatter());
})
bit to my Startup.cs, and added to the Action that needs XML:
[Produces("application/xml")]
public async Task<IActionResult> ExportAsKML(Guid id)
And this works for that method, but now ALL of my controller actions default to XML. How can I keep the default to JSON, but only use XML for a certain few actions?

Have you changed the order of your formats in OutputFormatters?
Accroding to the offcial document :Formatters are evaluated in the order they're inserted, where the first one takes precedence.
:
https://learn.microsoft.com/en-us/aspnet/core/web-api/advanced/custom-formatters?view=aspnetcore-6.0#configure-mvc-to-use-a-custom-formatter
check the order of the formats:
when I debug:
the default format become xml with out other settings,
in this order,

Related

ASP.NET Core .NET 6 app returning XML instead of JSON by default

We are migrating a .NET 2.2 app to .NET 6, and we are facing a problem where some third-party apps that make requests to our system without specifying the Accept HTTP header were getting back JSON data by default in .NET 2.2, but now they are getting XML when nothing is specified.
If I run the same request, but specify Accept as application/json, I get back JSON.
Our app returns 99% of the results in JSON, but has a specific SOAP endpoint that returns XML (it communicates with another SOAP web service and returns SOAP on this single endpoint).
The config is:
services.AddSoapCore();
services
.AddMvc()
.AddXmlSerializerFormatters()
.AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));
If I remove AddXmlSerializerFormatters(), the endpoint returns JSON correctly but then the SOAP endpoint stops working.
I am aware I can use the [Produces] attribute, but ideally we would keep the same default behavior instead of having to manually go through all endpoints.
Is there a way to configure the app to return JSON by default when nothing is specified, without removing XML support?
Asp.NET Core chooses registered formatters by their precedence and the order they added will be their precedence. So as you added XML formatter first, when no Accept header is appeared in request the first matched formatter will be XML formatter. Just add JSON formatter first.
I reproduced the issue and adding JSON formatter first, successfully fixed the problem
builder.Services
.AddMvc()
.AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()))
.AddXmlSerializerFormatters();

Microsoft.Net.Http vs Microsoft.AspNet.WebApi.Client

I need to access REST service from .NET application and it seems it can be done with any of those two packages. It's not clear to me which package is supposed to be used in which scenarios. Can anyone bring more light into this?
The short answer is yes, use Microsoft.AspNet.WebApi.Client.
https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Client/
This package adds support for formatting and content negotiation to
System.Net.Http. It includes support for JSON, XML, and form URL
encoded data.
Microsoft.AspNet.WebApi.Client actually depends on Microsoft.Net.Http, and extends the HttpClient with some more features that you would likely need to talk to a RESTful service such as ASP.NET Web API (e.g. JSON and XML support).
Both packages operate in the System.Net.Http namespace and revolve around the key HttpClient class.
The Microsoft.AspNet.WebApi.Client package contains the System.Net.Http.Formatting.dll assembly, which adds some handy extension methods to HttpClient and HttpContent (and others).
So for example:
using (var client = new HttpClient())
{
var response = await client.GetAsync("http://localhost/foo/api/products/1");
response.EnsureSuccessStatusCode();
var product = await response.Content.ReadAsAsync<ProductInfo>();
}
The ReadAsAsync method is an extension method that Microsoft.AspNet.WebApi.Client adds onto the HttpContent object. This automatically figures out if the response is JSON, XML or form URL encoded (the aforementioned content negotiation), and then uses the corresponding formatter to de-serialize it into your strongly typed model (in this case, ProductInfo).
If you tried to just use Microsoft.Net.Http, the ReadAsAsync method wouldn't be available to you, and you'd only be able to read the content as raw data such as bytes or string, and have to do the serializing / de-serializing yourself.
You also get extension methods to PUT / POST back to the service in JSON or XML without having to do that yourself:
// Save the ProductInfo model back to the API service
await client.PutAsJsonAsync("http://localhost/foo/api/products/1", product);
Key Microsoft.AspNet.WebApi.Client extensions:
https://msdn.microsoft.com/en-US/library/system.net.http.httpclientextensions.aspx
https://msdn.microsoft.com/en-US/library/system.net.http.httpcontentextensions.aspx

Difference between Kendo dataSource view and data methods

I've inherited a project that uses Kendo, and I'm still learning its basics. A feature I'm working on entails getting JSON data from the server and using it to display something in a Web page. For this I'll use a dataSource, call its read function on the appropriate URL, and specify a callback to render the data; but I'm unsure whether to use view() or data() to get the JSON data from the dataSource. They appear to serve very similar purposes. Which one is appropriate if I'm using a simple callback to render data from the server, and what's the difference?
Following Kendo UI documentation: The view() method returns only displayed data - after filtering, sorting, groupping and page selection. If you don't use any of this features or if you use it on the server side view() and data() will give you the same data.
In simple words view() returns displayed data and data() returns data available in dataSource (all data downloaded from service in the last read).
I'm working with Kendo for 2 years and I've almost always used the data() method for any type of action.

How can call the Alfresco REST API using Json String?

Please provide me some references to call WebScripts in alfresco remotely using JSON..
Alfresco has some default Webscripts ,I need to invoke these Webscripts in different Application remotely...
There is no documentation that I know of at the present time that documents all web scripts that expect JSON to be posted along with a schema that defines the expected JSON. Honestly, we haven't done a good job identifying which out-of-the-box URLs are actually public. Some are there just for the Share application's use and could change without warning.
With that said, you can go to http://localhost:8080/alfresco/s/index and see a list of web scripts. And if you drill down into the web script (click on the web script's ID), you can see the source code for the JavaScript controller or, if the web script is implemented in Java, you can see the full class name that implements it. You can then inspect the source to see what it is expecting.
Another way to do it is to use Firebug or your browser's developer console to watch the network calls that go from your browser to the repository tier. Many of these calls include JSON being posted to repository tier web scripts.
Assuming you're referring to getting a webscript to respond with a json, there are a few steps.
1. Create a webscript, and possibly set json the default format (in the webscript definition file, i.e. mywebscript.get.desc.xml, add a tag
<format default="json">argument</format>
Create a JSON controller too, ie. mywebscript.get.json.js. This script can do two things:
a) get json parameter (if you sent a json in): if (json.has('myparam')) myVar = json.get('myparam');
b) provide some data to the model, ie. model.docs = companyhome.children
Your webscript also needs to format this json for json response, i.e. mywebscript.get.json.ftl would look something like this:
{ "docs": [
<#list docs as doc> {
"name": "${doc.name}",
"prop": "${doc.properties["mymodel:myprop"]}"
} <#if doc_has_next>,</#if>
</#list>
]
}

Binding JSON to nested Grails Domain Objects

I'm developing a RESTful interface which is used to provide JSON data for a JavaScript application.
On the server side I use Grails 1.3.7 and use GORM Domain Objects for persistence. I implemented a custom JSON Marshaller to support marshalling the nested domain objects
Here are sample domain objects:
class SampleDomain {
static mapping = { nest2 cascade: 'all' }
String someString
SampleDomainNested nest2
}
and
class SampleDomainNested {
String someField
}
The SampleDomain resource is published under the URL /rs/sample/ so /rs/sample/1 points to the SampleDomain object with ID 1
When I render the resource using my custom json marshaller (GET on /rs/sample/1), I get the following data:
{
"someString" : "somevalue1",
"nest2" : {
"someField" : "someothervalue"
}
}
which is exactly what I want.
Now comes the problem: I try to send the same data to the resource /rs/sample/1 via PUT.
To bind the json data to the Domain Object, the controller handling the request calls def domain = SampleDomain.get(id) and domain.properties = data where data is the unmarshalled object.
The binding for the "someString" field is working just fine, but the nested object is not populated using the nested data so I get an error that the property "nest2" is null, which is not allowed.
I already tried implementing a custom PropertyEditorSupport as well as a StructuredPropertyEditor and register the editor for the class.
Strangely, the editor only gets called when I supply non-nested values. So when I send the following to the server via PUT (which doesn't make any sense ;) )
{
"someString" : "somevalue1",
"nest2" : "test"
}
at least the property editor gets called.
I looked at the code of the GrailsDataBinder. I found out that setting properties of an association seems to work by specifying the path of the association instead of providing a map, so the following works as well:
{
"someString" : "somevalue1",
"nest2.somefield" : "someothervalue"
}
but this doesn't help me since I don't want to implement a custom JavaScript to JSON object serializer.
Is it possible to use Grails data binding using nested maps? Or do I really heave to implement that by hand for each domain class?
Thanks a lot,
Martin
Since this question got upvoted several times I would like to share what I did in the end:
Since I had some more requirements to be implemented like security etc. I implemented a service layer which hides the domain objects from the controllers. I introduced a "dynamic DTO layer" which translates Domain Objects to Groovy Maps which can be serialized easily using the standard serializers and which implements the updates manually. All the semi-automatic/meta-programming/command pattern/... based solutions I tried to implement failed at some point, mostly resulting in strange GORM errors or a lot of configuration code (and a lot of frustration). The update and serialization methods for the DTOs are fairly straightforward and could be implemented very quickly. It does not introduce a lot of duplicate code as well since you have to specify how your domain objects are serialized anyway if you don't want to publish your internal domain object structure. Maybe it's not the most elegant solution but it was the only solution which really worked for me. It also allows me to implement batch updates since the update logic is not connected to the http requests any more.
However I must say that I don't think that grails is the appropriate tech stack best suited for this kind of application, since it makes your application very heavy-weight and inflexbile. My experience is that once you start doing things which are not supported by the framework by default, it starts getting messy. Furthermore, I don't like the fact that the "repository" layer in grails essentially only exists as a part of the domain objects which introduced a lot of problems and resulted in several "proxy services" emulating a repository layer. If you start building an application using a json rest interface, I would suggest to either go for a very light-weight technology like node.js or, if you want to/have to stick to a java based stack, use standard spring framework + spring mvc + spring data with a nice and clean dto layer (this is what I've migrated to and it works like a charm). You don't have to write a lot of boilerplate code and you are completely in control of what's actually happening. Furthermore you get strong typing which increases developer productivity as well as maintainability and which legitimates the additional LOCs. And of course strong typing means strong tooling!
I started writing a blog entry describing the architecture I came up with (with a sample project of course), however I don't have a lot of time right now to finish it. When it's done I'm going to link to it here for reference.
Hope this can serve as inspiration for people experiencing similar problems.
Cheers!
It requires you to provide teh class name:
{ class:"SampleDomain", someString: "abc",
nest2: { class: "SampleDomainNested", someField:"def" }
}
I know, it requires different input that the output it produces.
As I mentioned in the comment earlier, you might be better off using the gson library.
Not sure why you wrote your own json marshaller, with xstream around.
See http://x-stream.github.io/json-tutorial.html
We have been very happy with xstream for our back end (grails based) services and this way you can render marshall in xml or json, or override the default marshalling for a specific object if you like.
Jettison seems to produce a more compact less human readable JSON and you can run into some library collision stuff, but the default internal json stream renderer is decent.
If you are going to publish the service to the public, you will want to take the time to return appropriate HTTP protocol responses for errors etc... ($.02)