Content negotiation: how to remove JSON as a supported format? - c#

I'm implementing a web service in ASP.NET Core 2.1 based on a specification that exclusively supports XML. Therefore, the content negotiation process must return a XML document or respond with an error. Unfortunately ASP.NET Core 2.1 supports JSON by default, and by default the content negotiation process always succeeds if a request is made with Accept: application/json.
Does anyone know if it's possible to configure an ASP.NET Core project so that the content negotiation process throws an error if any media type other than XML is set?

Sorry if I am late to the party. This works for me:
services.AddMvc(options =>
{
options.OutputFormatters.RemoveType(typeof(JsonOutputFormatter));
options.InputFormatters.RemoveType(typeof(JsonInputFormatter));
options.ReturnHttpNotAcceptable = true;
})
.AddXmlSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

Use MVC input and output formatters:
services.AddMvc(configure =>
{
// remove JSON formatter
var outputFormatters = configure.OutputFormatters;
var jsonOutputFormatter = outputFormatters.First(f => f is JsonOutputFormatter);
outputFormatters.Remove(jsonOutputFormatter);
var inputFormatters = configure.InputFormatters;
var jsonInputFormatter = inputFormatters.First(f => f is JsonInputFormatter);
inputFormatters.Remove(jsonInputFormatter);
}).AddXmlSerializerFormatters()

Related

ASP.NET Core OData Atompub formatter

I am trying to format an ASP.NET Core OData response to Atom+xml to retain backward compatibility.
Here is the code I tried but I still have no luck. Is there a way I can format response in atom+xml ?
builder.services.AddMvc().AddMvcOptions (o =>{
o.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
});
The ASP.NET Core code is clearing the headers in the call and adding the new header value and asp.net code is format is getting changed to atom xml.
this.Request.Headers.Clear()
this.Request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/atom+xml")

.NET 6 Core C# -building a rest webservice with binary multipart/form-data upload returning json

I'm trying to build a .NET 6.0 C# rest webservice, receiving a string and three files, one of them a binary image.
The files are not saved, just checked/evaluated and the result is returned in a json structure.
The string can be an url path parameter.
The webservice should run on windows and in a linux docker container.
It is called only from C# clients and is not accessible from the internet.
So the curl looks like that:
curl -X POST -H "Content-Type: multipart/form-data; boundary=------------------------d74496d66958873e" \
--data-binary "#KeyValue.json" \
--data-binary "#Text.txt" \
--data-binary "#Image.tif" \
http://localhost:5000/check/CheckType01
I tried an approach starting with the Visual Studio 2022 Project "ASP.NET Core-Web-Api"
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/check/{checkType}", (string checkType, HttpContext ctx) =>
{
ctx.Request.EnableBuffering();
ctx.Request.Body.Position = 0;
var reader = new StreamReader(ctx.Request.Body);
var body = Task.Run(async () => await reader.ReadToEndAsync().ConfigureAwait(false));
Console.WriteLine("Parameter: " + checkType);
Console.WriteLine("MultiPart: " + body.Result);
return new { check = "Ok", confidence = 100 }; ;
});
app.Run();
With the three files containing "KeyValueContent", "TextContent" and "ImageContent", this code partially works:
Output:
Parameter: CheckType01
MultiPart: KeyValueContent&TextContent&ImageContent
Return:
{"check":"Ok","confidence":100}
But this can't be the correct approach to solve this, I assume.
The files are separated by an '&' and not by the boundary from the header, so it is not possible to separate them.
Somehow the framework should do the separation instead.
The multipart body is a string and not a byte array.
The webservice is blocked during the body read.
I have read a lot about how to upload files in ASP.Net Core, about webapi-controllers, model view controllers, annotations, minimal API or not and so on,
but I'm still not sure what the correct way to go is, I couldn't find a working minimal example.
I would like to know:
which Visual Studio 2022 starting project type should I use?
what framework to use (minimal api, api with controllers, [ApiController] attribute ...)?
the necessary attributes for POST - binary multipart/form-data?
Besides fixing the curl request to read multiple file you can use IFormFileCollection returned by HttpRequest.Form.Files (inject HttpRequest as handler parameter or use ctx.Request to access it).
Also note that Task.Run not only pointless here but harmful, just mark the lambda handler as async:
app.MapPost("/check/{checkType}", async (string checkType, HttpRequest request) =>
{
var formFileCollection = request.Form.Files;
foreach (var formFile in request.Form.Files)
{
using var openReadStream = new StreamReader(formFile.OpenReadStream());
var readToEndAsync = await openReadStream.ReadToEndAsync();
// do something here
}
...
return new { check = "Ok", confidence = 100 };
});
I checked your codes,you want to post mutiple files at one time,but --data-binary allows you post one file per request,you could try with -F to post serverl files and access the files from HttpContext.Request.Form.
You could try with postman,and you will find what's wrong immediately:

Self Referencing loop detected for property 'manifestmodule' | While adding certificate to GET request

I have below code for GET request -
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method="GET";
request.Timeout=300000;
X509Certificate2 certificate= new X509Certificate2(path,password);
request.ClientCertificates.Add(certificate);
While adding certificate I am getting Error -
Self Referencing loop detected for property 'manifestmodule' with type 'System.Reflection.RuntimeModule' Path 'Exception.Targetsite.Module.Assembly'
I searched on internet with respect to this error , but its general occurance is while using / parsing json which I am nowhere doing in my code.
I am using .NET core - 2.1.1
As you already found out this is an error coming from the Newtonsoft JsonSerializer. I think what's happening is that inside your API an exception is occurring, which is then passed to Newtonsoft to serialize to JSON so it can be returned as a response. Your options are either to fix this exception or disable reference loop detection mechanism.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
}

How to set default content-type to Json with servicestack serializer

I want if client did not provide content-type in calling web api, in server side set that to application/json, I found this :
SetConfig(new HostConfig {
PreferredContentTypes = new []{ MimeTypes.Json }.ToList(),
});
in this link
but when I write this code compiler dont recognize Setconfig.
I set servicestack as default serializer in web api
EDIT:
I followed this instruction for replacing servicestack.text instead of default serializer of web api.
I dont know where should I put this config, beacuase when I put that in ServiceStackTextFormatter constructor compiler does not recognize SetConfig.
Use Config.DefaultContentType e.g:
SetConfig(new HostConfig {
DefaultContentType = MimeTypes.Json
});

Authorization bearer token with NEST elasticsearch and C#

I've got a problem while trying to connect to an elasticsearch API.
The API expect an bearer token, but the NEST lybrary only provides a basic authentication and I've got to pass a custom header as well. So, did anybody have to face this problem?? How to pass custom headers?!
Thanks
You can add headers that should be added to all requests on ConnectionSettings
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings = new ConnectionSettings(pool)
.GlobalHeaders(new NameValueCollection
{
{ "Authorization", "Bearer fnoi3nfion3fn00jr0j1r0" }
});
var client = new ElasticClient(connectionSettings);
Actually I was getting a mistaken concept. Actually I'm interacting with an API wich encapsolate the elasticsearch and just use the elasticsearch query sintax, so I didn't need to use NEST, the elasticsear package, to connect with it. And I just got to interact it with a simple http call.
Anyway, thanks Russ
you can add any header to your request:
req.Headers.Add("CustomeKey", CustomeData);

Categories