StringEnumConverter works as an attribute but not globally - json.net

We are implementing a .NET Core 3.1 API and we are using Microsoft.AspNetCore.Mvc.NewtonsoftJson according to this doc. We are dealing with enums and we need the string representation instead of the integers. We are doing it using the JsonConverter attribute like this:
[JsonProperty("region")]
[JsonConverter(typeof(StringEnumConverter))]
public Region Region { get; set; }
We are trying to do it globally from the Startup.cs like below :
services.AddControllers().AddNewtonsoftJson(opts => opts.SerializerSettings.Converters.Add(new StringEnumConverter()));
If we do that, the Cosmos DB is complaining with
"PartitionKey extracted from document doesn't match the one specified in the header"
So we tried removing all the attributes except by the region one. All the other enums that don't have the attribute are stored as strings correctly, but the region still needs the attribute to work. Any clue why is this happening and how to solve it?

In netcore 3.1 or higher, you can use JsonStringEnumConverter:
var options = new JsonSerializerOptions
{
Converters = { new JsonStringEnumConverter() },
//other options
};
Try Example online

Related

Swashbuckle use format identifier via XML comment in .NET application

I'm trying to get the format identifier printed on the Swagger UI which is stated on their homepage. In the auto-generated json file it should look like in this example:
The way of how I'd like to achieve that is via xml comments in my view model class. This works well for tags like example, summary etc., but there is no tag like format. It would be important for me to state that the string we are awaiting here in the API must be in a certain format.
A similar question has been asked here, but there hasn't been an answer for the format identifier.
How can I achieve this?
Versions used: .NET 7 and Swashbuckle v 6.4.0.
My view model looks like that:
public class MeasurementViewModel {
/// <example>20.01.2003</example>
/// <format>dd.mm.yyyy</format> <-- this is what I would expect but doesn't have any effect
[JsonProperty("patient_birthdate")] public string? PatientDateOfBirth { get; set; }
}
Found a solution thanks to that answer.
I added the additional package "Swashbuckle.AspNetCore.Annotations" via NuGet and in my Startup.cs where I configure the Swagger generation I enable the annotations:
services.AddSwaggerGen(c =>
...
c.EnableAnnotations();
}
In my ViewModel I can now use the following annotation:
/// <example>20.01.2002</example>
[JsonProperty("patient_birthdate"), SwaggerSchema(Format = "dd.mm.yyyy")] public string? PatientDateOfBirth { get; set; }
.. which results in a beautiful documentation:

CamelCase property names with NJsonSchema C# CodeGeneration

does anybody know a way to configure NJsonSchema to use CamelCase property naming durching code generation? I've a JSON schema with property names like message_id which lead to C# property name 'Message_id' where i.e. 'MessageId' whould be a more C#-like way.
With an attribute like '[JsonProperty("message_id"]' it would be no problem to specified the connection between the different names.
So, you asked about code generation. I was having trouble with the schema it generated not matching what was getting sent to my Angular app. So, while this isn't exactly what you were looking for, perhaps it helps you find an answer (maybe?).
To generate the schema with the camel case property names, I'm setting the Default Property Name Handling to CamelCase, but this is using the deprecated call to set these settings directly. There should be some way to use the SerializerSettings directly, but I wasn't quite able to make that work. This isn't production code for me, so it will do.
internal class SchemaFileBuilder<T>
{
public static void CreateSchemaFile()
{
CreateSchemaFile(typeof(T).Name);
}
public static void CreateSchemaFile(string fileName)
{
JsonSchemaGeneratorSettings settings = new JsonSchemaGeneratorSettings();
settings.DefaultPropertyNameHandling = PropertyNameHandling.CamelCase;
var schema = NJsonSchema.JsonSchema.FromType<T>(settings);
var json = schema.ToJson();
Directory.CreateDirectory("Schemas");
File.WriteAllText($"Schemas\\{fileName}.schema.json", json);
}
}
I set this up as a generic function so I could pass multiple schemas in to either createSchemaFile functions. Here's are some example calls which would generate a Person.schema.json file and a Persons.schema.json file:
SchemaFileBuilder<Person>.CreateSchemaFile();
SchemaFileBuilder<Dictionary<string, Person>>.CreateSchemaFile("Persons");

.net core MEF 2 NonShared Creation Policy

I am switching over to .net core and attempting to migrate my legacy framework MEF code to the new Microsoft Composition (MEF 2) (Microsoft.Composition 1.0.31).
We have several classes whose creation policy is "NonShared". I'm getting stuck on how I should apply the following attribute using MEF 2 with .net core:
[PartCreationPolicy(CreationPolicy.NonShared)]
Does anyone know what the .net core MEF 2 equivalent is for setting the above attribute to 'NonShared'?
Since only MEF 2 has been ported to .NET Core we only have acces to types within System.Composition and not those in System.ComponentModel.Composition. Therefore it is not possible to set that attribute just the way you used to do with MEF 1.
You can set the part creation policy for each export defined through the API though.
Since we're near Halloween, let's supouse we have these classes:
abstract class Monster { }
class It : Monster { }
class Zombie : Monster { }
class Wife : Monster { }
In MEF 2 you need to create a ConventionBuilder in order to defeine your exports, like this:
var rules = new ConventionBuilder();
rules.ForTypesDerivedFrom<Monster>()
.Export<Monster>();
The interesting part here is that by default a Non Shared creation policy is enforced, so no need for the attribute. Let's test it:
var config = new ContainerConfiguration()
.WithAssemblies(new[]{ typeof(Monster).GetTypeInfo().Assembly}, rules);
var container = config.CreateContainer();
var monsterA = container.GetExports<Monster>().First();
var monsterB = container.GetExports<Monster>().First();
Console.WriteLine(monsterA == monsterB);
Now, since by default we do not enforce sharing in our exports this will write to the console False.
In order to enforce sharing we simply add .Shared() to the methods chain after .Export like this:
rules.ForTypesDerivedFrom<Monster>()
.Export<Monster>()
.Shared();
And if we run the test again we will get True since now both instances are pointing to the same reference.
For composing parts you would do something like this:
class TerrorContainer
{
[ImportMany]
public IEnumerable<Monster> Monsters { get; set; }
}
And wherever you are composing you would write:
var terrorContainer = new TerrorContainer();
container.SatisfyImports(terrorContainer);
Hope this helps!

Dynamic data-driven website localization

I have a website that reads some of its content from a database, I need this website in both languages, English and Arabic.
the needed content is duplicated in the database in both languages. lets say I have a En_Name and Ar_Name columns in my database.
and for example for the Arabic version of the website a link will display a text from Ar_Name , and with the English one it should display the text from the En_Name.
for the static content in my website I think it is a good idea to use the ASP.NET default localization using (.resx files). but what I don't know is how to do the localization for the dynamic section of the website.
So, how can I make the same hyperlink read once from the Ar_Name field, and then from the En_Name based on the users choice (Localization)?
There are many ways to accomplish this. You've not mentioned which database technology you are using, so my example is with Entity Framework. You may need to customise this to your own situation.
Something similar may be possible with LinqToSql or other ORMs. If you are using something else entirely, then the key is to have a central class that you pass something consistent to (hence the interface) that does the translation.
For example, if I was using Entity Framework, every table in the database that had these two fields I'd add an interface that exposes those fields. Then I'd have a helper class with a method that took any entity with that interface and checked the current localisation and return the correct version of the text.
public interface IBilingualEntity
{
// Defines a consistent interface that indicates which language version
// each thing is in.
string Ar_Name { get; }
string En_Name { get; }
}
public partial MyEntity : IBilingualEntity
{
// This is a class generate by Entity Framework. But it could
// be anything really if you are using some other framework.
//
// Nothing to do here as the other side of the partial
// should already implement the interface with the code
// generated from Entity Framework. If not, implement the
// interface and return the correct language version in
// the property.
}
// This is the helper that works out which language version to use.
public class BilingualHelper
{
public string GetName(IBilingualEntity entity)
{
// NOTE: You may have to strip away the region part of the name
// but off the top of my head I can't remember the format.
// If you are using something else to store the culture you'll
// have to reference that instead.
var cultureName = Thread.CurrentThread.CurrentUICulture.Name;
if (cultureName == "ar")
return entity.Ar_Name;
return entity.En_Name;
}
}

Unity 2 trouble referencing RegisterInstance using InjectonProperty

I have the following code:
Unity Container:
Settings settings = CreateSettings();
container.RegisterInstance(settings)
.RegisterType<MyHttpHandler>(new InjectionProperty[]
{
// How do I tell Unity to inject my settings created above?
new InjectionProperty("Settings", new ResolvedParameter(????))
});
MyHttpHandler:
public class MyHttpHandler: IHttpHandler
{
public MyHttpHandler()
{
IoC.Inject(this);
}
public Settings Settings
{
get;
set;
}
}
How do I tell Unity to inject the settings? This works just fine with interfaces but not sure how to proceed here.
Any help is appreciated.
It just goes off the type. You've registered an instance for the Settings class, so you just need to tell it to inject that type:
container.RegisterInstance(settings)
.RegisterType<MyHttpHandler>(
new InjectionProperty("Settings", new ResolvedParameter<Settings>());
(Note that you don't need the extra array, RegisterType takes a variable parameter list.)
Since this is a common requirement, there are shorthands you can use. First off, if you're resolving a dependency and you just need the default (non-named) registration, you don't need to use ResovledParameter, you can just pass the type object:
container.RegisterType(settings)
.RegisterType<MyHttpHandler>(
new InjectionProperty("Settings", typeof(Settings));
But, we can also go simpler than that. If you're using the default for a property based on the type, you don't need to pass the value at all - the container will simply use the type of the property. So you can just say:
container.RegisterType(settings)
.RegisterType<MyHttpHandler>(
new InjectionProperty("Settings"));
and the container will figure it out.

Resources