Reading data from appsettings.json it does not work - json

I'm trying to read from appsetings.json file some data just like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
//sercies.Configure<Models.AppDate>(Configuration);
services.Configure<Models.AppData>(Configuration.GetSection("AppData"));
//It does not works
string option = Configuration.Get<Models.AppData>().AnotherOption;
//It works
string anotherOption = Configuration["AppData:AnotherOption"];
// Add framework services.
services.AddMvc();
}
With these classes:
public class AppData
{
public Jwt Jwt { get; set; }
public string AnotherOption { get; set; }
}
public class Jwt
{
public string Audience { get; set; }
public string Issuer { get; set; }
}
And in appsettings.json:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"AppData": {
"Jwt": {
"Audience": "http://localhost:5000",
"Issuer": "http://localhost:5000"
},
"AnotherOption": "Not yet"
}
}
When i debug, option var it's null. ¿How can i implement this?. Ty

I am not really sure why the code above doesn't work.
But I know other ways to do it.
string option = Configuration.GetSection("AppData").Get<Models.AppData>().AnotherOption;
or
string option = ConfigurationBinder.Get<Models.AppData>(Configuration.GetSection("AppData")).AnotherOption;

public IConfiguration Configuration { get; }
Below method can access the data from appsettings.json
public void ConfigureServices(IServiceCollection services)
{
var config = Configuration.GetSection("Application").Get<Application>();
}
//Model class
public class Application
{
public string ServiceUrl { get; set; }
}

Related

Why does it say "The field is required" in postman even if it's nullable?

I have connected my asp.net core project to MS SQL server and am trying to test my APIs after writing the controllers. Here are 2 of the data models that I am trying to use.
public partial class Content
{
public Guid CCuid { get; set; }
public Guid CPuid { get; set; }
public string? CContents { get; set; }
public decimal? CAmount { get; set; }
public string? CCheckNumber { get; set; }
public int? CQuantity { get; set; }
public string? CNotes { get; set; }
public DateTime CDateProcessed { get; set; }
public string? CUserName { get; set; }
public virtual Vompackage? CPu { get; set; }
}
public partial class Package
{
public Package()
{
Contents = new HashSet<Content>();
}
/// <summary>
/// Unique Package Identifier
/// </summary>
public Guid PPuid { get; set; }
public Guid PSuid { get; set; }
public string? PTrackingNumber { get; set; }
public string? PBolnumber { get; set; }
public string? PProductCode { get; set; }
public int? PQuantity { get; set; }
public int? PPallets { get; set; }
public int? PBoxes { get; set; }
public string? PNotes { get; set; }
public DateTime PDateEntered { get; set; }
public virtual Vomshipment? PSu { get; set; }
public virtual ICollection<Content> Contents { get; set; }
}
}
Now I am trying to add a content using postman. When I tried to add the following data,
{
"cAmount": 2332,
"cCheckNumber": "",
"cQuantity": 133,
"cNotes": "thank u ",
"cDateProcessed": "2020-12-02T13:40:47.207",
"cUserName": "ztinsley",
"CPu": null
}
It gives 400 response, and
"errors": {
"CPu": [
"The CPu field is required."
]
I used null! to make CPu nullable. And when I tested GET method to pull all the contents, it says "cPu": null for every data. Why is it having trouble adding a new data? I also tried to add options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true in AddControllers(), but the it gives me 500 response. Please help!
P.S.
I have attached my controller to see if I made any mistakes.
[Produces("application/json")]
[ApiController]
[Route("api/content")]
public class ContentController : Controller
{
private readonly IContentRepository _contentReporitory;
public ContentController(IContentRepository contentReporitory)
{
_contentReporitory = contentReporitory;
}
[HttpGet("{ccuid}")]
public async Task<ActionResult<Content>> GetContentById(Guid ccuid)
{
try
{
var result = await _contentReporitory.GetContentById(ccuid);
if (result == null)
{
return BadRequest();
}
return result;
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
[HttpPost("addcontent")]
public async Task<ActionResult<Content>> AddContent([FromBody]Content content)
{
try
{
if (content == null)
return BadRequest();
var newContent = await _contentReporitory.AddContent(content);
return CreatedAtAction(nameof(GetContentById),
new { id = newContent.CCuid }, newContent);
} catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
}
}
My repository:
public class ContentRepository : IContentRepository
{
private readonly OperationsContext _operationsContext;
public ContentRepository(OperationsContext operationsContext)
{
_operationsContext = operationsContext;
}
public async Task<Content> AddContent(Content content)
{
var result = await _operationsContext.Contents.AddAsync(content);
await _operationsContext.SaveChangesAsync();
return result.Entity;
}
}
}
All project templates starting with .NET 6 (C# 10) enable the nullable context for the project. Projects created with earlier templates don't include this element, and these features are off unless you enable them in the project file or use pragmas. It means CPu is treated as a non-nullable property.
So you can simply send {} instead of null:
{
"cAmount": 2332,
"cCheckNumber": "",
"cQuantity": 133,
"cNotes": "thank u ",
"cDateProcessed": "2020-12-02T13:40:47.207",
"cUserName": "ztinsley",
"CPu": {}
}
Or just set
public virtual Package? CPu { get; set; }
Then you can send "CPu": null.
You can refer to this Docs to learn more.

How do I add a Claim (or set of claims) to an AppSettings file?

I have an application that is normally connected to an authentication service that provides an identity for the current user. Often, when I'm travelling or commuting, I don't have internet access and need to work in a local mode. In this environment, I want to hard-code a set of claims into the application using the appSettings file in order to give the current user an identity.
I'm having trouble deserializing the System.Security.Claims structure. I'm using the deserialization method found on this post, but the Configuration system isn't recognizing it. Here's the definition of the class I'm trying to read from the configuration:
public class HttpHost
{
public Uri BaseAddress { get; set; }
[JsonConverter(typeof(ClaimConverter))]
public System.Security.Claims Claim { get; set; }
public string Identifier { get; set; }
public TimeSpan Timeout { get; set; }
}
Here's the actual data:
"HttpHosts": [
{
"BaseAddress": "https://localhost/",
"Claim": {
"Issuer": "LOCAL AUTHORITY",
"OriginalIssuer": "LOCAL AUTHORITY",
"Type": "http://my.org/ws/2015/01/identity/claims/mytype",
"Value": "myvalue",
"ValueType": "http://www.w3.org/2001/XMLSchema#string"
},
"Identifier": "ThetaRex.OpenBook.Desktop.Common.OpenBookHost",
"Timeout": "00:01:23"
}],
How do I get the Configuration system to recognize the custom type converter - ClaimConverter - such that it will work when using it with DI:
public HttpHost(IOptions<List<HttpHost>> options)
{
HttpHost httpHost = options.Value.Find(h => h.Identifier == typeof(T).FullName);
...
}
this code was tested in visual studio and working properly
var appSettingsSection = configuration.GetSection("HttpHosts");
HttpHost[] settings = appSettingsSection.Get<HttpHost[]>();
UPDATE
if you need to use a special class Claims you can convert this claim to your class Claims using a mapper or manually ( you can add this code to getter or setter as well)
var claims=settings[0].ClaimDetails;
settings[0].Claims= new System.Security.Claims { Issuer=claims.Issuer, .... }
classes
public class HttpHost
{
public string BaseAddress { get; set; }
[JsonProperty("Claim")]
public ClaimDetails ClaimDetails { private get; set; }
[JsonIgnore]
public System.Security.Claims Claims { get; set; }
public string Identifier { get; set; }
public string Timeout { get; set; }
}
public class ClaimDetails
{
public string Issuer { get; set; }
public string OriginalIssuer { get; set; }
public string Type { get; set; }
public string Value { get; set; }
public string ValueType { get; set; }
}

deserialize dataset in xamarin forms

How can you decrypt/ deserialize dataset. here is what i am getting from the web service. I am new to xamarin forms. Thanks in advance. i tried this json2csharp.com to convert, but got an error because it can convert datatable to csharp but not datasets.
[
[
{
"bit_HasError":false,
"vchar_ErrorMsg":""
}
],
[
{
"int_SurveyQuestionID":1,
"vchar_Description":"we",
"vchar_Instruction":"Question Instruction",
"int_AnswerType":1
},
{
"int_SurveyQuestionID":5,
"vchar_Description":"this is the question 2",
"vchar_Instruction":null,
"int_AnswerType":2
}
],
[
{
"int_SurveyQuestionID":1,
"vchar_Option":"option1"
},
{
"int_SurveyQuestionID":5,
"vchar_Option":"answer1"
},
{
"int_SurveyQuestionID":5,
"vchar_Option":"answer2"
},
{
"int_SurveyQuestionID":5,
"vchar_Option":"answer3"
},
{
"int_SurveyQuestionID":1,
"vchar_Option":"optionn2"
}
]
]
Using https://app.quicktype.io/ it is quite easy to get started, just copy paste your json in there, here is the result:
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using QuickType;
//
// var prject = Prject.FromJson(jsonString);
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Prject
{
[JsonProperty("bit_HasError", NullValueHandling = NullValueHandling.Ignore)]
public bool? BitHasError { get; set; }
[JsonProperty("vchar_ErrorMsg", NullValueHandling = NullValueHandling.Ignore)]
public string VcharErrorMsg { get; set; }
[JsonProperty("int_SurveyQuestionID", NullValueHandling = NullValueHandling.Ignore)]
public long? IntSurveyQuestionId { get; set; }
[JsonProperty("vchar_Description", NullValueHandling = NullValueHandling.Ignore)]
public string VcharDescription { get; set; }
[JsonProperty("vchar_Instruction")]
public string VcharInstruction { get; set; }
[JsonProperty("int_AnswerType", NullValueHandling = NullValueHandling.Ignore)]
public long? IntAnswerType { get; set; }
[JsonProperty("vchar_Option", NullValueHandling = NullValueHandling.Ignore)]
public string VcharOption { get; set; }
}
public partial class Prject
{
public static List<List<Prject>> FromJson(string json) => JsonConvert.DeserializeObject<List<List<Prject>>>(json, QuickType.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this List<List<Prject>> self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters = {
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
}
P.S.: Please note that you have to modify the class names.

How to display JSON data in Xamarin.forms list view?

I am new to xamarin.forms, and i want to build an cross platform app that will display JSON data in the list view. This is my JSON data.
{
"fish_product": [
{
"fish_id": "1",
"fish_img": "",
"fish_name": "Indian Mackerel",
"fish_category": "Marine Fish",
"size": "Medium",
"price": "100"
},
{
"fish_id": "2",
"fish_img": "",
"fish_name": "Manthal Repti",
"fish_category": "Marine Fish",
"size": "Small",
"price": "200"
},
{
"fish_id": "4",
"fish_img": "",
"fish_name": "Baby Sole Fish",
"fish_category": "Marine Fish",
"size": "Small",
"price": "600"
}
]
}
I want to display "fish_name" in list view. please suggest any solution or any article or tutorial for this. thank you in advance.
I think you have to deserialize this JSON to an object like
public class FishProduct
{
public string fish_id { get; set; }
public string fish_img { get; set; }
public string fish_name { get; set; }
public string fish_category { get; set; }
public string size { get; set; }
public string price { get; set; }
}
public class RootObject
{
public ObservableCollection<FishProduct> fish_product { get; set; }
}
Then you have to use a ListView where you set your listview.ItemsSource = myList.fish_product
Then you have to create a DataTemplate using ViewCell
In this ViewCell you can have a Label when you SetBinding the fish_name field. In code something like
Label label = new Label();
label.SetBinding(Label.TextProperty, "fish_name");
I think you can take a look to ListView Documents
I think this may help you
Your MODEL
public class FishProduct
{
public string fish_id { get; set; }
public string fish_img { get; set; }
public string fish_name { get; set; }
public string fish_category { get; set; }
public string size { get; set; }
public string price { get; set; }
}
public class RootObject
{
public List<FishProduct> fish_product { get; set; }
}
Webservice call and JSON Deserialisation
public async Task GetData()
{
try
{
HttpClient client = new HttpClient();
var result = await client.GetAsync("http://yourJSON_Url");
result.EnsureSuccessStatusCode();
string json = await result.Content.ReadAsStringAsync();
List<FishProduct> res= JsonConvert.DeserializeObject<List<FishProduct>>(json);
}
catch (Exception ex)
{
throw;
}
}

How to use a POCO object to access an array of options in the appsettings.json file (ASP.NET 5)

I am using ASP.NET 5 and I want to use POCO classes to access my appsettings.json file. This file looks like this:
{
"Data": {
"ErpSystemConnection": {
"ConnectionString": "[myConnectionString]"
}
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Verbose",
"System": "Information",
"Microsoft": "Information"
}
},
"GoogleAnalytics": {
"Account": [
{
"Name": "AccountName",
"ServiceAccountEmailAddress": "someEmail#someaccount.iam.gserviceaccount.com",
"KeyFileName": "key1.p12",
"Password": "notasecret"
},
{
"Name": "AnotherAccount",
"ServiceAccountEmailAddress": "anotherEmailAccount#someotheraccount.iam.gserviceaccount.com",
"KeyFileName": "key2.p12",
"Password": "notasecret"
}
],
"KeyFilePath": "/googleApis/"
}
}
The 'GoogleAnalytics' key contains an array of accounts that I wish to be able to access in a collection either as a list or an array.
I created a POCO to represent this key that contains a corresponding collection of 'Account' objects:
public class GoogleAnalytics
{
public Account[] Account { get; set; } = new Account[1];
public string KeyFilePath { get; set; }
public GoogleAnalytics()
{
}
}
And the 'Account' object:
public class Account
{
private const string _applicationName = #"Storefront Analytics";
private X509Certificate2 _certificate;
private ServiceAccountCredential _credential;
private AnalyticsService _service;
#region |--Properties--|
public string Name { get; set; }
public string Password { get; set; }
public string ServiceAccountEmailAddress { get; set; }
public string KeyFileName { get; set; }
public string KeyFilePath { get; set; }
public string KeyFileFullPath
{
get
{
return $"{KeyFilePath}{KeyFileName}";
}
}
public X509Certificate2 Certificate
{
get
{
if(_certificate == null)
{
ConfigureInstance();
}
return _certificate;
}
set
{
_certificate = value;
}
}
public ServiceAccountCredential Credential
{
get
{
if (_credential == null)
{
ConfigureInstance();
}
return _credential;
}
set
{
_credential = value;
}
}
public AnalyticsService Service
{
get
{
if (_service == null)
{
ConfigureInstance();
}
return _service;
}
set
{
_service = value;
}
}
#endregion
#region |--Constructors--|
public Account()
{
}
public Account(string password, string keyFileName,
string keyFilePath,
string serviceAccountEmailAddress, string accountName)
{
//TODO: Validate parameters
Password = password;
KeyFileName = keyFileName;
KeyFilePath = keyFilePath;
ServiceAccountEmailAddress = serviceAccountEmailAddress;
Name = accountName;
}
#endregion
private void ConfigureInstance()
{
Certificate = new X509Certificate2(KeyFileFullPath, Password, X509KeyStorageFlags.Exportable);
Credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(ServiceAccountEmailAddress)
{
Scopes = new[] { AnalyticsService.Scope.Analytics }
});
Service = new AnalyticsService(new BaseClientService.Initializer()
{
HttpClientInitializer = Credential,
ApplicationName = _applicationName
});
}
}
My Controller:
public class GoogleAnalyticsController : Controller
{
#region |--Properties--|
[FromServices]
private IGoogleAnalyticsRepository _repo { get; set; }
#endregion
public GoogleAnalyticsController(IOptions<GoogleAnalytics> options)
{
var temp = options.Value;
}
}
The 'KeyFilePath' property is properly set in the IOptions instance.
The problem I am having is that the Account array contains null references - none of the accounts are being instantiated. I wondering if I am doing this wrong, or the Options Model doesn't support this type of behavior at this time?
Update in response to Shaun Luttin's answer
I implemented the changes listing in Shaun Luttin's answer. There seems to have been an additional problem. For whatever reason, all of the Account instances' properties were null until I simplified the class as follows:
public class Account
{
public string Name { get; set; }
public string Password { get; set; }
public string ServiceAccountEmailAddress { get; set; }
public string KeyFileName { get; set; }
public string KeyFilePath { get; set; }
}
Short Answer
I wondering if I am doing this wrong, or the Options Model doesn't support this type of behavior at this time?
You are doing one thing wrong. The Options Model does support arrays. You need NOT to initialize your array property with an array of size [1].
public Account[] Account { get; set; } = new Account[1]; // wrong
public Account[] Account { get; set; } // right
Demo
Here is a sample, just for you, that you can find here on GitHub.
MyOptions.cs
namespace OptionsExample
{
public class MyObj
{
public string Name { get; set; }
}
public class MyOptions
{
public string Option1 { get; set; }
public string[] Option2 { get; set; }
public MyObj[] MyObj { get; set; }
}
}
Startup.cs
namespace OptionsExample
{
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.OptionsModel;
using System.Linq;
public class Startup
{
public IConfigurationRoot Config { get; set; }
public Startup(IHostingEnvironment env)
{
Config = new ConfigurationBuilder().AddJsonFile("myoptions.json").Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<MyOptions>(Config);
}
public void Configure(IApplicationBuilder app,
IOptions<MyOptions> opts)
{
app.Run(async (context) =>
{
var message = string.Join(",", opts.Value.MyObj.Select(a => a.Name));
await context.Response.WriteAsync(message);
});
}
}
}
myoptions.json
{
"option1": "option1val",
"option2": [
"option2val1",
"option2val2",
"option2val3"
],
"MyObj": [
{
"Name": "MyObj1"
},
{
"Name": "MyObj2"
}
]
}
project.json dependencies
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final"
}
Output