Is there a way to escape colon in appsetting.json dictionary key in aspnetcore configuration? - asp.net-core

I have this provider dictionary in appsetting.json
"AppSettings": {
"Providers": {
"http://localhost:5001": "Provider1",
"http://localhost:5002": "Provider2"
},
"ArrayWorks": [
"http://localhost:5001",
"http://localhost:5002"
],
"SoDoesColonInDictionaryValue": {
"Provider1": "http://localhost:5001",
"Provider2": "http://localhost:5002"
}
}
And the following throw exception because there's colon in the dictionary key.
Configuration.GetSection("AppSettings").Get<AppSettings>()
However, colon works fine as dictionary value, or array, just not dictionary key.
I read colon has special meaning in config, but there seems no way to escape. Why?
Edit:
public class AppSettings
{
public string ApplicationName { get; set; }
public IDictionary<string, string> Providers { get; set; }
}
When debugging Configuration.GetSection("AppSettings"), you get this
Key AppSettings:Providers:http://localhost:5000
Value Provider1
It was intended to be something like this
Key AppSettings:Providers:http_//localhost_5000
But there seems no way to control how Configuration treat the :::

Edit:
According to aspnet/Configuration#792
Colons are reserved for special meaning in the keys, so they shouldn't
be used as part of normal key values.
This isn't supported and issue was closed.
Not yet, Until now there is no escape colon character, Accourding to Microsoft Asp.net repository on github, but there is an open issue with #782 on the github repository which move it to this backlog
As a workaround you can reverse the key with the value in appsetting:AppSettings and correct it in code like the below:
"AppSettings": {
"Providers": {
"Provider1":"http://localhost:5001",
"Provider2":"http://localhost:5002"
},
"ArrayWorks": [
"http://localhost:5001",
"http://localhost:5002"
],
"SoDoesColonInDictionaryValue": {
"Provider1": "http://localhost:5001",
"Provider2": "http://localhost:5002"
}
}
And in code make sure to reverse dictionary key and value as the below
var result = _configuration.GetSection("AppSettings:Providers")
.GetChildren().ToDictionary(i=>i.Value,i=>i.Key);
// result["http://localhost:5001"] return Provider1
// result["http://localhost:5002"] return Provider2

Related

How to make api call of string in flutter?

I am learning Flutter. This is the string that I need to call and I don't know how to call this type of string.
{
"Info":[
{
"c_type_id":"1",
"cleaning type":"Washroom Cleaning"
},
{
"c_type_id":"2",
"cleaning type":"Garden\/Lawn Cleaning"
}
]
}
My code
class Album {
final String title;
Album({
this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
title: json['title'],
);
}
}
As I am following my code like this https://flutter.dev/docs/cookbook/networking/fetch-data
and got this error "A non-null String must be provided to a Text widget." because they are following this type of string and my string type is different. Help!
{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
}
Your given data (API response) seems to have a list of maps, so you should get the data first (use async function):
var response = await http.get("Your Url")
then you should extract the given map list as follow:
var temp = json.decode(response);
List<dynamic> result = temp['Info']); // it is the described list
now, you can use your data (extract each parameter):
String c_type_id = result[0]['c_type_id'];
// and so on...
Your question is not clear at all but I can show you an example how to reach an element in a json.
Your json consists a list that contains string keys. To reach first element of list;
json["Info"][0]
Then pass the key you want to get its value;
json["Info"][0]["c_type_id"]
http_requests All type of http requests are mentioned in this post. If you have any further problem kindly make comment.

ASPNET Core Options Binding does not populate dictionary key/value pair

I have the following JSON configuration
"Configurations": {
"KeyA": {
"Ids": []
},
"KeyB": {
"Ids": [1, 2, 3]
},
"KeyC": {
"Ids": [1, 2, 3],
"OptionalData": "asdf"
}
}
This is then read into the following object
public class AppConfiguration
{
public Dictionary<ConfigType, ConfigurationData> Configurations {get; set;} = new Dictionary<ConfigType, ConfigurationData>();
}
public class ConfigurationData
{
public HashSet<int> Ids {get;set;} = new HashSet<int>();
public string OptionalData = "";
}
public Enum ConfigType
{
KeyA = 1,
KeyB = 2,
KeyC = 3
}
I then bind this in ConfigureServices(IServiceCollection services) method using
services.Configure<AppConfiguration>(this.Configuration);
However, I notied that the configuration binding produces my AppConfiguration's dictionary with only the KeyB and KeyC keys, skipping KeyA, because its Ids array is empty. I read up on the behaviour of the configuration binding online, but as far as I saw it should bind the Ids to null, but here it just does not generate a key value pair in the dictionary altogether.
I tried removing the "Ids" property, leaving my config like "KeyA": {}", but this still did not work. The only way I can get it to parse is if I put in some numbers in the array, but this obviously not what I want.
I would like to know if there is anyway I can bind such a key-value pair, where I don't have any Ids in my array. This seems like it should be somehow supported out of the box, but I'm not sure why it's not working and how could I resolve it, without implementing some hacky custom configuration loader/binder.
For anyone who stumbles upon this in the future, I managed to solve this by setting my array to null, instead of an empty array like so.
"Configurations": {
"KeyA": {
"Ids": null
}
}

How to change JSON returned by query using Helidon 2.0.0-M-2

I'm using Helidon 2.0.0-M2.
When I run the query below I get back a list of JSON objects.
dbClient.execute(exec -> exec.createNamedQuery("select-dsitem-by-id")
.addParam("userId", dataItemId)
.execute())
.thenAccept(response::send)
.exceptionally(throwable -> sendError(throwable, response));
Returned list
[
{
"data": "qwerty",
"user_id": "12345"
},
{
"data": "qwerty123",
"user_id": "22345"
}
]
The attribute names seem to be taken directly from the database column name. e.g. one attribute name returned is "user_id". However, I want it to be "userId". I also want to create a parent wrapper for this list like:
{
"userList": [
{
"data": "qwerty",
"user_id": "12345"
},
{
"data": "qwerty123",
"user_id": "22345"
}
]
}
What is the best way to do this with the dbclient?
Thanks
Simple approach:
Change your SQL statement to return the correct name, such as:
SELECT data, user_id as userId FROM mytable
Complicated approach:
We are working on a better support to map to a JSON stream.
Currently there is only one (a bit complicated) way to achieve this:
You can create a custom mapper from a DbRow to JsonObject. This mapper needs to be a general one (it must work for any DbRow of any query).
The built-in mapper uses metadata provided on the columns. I have prepared a simple example (that just expects to have a single type of statements):
class DbRecordMapperProvider implements DbMapperProvider {
private static final DbMapper<JsonObject> MAPPER = new DbRecordMapper();
#SuppressWarnings("unchecked")
#Override
public <T> Optional<DbMapper<T>> mapper(Class<T> aClass) {
if (JsonObject.class.equals(aClass)) {
return Optional.of((DbMapper<T>)MAPPER);
}
return Optional.empty();
}
}
class DbRecordMapper implements DbMapper<JsonObject> {
#Override
public JsonObject read(DbRow dbRow) {
return Json.createObjectBuilder()
.add("name", dbRow.column("FIRSTPART").as(String.class))
.add("message", dbRow.column("SECONDPART").as(String.class))
.build();
}
#Override
public Map<String, ?> toNamedParameters(JsonObject dbRecord) {
return dbRecord;
}
#Override
public List<?> toIndexedParameters(JsonObject dbRecord) {
throw new IllegalStateException("Cannot convert json object to indexed parameters");
}
}
The important method is public JsonObject read(DbRow dbRow).
Once you have such a DbMapperProvider, you register it with the DbClient:
dbClient = DbClient.builder()
.config(config.get("db"))
.mapperProvider(new DbRecordMapperProvider())
.build();

Stop all further validation if multiple validation for first field fails

I am trying to write the rules for validating field for the validation.
At first i want to check if Location Id is empty, null or if that exist in the database, and then only processed further for other validation.
But, with the code i used, only check if empty, it does not stop if Location Id does not exist in the database.
Register Model
public class RegisterModel
{
public long LocationId {get;set;}
public long FirstName {get;set;}
public long LastName {get;set;}
//...other property to be added
}
JSON i am passing to API:
{
"FirstName": "John",
"LocationId": "1234534",
}
The location id does not exist in the database: But i am getting the response as:
{
"Errors": [
{
"FieldName": "LastName",
"Message": "'Last Name' must not be empty."
},
{
"FieldName": "LocationId",
"Message": "Invalid request."
}
]
}
Validation rule i am using:
public class RegisterModelValidator : AbstractValidator<RegisterModel>
{
private readonly DbContext _context;
public RegisterModelValidator(DbContext context)
{
this._context = context;
this.CascadeMode = CascadeMode.StopOnFirstFailure;
RuleFor(req => req.LocationId)
.NotEmpty().WithMessage("param1 is missing.")
.Must(IsValidRequest).WithMessage("Invalid request.");
When(x => x.LocationId != null, () => {
RuleFor(x => x.FirstName).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEmpty();
RuleFor(x => x.LastName).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEmpty();
});
}
private bool IsValidRequest(string req)
{
var locationId = long.TryParse(req, out long result) ? result : 0;
return _context.Locations.Any(x => x.LocationExtId == locationId);
}
private bool BeAValidDate(string value)
{
DateTime date;
return DateTime.TryParse(value, out date);
}
}
In my condition what i want is if the location id is missing or does not exist in the database, the validation should stop immediately, it should not check for the other field.
If you look at the docs here, its mentioned as
Setting the cascade mode only applies to validators within the same RuleFor chain. Changing the cascade mode does not affect separate calls to RuleFor. If you want prevent one rule from running if a different rule fails, you should instead use Dependent Rules (below)
So can you try it like this using Dependent Rules
RuleFor(x => x.FirstName).NotNull().NotEmpty()
.DependentRules(d => d.RuleFor(req => req.LocationId)
.NotEmpty().WithMessage("param1 is missing.")
.Must(IsValidRequest).WithMessage("Invalid request."));
But i see if we use it like this, i think it should be repeated for multiple properties.
or a better option for you is using PreValidate since
At first i want to check if Location Id is empty, null or if that exist in the database
Prevalidate a property

JayData - Server side validation (CRUD)

I want to create an application with JayData + WCF/RIA Services but i need to detect the changes in the client side (Javascript) entities to put the business logic on the server side.
E.g: if i change a name of a customer, i want to do some validation before i update it on the server.
Is there anyway to do something like this?
[Insert]
public void InsertCustomer(Customer customer)
{
// Some validation before insert
}
[Update]
public void UpdateCustomer(Customer customer)
{
// Some validation before update
}
[Delete]
public void DeleteCustomer(Customer customer)
{
// Some validation before delete
}
To address this securely you need to do it on the server side (and not in JayData) and you need to implement authentication either on .NET way or on you own Then have a check in the onupdate server side method and make something like this:
C# code:
[Insert]
public void InsertCustomer(Customer customer) {
if (! customer.LoginName == Thread.CurrentPrincipal.Identity.Name ) {
throw new SomeValidtionException()
}
}
Is this what you need?
Maybe this is not what you need but I give a shot: you can validate fields on the client with a custom validator function attached to the field. Here is how you do it:
After importing the data context with JaySvcUtil.exe modify the entity and decorate the field with a customValidator:
$data.Entity.extend("UserModel", {
Id: { type: "int", key: true, computed: true },
UserName: { type: "string", required: true,
customValidator: function (v) { return !v || v.length == 3 },
errorMessage: "custom error, length: 3" }
});
In the current version there is no entity level validation functions. If you want them to be, submit a user story on JayData.org/backlogs or an issue at github.com/jaydata/jaydata