How to add Json Formatters to MvcCore? - c#

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 ......

Related

.Net6 Upgrade with OData v8, Broken DI

I have a WEB API running on.Net5 for a while with the OData package.
Recently I've started to undertake the upgrade for .Net6 work but OData compatibility is broken at first. I needed to upgrade the OData package as well from v7 to v8.
After the upgrade first, my package references were broken so I've changed them from;
"using Microsoft.AspNet.OData;"
to
"using Microsoft.AspNetCore.OData;"
Now that resolved many of the errors, but coming back to my OData Config, my
services.AddOData();
has started to throw the error of "IServiceCollection' does not contain a definition for 'AddOData' and the best extension method overload 'ODataMvcBuilderExtensions.AddOData(IMvcBuilder)' requires a receiver of type 'IMvcBuilder'"
After some research, I've changed that to AddControllers first "services.AddControllers().AddOData();" and now my config file is like this;
public static void SetupOData(this IServiceCollection services)
{
// OData Support
//services.AddOData();
services.AddControllers().AddOData();
// In order to make swagger work with OData
services.AddMvcCore(options =>
{
foreach (OutputFormatter outputFormatter in options.OutputFormatters.OfType<OutputFormatter>().Where(x => x.SupportedMediaTypes.Count == 0))
{
outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
foreach (InputFormatter inputFormatter in options.InputFormatters.OfType<InputFormatter>().Where(x => x.SupportedMediaTypes.Count == 0))
{
inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
});
}
However after adding Config to the Startup with
// OData
services.SetupOData();
and
app.UseEndpoints(endpointRouteBuilder =>
{
endpointRouteBuilder.MapControllers();
// OData configuration
endpointRouteBuilder.EnableDependencyInjection();
endpointRouteBuilder.Filter().Select().Count().OrderBy();
});
I am getting error on EnableDependencyInjection() "'IEndpointRouteBuilder' does not contain a definition for 'EnableDependencyInjection' and no accessible extension method 'EnableDependencyInjection' accepting a first argument of type 'IEndpointRouteBuilder' could be found (are you missing a using directive or an assembly reference?)
So my OData usage is taking the non-EDM route and tried to implement that as simple as possible. But now after the upgrade, I am completely confused and or blinded right now. Can you help me get through this?
So an update;
Changing the OData config worked for me;
Instead of adding Odata first;
services.AddOData();
I pulled it inside the MvcCore;
services.AddMvcCore(options =>
{
foreach (OutputFormatter outputFormat ......."odatatestxx-odata"));
}
}).AddOData();
And then instead of using DI on endpointRouteBuilder, just kept MapControllers as;
endpointRouteBuilder.MapControllers();

Swagger fails when using Microsoft.AspNetCore.OData v8.0.0-preview2

I am working on an ASP.NET Core 5 API project and I am using Microsoft.AspNetCore.OData v8.0.0-preview2.
If I use the out-of-box ASP Net Web application template, before I add OData, Swagger works just fine.
However, as soon as I add the following code;
services.AddOData(
option => option.AddModel("v1", GetV1EdmModel())
.Select()
.Expand()
.Filter()
.OrderBy()
.Count());
... to my Startup.cs --> ConfigureServices method and then try to navigate to the ../swagger endpoint the swagger page loads but displays the following error;
Failed to load API definition
Fetch error
unidentified /swapper/v1/swagger.json
Is swagger not yet supported in the Microsoft.AspNetCore.OData v8.0.0-preview2 release? Or am I missing something.
I have read through Sam Xu's blog posts; ASP.NET Core OData 8.0 Preview for .NET 5 and Routing in ASP.NET Core OData 8.0 Preview
But there was no mention of this issue.
Does anyone have a solution or a work around?
You can find the error message in the response:
System.InvalidOperationException: No media types found in 'Microsoft.AspNetCore.OData.Formatter.ODataOutputFormatter.SupportedMediaTypes'. Add at least one media type to the list of supported media types.
Try add below code after services.AddOData(...).
services.AddMvcCore(options =>
{
foreach (var outputFormatter in options.OutputFormatters.OfType<ODataOutputFormatter>().Where(_ => _.SupportedMediaTypes.Count == 0))
{
outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
foreach (var inputFormatter in options.InputFormatters.OfType<ODataInputFormatter>().Where(_ => _.SupportedMediaTypes.Count == 0))
{
inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/prs.odatatestxx-odata"));
}
});
And the same issue on github.

Scaffolding Entity Framework Controllers with Lamar

I have Lamar set up in my .NET Core 2 project:
public class Program
{
public static void Main(string[] args)
{
IWebHost webhost = CreateWebHostBuilder(args).Build();
//((Container)webhost.Services).GetInstance<IStart>().Run();
webhost.Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseLamar()
.UseStartup<Startup>();
}
...
public class Startup
{
...
public void ConfigureContainer(ServiceRegistry services)
{
services.Configure<Configuration.Auth>("auth", Configuration);
...
services.Scan(s =>
{
s.TheCallingAssembly();
s.WithDefaultConventions();
});
services.AddCors();
services.AddMvc()
.AddJsonOptions(o =>
{
o.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<Context>(options => options.UseSqlServer(Configuration.GetConnectionString("defaultConnection")));
}
}
However, when attempting to use Scaffold API Controller with actions, using Entity Framework I run into the following error:
There was an error running the selected code generator: 'No parameterless constructor defined for this object.'
Looking up this https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/?view=aspnetcore-2.2#update-main-method-in-programcs suggested that this can show up in ASP.NET Core 2 projects that attempt to still use the .NET 1.x structure.
I found a hacky work-around that I'll post below, which suggests that the scaffolding code generation may have an issue with Lamar. However, is there a better solution? Can you set up Lamar to be able to handle Entity Framework Code generation?
Considering EF was failing in the generate code section, I wondered if perhaps the issue was not the parameterless constructor (I'm pretty sure that whatever unnamed object it was referring to actually has one) but the issue with how the WebHost gets built when using Lamar.
The note in the Lamar documentation on integrating with ASP.NET Core states
Note! The Startup.ConfigureServices(ServiceRegistry) convention does not work as of ASP.Net Core 2.1. Use ConfigureContainer(ServiceRegistry) instead.
I was using that Lamar function in my Startup; however, if I changed it back to ConfigureContainer(IServiceCollection services) (and commented out the Lamar-specific functions, such as Scan), I found that I was able to scaffold the EF controller again.
So, at the moment, my workaround is to comment out Lamar before scaffolding, and then uncomment it back once I'm done. I suspect there may be a better solution though...

XmlSerializerInputFormatter is obsolete - ASP.NET Core 2.1

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);
}

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