Use Newtonsoft.Json in isolated-process Azure Functions in .Net 6.0 - c#

I currently use Azure App Configuration to store all the config data. When i read the data, i would like to use Newtonsoft.Json instead of the default System.Text.Json to correctly transform my data to custom types.
Unfortunately, i cannot find a way to tell the HostBuilder in the Program.cs file to use Newtonsoft.Json instead of the System.Text.Json. All my converters are written using Newtonsoft.Json and i really would like to not migrate them all to System.Text.Json.
As an example:
public Enum SampleEnum
{
[Description("Sample")] SampleAbc
}
public class SampleConfig
{
public SampleEnum ConfigEnumA {get; set;}
}
// configuration is the IConfiguration object from Microsoft.Extensions.Configuration
var sampleConfig = new SampleConfig()
configuration.GetSection("section").bind(sampleConfig);
The Description value Sample is what comes from Azure App Configuration as a string and ideally my current Newtonsoft.Json converters should transform it to SampleAbc enum value when binding the object SampleConfig. This allows me to be type safe in code.
This means that ConfigEnumA should have a value of SampleEnum.SampleAbc instead of Sample
I have already tried using but it did not work although i am working with HTTP Triggers and not a web application
var hostBuilder = new HostBuilder().ConfigureServices(services =>
{
services.AddMvc().AddNewtonsoftJson(options =>
{
options.SerializerSettings.Converters = <my-custom-converters>
}
)
});
if there is no way to use Newtonsoft.Json in Azure Function apps that arent Mvc applications, then can someone help with achieving the same behaviour with System.Text.Json?
Thanks for the help.
Cheers.

AFAIK, Services.AddMvcCore().AddJsonOptions(...) is for System.Text.Json whereas builder.services.AddMvcCore().AddNewtonsoftJson(options => can be used for Newtonsoft.json.
If you want to use Newtonsoft, add Microsoft.AspNetCore.Mvc.NewtonsoftJson as a dependency from NuGet which contains AddNewtonsoftJson() extension.
dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson --version 7.0.0
Thanks to #Nate1zn, I found how to use Newtonsoft.Json in Azure Function apps, you can add a startup to your function project as below:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection
[assembly: FunctionsStartup(typeof(NewtonsoftjsonfunctionApp.functionsample))]
namespace NewtonsoftjsonfunctionApp
public class functionsample : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.services.AddMvcCore().AddNewtonsoftJson(options =>
{
options.SerializerSettings.//json settings
}
}
}

Related

Console Application throwing a CS1069 Error when trying to use settings. C# .NET5 [duplicate]

I've got a method that reads settings from my config file like this:
var value = ConfigurationManager.AppSettings[key];
It compiles fine when targeting .NET Standard 2.0 only.
Now I need multiple targets, so I updated my project file with:
<TargetFrameworks>netcoreapp2.0;net461;netstandard2.0</TargetFrameworks>
But now, the compilation fails for netcoreapp2.0 with the following error message:
Error CS0103 The name 'ConfigurationManager' does not exist in the current context (netcoreapp2.0)
Separately, I created a new .NET Core 2.0 console application (only targeting .NET Core 2.0 this time), but likewise there seems to be no ConfigurationManager under the namespace System.Configuration.
I'm quite confused because it's available under .NET Standard 2.0, so I would expect it to be available in .NET Core 2.0, as .NET Core 2.0 is .NET Standard 2.0 compliant.
What am I missing?
Yes, ConfigurationManager.AppSettings is available in .NET Core 2.0 after referencing NuGet package System.Configuration.ConfigurationManager.
Credits goes to #JeroenMostert for giving me the solution.
I installed System.Configuration.ConfigurationManager from Nuget into my .net core 2.2 application.
I then reference using System.Configuration;
Next, I changed
WebConfigurationManager.AppSettings
to ..
ConfigurationManager.AppSettings
So far I believe this is correct. 4.5.0 is typical with .net core 2.2
I have not had any issues with this.
Once you have the packages setup, you'll need to create either an app.config or web.config and add something like the following:
<configuration>
<appSettings>
<add key="key" value="value"/>
</appSettings>
</configuration>
The latest set of guidance is as follows: (from https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library#environment-variables)
Use:
System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
From the docs:
public static class EnvironmentVariablesExample
{
[FunctionName("GetEnvironmentVariables")]
public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
}
public static string GetEnvironmentVariable(string name)
{
return name + ": " +
System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
}
}
App settings can be read from environment variables both when developing locally and when running in Azure. When developing locally, app settings come from the Values collection in the local.settings.json file. In both environments, local and Azure, GetEnvironmentVariable("<app setting name>") retrieves the value of the named app setting. For instance, when you're running locally, "My Site Name" would be returned if your local.settings.json file contains { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } }.
The System.Configuration.ConfigurationManager.AppSettings property is an alternative API for getting app setting values, but we recommend that you use GetEnvironmentVariable as shown here.
I used below code example. Also this is so convenient way.
using Microsoft.Extensions.Configuration;
using System.IO;
namespace DemoWeppApp
{
public static class StaticConfigurationManager
{
public static IConfiguration AppSetting { get; }
static StaticConfigurationManager()
{
AppSetting = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
}
}
}
And then I can use easly in any static class like this
StaticConfigurationManager.AppSetting["conf_name"];
You can use Configuration to resolve this.
Ex (Startup.cs):
You can pass by DI to the controllers after this implementation.
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var microserviceName = Configuration["microserviceName"];
services.AddSingleton(Configuration);
...
}
I know it's a bit too late, but maybe someone is looking for easy way to access appsettings in .net core app.
in API constructor add the following:
public class TargetClassController : ControllerBase
{
private readonly IConfiguration _config;
public TargetClassController(IConfiguration config)
{
_config = config;
}
[HttpGet("{id:int}")]
public async Task<ActionResult<DTOResponse>> Get(int id)
{
var config = _config["YourKeySection:key"];
}
}

I set default JsonSerializer to Utf8Json

Using c# 8 and .netcore 3.1.
I've read HERE that Utf8Json library process json serialization and deserialization faster that NewtonsoftJson.
We've recently upgraded our servers code from .netcore 2.2 to 3.1 mostly for performance improvements.
Thus, it is reasonable that we also use the best serialization library.
So my questions are:
In Startup.cs there is this
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
And I want it to use a different library, so I found out that I can use .AddJsonOptions but I cannot figure out how to set default serializer, even after using my google-fu skills.
Since I've been using [JsonProperty("<name>")] everywhere in my code in order to reduce json string size, do I need to format everything for the new serializer or is there a way to make him consider the property attribute ? (attribute is Newtonsoft)
Thanks.
#Ori you can use Utf8json in net core 3.1 projects.
Use
[DataMember(Name = "RoleType")]
public string Role_Type { get; set; }
Instead of
[JsonProperty("<name>")]
To use Utf8json formatters in Asp.Net core you need add the formatters as mentioned below.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews()
// Add Utf8Json formatters
.AddMvcOptions(option =>
{
option.OutputFormatters.Clear();
option.OutputFormatters.Add(new JsonOutputFormatter (StandardResolver.Default));
option.InputFormatters.Clear();
option.InputFormatters.Add(new JsonInputFormatter ());
});
}
You can also refer below link for the formatters.
https://github.com/neuecc/Utf8Json/blob/master/src/Utf8Json.AspNetCoreMvcFormatter/Formatter.cs
I am using utf8json and its working great for us.

HttpClient has no definition for GetJsonAsync

I'm currently tapping into Blazor, and want to move my code so it's more readable and reusable. In my razor component, the Method works flawlessly - in a Class, it doesn't.
In my component, I can simply use this:
response = await Http.GetJsonAsync<T>(Uri);
In my Class, Visual Studio complains that System.Net.Http's HttpClient contains no definition for GetJsonAsync - but I'm getting a typed response, so I want to deserialize it properly.
As of preview 8, you need:
<PackageReference Include="Microsoft.AspNetCore.Blazor.HttpClient" Version="3.0.0-preview8.19405.7" PrivateAssets="all" />
NOTE: This was correct at the time, but as of Blazor version 3.1.0 this may have changed again so that now you most likely want the System.Net.Http.Json package. See the answer from #JohnB below.
Great question. And I'm assuming Darrell's answer (and the others) was 100% correct as of version 3.0.0 (Blazor WebAssembly preview).
However, as for version 3.1.301 I think the package location has changed.
Currently, the namespace is: System.Net.Http.Json
That will give you access to: HttpClientJsonExtensions
A. If you want to put that code into a separate class within your Blazor WebAssembly project, all you need is to put this at the top of your class file:
using System.Net.Http; // for HttpClient
using System.Net.Http.Json; // for HttpClientJsonExtensions
B. If you want to put that class into a separate project (.NET Core library) then you need to add the NuGet package also:
NuGet package: System.Net.Http.Json
Then you can use it in your class like in the example below. Obviously these extension methods are doing serialization, but what's interesting is that the package doesn't depend on Newtonsoft.Json because it uses the new System.Text.Json instead.
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace MyClassLibrary
{
public class MyClass
{
public async Task MyMethod()
{
string baseAddress = "http://localhost:57012/";
var httpClient = new HttpClient() { BaseAddress = new Uri(baseAddress) };
var myPocos = await httpClient.GetFromJsonAsync<MyPoco[]>("api/mypocos");
foreach (var myPoco in myPocos)
Console.WriteLine($"Id: {myPoco.Id}, Name: {myPoco.Name}");
}
}
public class MyPoco
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Article about System.text.json VS Newtonsoft.json versus Utf8Json.
As of today the correct answer is:
using System.Net.Http.Json
and
GetFromJsonAsync()
Just download Microsoft.AspNetCore.Blazor.HttpClient package.
It's worth noting that "include prerelease" must be checked in order to find this package. I just spent a half hour getting fairly angry that the package wasn't found and scouring google to find out why!
For Blazor, there is an extension class (Microsoft.AspNetCore.Blazor.HttpClientJsonExtensions) available to get you the same extension methods.
Ref: https://learn-blazor.com/architecture/rest-api/

JSON configuration properties containing dashes/hyphens in .NET Core

I have a .NET Core 2.0 project using a JSON configuration file, via the Microsoft.Extensions.Configuration.Json provider.
This application is a utility application to support another application that I do not control.
To keep consistency with that other application's configuration file format/style, multi-word setting keys use dashes between words.
Example JSON:
{
"multi-word-setting": "setting value"
}
Example settings class:
public class AppSettings
{
// Pascal casing, as is typical in C#
public string MultiWordSetting { get; set; }
}
Example application code:
class Program
{
private static void Main ( string[ ] args )
{
IConfigurationBuilder configBuilder = new ConfigurationBuilder( ).SetBasePath( Environment.CurrentDirectory ).AddJsonFile( "my-settings.json", true, true );
IConfigurationRoot configRoot = configBuilder.Build( );
AppSettings config = new AppSettings( );
configRoot.Bind( config );
Console.WriteLine( config.MultiWordSetting );
}
}
However, given that hyphens are illegal in identifiers in C#, how can I follow typical C# naming conventions while also following the defined style of the application I am supporting?
I know I can use Newtonsoft and its JsonPropertyAttribute to just manually deal with the json data, but I'd prefer to make this work without "external" libraries, if possible. Besides, JSON.Net is over 20x larger, and the configuration libraries handle other stuff, such as automatic reloading, binding, merging, and optional files.
I've tried adding DataMember attributes to the properties of my class, to indicate the name of the json property, but that doesn't do the trick.
Is there a way to do this, with the .NET Core Microsoft.Extensions.Configuration.Json provider?
While I was writing the question, I decided to dive into the .net core source and found that no, it is not possible to do what I wanted to do.
So, I decided to fix it and, pending the outcome of ASP.Net Configuration Pull Request 775, it may be possible in a future version of .net core. Please feel free to review/scrutinize that pull request.
Until then, a relatively simple workaround is to bind the configuration as normal and then manually access any unsupported settings via the ConfigurationRoot object's indexer.
Note that, if you're using the automatic reload feature, you'd have to manually handle setting the property on reload, too.

Is ConfigurationManager.AppSettings available in .NET Core 2.0?

I've got a method that reads settings from my config file like this:
var value = ConfigurationManager.AppSettings[key];
It compiles fine when targeting .NET Standard 2.0 only.
Now I need multiple targets, so I updated my project file with:
<TargetFrameworks>netcoreapp2.0;net461;netstandard2.0</TargetFrameworks>
But now, the compilation fails for netcoreapp2.0 with the following error message:
Error CS0103 The name 'ConfigurationManager' does not exist in the current context (netcoreapp2.0)
Separately, I created a new .NET Core 2.0 console application (only targeting .NET Core 2.0 this time), but likewise there seems to be no ConfigurationManager under the namespace System.Configuration.
I'm quite confused because it's available under .NET Standard 2.0, so I would expect it to be available in .NET Core 2.0, as .NET Core 2.0 is .NET Standard 2.0 compliant.
What am I missing?
Yes, ConfigurationManager.AppSettings is available in .NET Core 2.0 after referencing NuGet package System.Configuration.ConfigurationManager.
Credits goes to #JeroenMostert for giving me the solution.
I installed System.Configuration.ConfigurationManager from Nuget into my .net core 2.2 application.
I then reference using System.Configuration;
Next, I changed
WebConfigurationManager.AppSettings
to ..
ConfigurationManager.AppSettings
So far I believe this is correct. 4.5.0 is typical with .net core 2.2
I have not had any issues with this.
Once you have the packages setup, you'll need to create either an app.config or web.config and add something like the following:
<configuration>
<appSettings>
<add key="key" value="value"/>
</appSettings>
</configuration>
The latest set of guidance is as follows: (from https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-class-library#environment-variables)
Use:
System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
From the docs:
public static class EnvironmentVariablesExample
{
[FunctionName("GetEnvironmentVariables")]
public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
}
public static string GetEnvironmentVariable(string name)
{
return name + ": " +
System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
}
}
App settings can be read from environment variables both when developing locally and when running in Azure. When developing locally, app settings come from the Values collection in the local.settings.json file. In both environments, local and Azure, GetEnvironmentVariable("<app setting name>") retrieves the value of the named app setting. For instance, when you're running locally, "My Site Name" would be returned if your local.settings.json file contains { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } }.
The System.Configuration.ConfigurationManager.AppSettings property is an alternative API for getting app setting values, but we recommend that you use GetEnvironmentVariable as shown here.
I used below code example. Also this is so convenient way.
using Microsoft.Extensions.Configuration;
using System.IO;
namespace DemoWeppApp
{
public static class StaticConfigurationManager
{
public static IConfiguration AppSetting { get; }
static StaticConfigurationManager()
{
AppSetting = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
}
}
}
And then I can use easly in any static class like this
StaticConfigurationManager.AppSetting["conf_name"];
You can use Configuration to resolve this.
Ex (Startup.cs):
You can pass by DI to the controllers after this implementation.
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var microserviceName = Configuration["microserviceName"];
services.AddSingleton(Configuration);
...
}
I know it's a bit too late, but maybe someone is looking for easy way to access appsettings in .net core app.
in API constructor add the following:
public class TargetClassController : ControllerBase
{
private readonly IConfiguration _config;
public TargetClassController(IConfiguration config)
{
_config = config;
}
[HttpGet("{id:int}")]
public async Task<ActionResult<DTOResponse>> Get(int id)
{
var config = _config["YourKeySection:key"];
}
}

Categories