XmlSerializerInputFormatter is obsolete - ASP.NET Core 2.1 - c#

I am using the following to accept XML serialized in my Core API App.
services.AddMvc(options =>
{
// allow xml format for input
options.InputFormatters.Add(new XmlSerializerInputFormatter());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
After updating to ASP.NET Core 2.1 I receive the following warning:
'XmlSerializerInputFormatter.XmlSerializerInputFormatter()' is obsolete: 'This constructor is obsolete and will be removed in a future version.'
What is the new way to handle this?

According to the source code, there's a constructor that has not been marked as Obsolete:
public XmlSerializerInputFormatter(MvcOptions options)
This constructor takes an instance of MvcOptions, so you can pass through your existing options argument:
services.AddMvc(options =>
{
// allow xml format for input
options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
}) ...
As of ASP.NET Core 3.0, this constructor is the only one available. Those that were marked obsolete have now been removed.

With .NET Core 2.2 or later XmlSerializerInputFormatter should be marked as deprecated.
Instead a of explicitly defining XML serializers as we did before, in the .NET Core 2.2 we can add them simply by calling AddXmlSerializerFormatters() method which will do the job now. Read here why it has been deprecated
Here is how you can do it.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config =>
{
config.RespectBrowserAcceptHeader = true;
config.ReturnHttpNotAcceptable = true;
config.OutputFormatters.Add(new CsvOutputFormatter());
}).AddXmlSerializerFormatters().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Related

Replace ASP.NET Core 3.1 JSON implementation system wide

Recently I have decided to go from ASP.NET Core 2.2 to ASP.NET Core 3.1 and did not anticipate all the breaking changes; nearly every part of my application broke as most parts rely on JSON.
To safeguard against future JSON related problems, would it be possible to create an interface, mimicking the current Json implementation and override the default behaviour.
Most of my code relies on these two methods:
Json.Serialize() // used in my razor
Json() // returns an IActionResult
Use case: a Razor Page : Json.Serialize Doc
<script>
var myModel = #Html.Raw(Json.Serialize(Model))
</script>
Use case: a Controller
public async Task<IActionResult> AjaxGetRoleDetails(int id)
{
return Json(await GetUserRoles(id));
}
Here are the methods that I would like, when the above methods are called respectively.
JsonConvert.SerializeObject() // override Json.Serialize
Content(JsonConvert.SerializeObject(), new MediaTypeHeaderValue("application/json")) // override Json()
How can override the system implementation, and call my own implementation
for now, and later easily revert to the system's implementation when ASP.NET settles on a JSON implementation.
The default JSON serializer for ASP.NET Core is now System.Text.Json
So you could migrate over to using it.
Or, if you want to continue using Newtonsoft.Json in ASP.NET Core 3.0 and above, you can update your Startup.ConfigureServices to call AddNewtonsoftJson.
If you require things just like before, for example, in ASP.NET Core 2.2 then you can use the default contract resolver. E.g.
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});

ShouldSerialize method is not triggered in .NET Core 3

I normally use ShouldSerialize to exclude properties that have no data such as array but now, it does not appear to be triggered when I'm only using JSON serializer in .NET Core 3. It was being triggered when using NewtonSoft but I've removed it from my project since it no longer appears to be required.
For example:
private ICollection<UserDto> _users;
public ICollection<UserDto> Users
{
get => this._users ?? (this._users = new HashSet<UserDto>());
set => this._users = value;
}
public bool ShouldSerializeUsers()
{
return this._users?.Count > 0;
}
Any ideas why ShouldSerializeUsers is not being triggered?
I've seen other answers where you can use:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddJsonOptions(options => {
options.SerializerSettings.NullValueHandling =
NullValueHandling.Ignore;
});
}
But I'd like to know if there is another way to handle this as I'm not using .AddMvc
Thanks.
The reason that your ShouldSerialize is not triggered in ASP.NET Core 3.0 is that, in this and subsequent versions of ASP.NET, a different JSON serializer is being used by default, namely System.Text.Json.JsonSerializer. See:
Try the new System.Text.Json APIs.
Breaking changes to Microsoft.AspNetCore.App in 3.0 #325.
The future of JSON in .NET Core 3.0 #90.
Unfortunately as of .NET Core 3.1 this serializer does not support the ShouldSerializeXXX() pattern; if it did it would be somewhere in JsonSerializer.Write.HandleObject.cs -- but it's not. The following issues track requests for conditional serialization:
.net core 3.0 system.text.json option for ignoring property at runtime like newstonsoft DefaultContractResolver #42043.
System.Text.Json option to ignore default values in serialization & deserialization #779.
To restore ShouldSerialize functionality, you can revert back to using Newtonsoft as shown in this answer to Where did IMvcBuilder AddJsonOptions go in .Net Core 3.0? by poke, and also Add Newtonsoft.Json-based JSON format support:
Install Microsoft.AspNetCore.Mvc.NewtonsoftJson.
Then call AddNewtonsoftJson() in Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddNewtonsoftJson();
}
It is possible in Net 5 to use conditional JsonIgnore. It does not give you full conditional option, but you can exclude null at least which I suppose is the most used case:
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? MyProperty { get; set; }
If one wants to allow for optional null in json, it is possible to use a custom Optional<T> struct that is similar to Nullable, like e.g. one from Roslyn. Then it's possible to have a value, null, or no field at all in the result JSON.

How to add Json Formatters to MvcCore?

I'm following the next tutorial of IdentityServer4 implementation for API , but I can't call the method AddJsonFormatters() to services.AddMvcCore().
I'm currently configuring the API from an empty template in ASP.NET Core 3.0.0
I have added NuGet package Microsoft.AspNetCore.Mvc.Formatters.Json with no results.
Also, I understand that using AddMvc() instead of AddMvcCore() would be a partial solution but I can't use AddAuthorization() on AddMvc()
//code extracted from the link
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
}
}
This is the error message I see above:
'IMvcCoreBuilder' does not contain a definition for
'AddJsonFormatters' and no accessible extension method
'AddJsonFormatters' accepting a first argument of type
'IMVCoreBuilder' could be found (are you using a missing directive or
an assembly reference?)
Is this the method? Should I send an MVCCoreBuilder? How do I do that? MvcJsonMvcCoreBuilderExtensions.AddJsonFormatters Method
When you call services.AddMvc() you get an IMvcBuilder.
if you want to add more output or input formatters, the IMvcBuilder has an extension method that you can call AddMvcOptions bellow you have an example of an XmlDataContractSerializerOutputFormatter that was added
mvcBuilder.AddMvcOptions(options =>
{
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options));
Mvc already has a JsonOutputFormatter ,so inside of the AddMvcOptions you can get it and also and add your own custom mediatypes if you need it.
var jsonOutputFormatter = options.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault();
if (jsonOutputFormatter != null)
{
jsonOutputFormatter.SupportedMediaTypes.Add(HttpMediaTypes.Vnd+json.all);
jsonOutputFormatter.SupportedMediaTypes.Add(HttpMediaTypes.ApplicationOctetStream);
}
As I understood, there is not class MvcJsonMvcCoreBuilderExtensions in .NET Core 3.0 yet.
Eventually I just added -f parameter when I was created the Api project:
dotnet new web -n Api -f netcoreapp2.2
instead of
dotnet new web -n Api
It makes the Api project for .NET Core 2.2 so you can read the tutorial.
I was having the same issue. I found that I was on the wrong tutorial for implementing it with the current versions of dotnet core. The comment made by -AnorZaken helped:
Check the tutorial again, it has been updated to NetCore3
Look at the top of the sidebar on the tutorial page. If it says "Release" under the IdentityServer4 title, that won't work.
There is a dropdown at the bottom of the sidebar where you can select "3.1" instead.
Use this:
If MVC
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver());
.....
.....
if it is API than use
services.AddControllersWithViews().AddNewton ......

Bypass default AuthorizeFilter in .NET Core 2.1

I recently updated my .NET Core app from 2.0 to 2.1.
I have an authorize filter that I add during startup as so:
var posBearerPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
.RequireAuthenticatedUser()
.AddRequirements(new POSBearerRequirement())
.Build();
services.AddMvc(options =>
{
options.Filters.Add(new BearerAuthorizeFilter(posBearerPolicy));
});
Within BearerAuthorizeFilter's OnAuthorizationAsync method, I have the following logic:
public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context.Filters.Count(f => f is AuthorizeFilter) > 1 || context.Filters.Any(f => f is AllowAnonymousFilter))
{
return Task.CompletedTask;
}
return base.OnAuthorizationAsync(context);
}
This works exactly as I want it to in .NET Core 2.0. I have a default authorization policy that applies to all of my controllers. If I want to override that policy, then I just add an [Authorize(NAME)] attribute to my controller. Within that OnAuthorizationAsync, it will detect multiple AuthorizeFilter attributes on the controller and then only apply the policies that I've overridden for that particular controller.
However, since updating to .NET Core 2.1, my posBearerPolicy above is -always- getting applied. I have an API controller with a custom attribute that inherits from AuthorizeAttribute that has its own policy defined and everything set up during startup.
Even when that
return Task.CompletedTask;
line gets hit, the framework is still applying my posBearerPolicy.
Does anyone know what I'm missing? What caused this to change in .NET Core 2.1? How should I re-write the OnAuthorizationAsync method to tell it to skip/bypass the policy if multiple AuthorizationFilters are present?

JSON properties now lower case on swap from ASP .Net Core 1.0.0-rc2-final to 1.0.0

I've just swapped our project from ASP .Net Core 1.0.0-rc2-final to 1.0.0. Our website and client have stopped working because of the capitalization of JSON properties. For example, this line of JavaScript now fails
for (var i = 0; i < collection.Items.length; i++){
because the controller now calls the array "items" instead of "Items". I have made no changes beyond installing the updated packages and editing the project.json file. I have not changed the C# model files which still capitalize their properties.
Why have the ASP.Net Core controllers started returning JSON with lower-cased properties? How do I go back to them honoring the case of the property names from the model?
MVC now serializes JSON with camel case names by default
Use this code to avoid camel case names by default
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
Source:
https://github.com/aspnet/Announcements/issues/194
In case you found this from Google and looking for a solution for Core 3.
Core 3 uses System.Text.Json, which by default does not preserve the case. As mentioned with this GitHub issue, setting the PropertyNamingPolicy to null will fix the problem.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddControllers()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
and if you don't want to change the global settings, for one action only it's like this:
return Json(obj, new JsonSerializerOptions { PropertyNamingPolicy = null });
You can change the behavior like this:
services
.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
See the announcement here: https://github.com/aspnet/Announcements/issues/194
For those who migrated to Core 3.1 and have Core MVC project can use following setup code in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddControllersWithViews().AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);
...
}
This will fix it in dotnet core 3 webapi, so that it doesn't change your property names at all, and you return to your client exactly what you intended to.
In Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddHttpClient();
}
For someone who does not want to set it globally, it is possible to use ContractResolver also to return as Json result:
public IActionResult MyMethod()
{
var obj = new {myValue = 1};
return Json(obj, new JsonSerializerSettings {ContractResolver = new DefaultContractResolver()});
}
For some one who is using ASP.net WEB API ( rather than ASP.NET Core).
Add this line in your WebApiConfig.
//Comment this jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();
Adding this as an answer here because this comes up first in google search for web api as well.
For ASP MVC Core 6 Web API , Add below code into Program.cs file will make sure JSON propreties name follow C# model properties name in right casing. No 3rd party package require
using Microsoft.AspNetCore.Mvc;
builder.Services.Configure<JsonOptions>(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
For Core 2.x versions, using this code you can avoid camel case names by default. You need to add following code inside the ConfigureServices method of Startup.cs file.
services.AddMvc()
.AddJsonOptions(o =>
{
if (o.SerializerSettings.ContractResolver != null)
{
var castedResolver = o.SerializerSettings.ContractResolver
as DefaultContractResolver;
castedResolver.NamingStrategy = null;
}
});
Recently had this issue with .Net6
The solution turned out to be that I needed to install
Microsoft.AspNetCore.Mvc.NewtonsoftJson 6.0.0.x (Note, use 7.x for .Net 7)
Found this out from Mason's post:
Microsoft.AspNetCore.Mvc.NewtonsoftJson 6.0.2 is not compatible with net5.0
Install
Microsoft.AspNetCore.Mvc.NewtonsoftJson
For .net 6 you should select this version: 6.0.13
and then go to Program.cs and configure it like this
builder.Services
.AddControllersWithViews()
.AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());

Categories

Resources