IOptions not getting the values from appsettings.Development.json - c#

I am trying to create a gateway api using net core. When I try to redirect the call using app.route :
app.Run(async (context) =>
{
using (var serviceScope = app.ApplicationServices.CreateScope())
{
var routing = serviceScope.ServiceProvider.GetService<IRoutingService>();
var content = await routing.RouteRequest(context.Request);
await context.Response.WriteAsync(await content.Content.ReadAsStringAsync());
content.Dispose();
// Seed the database.
}
});
... And RoutingService service starts like :
public class RoutingService : IRoutingService
{
private readonly RouteManagement _routeManagement;
static HttpClient _client = new HttpClient();
public RoutingService(IOptions<RouteManagement> routeManagement)
{
_routeManagement = routeManagement.Value;
}
...
.. I can not get the values from json file filled. The following is the json file :
{
"tokenManagement": {
"secret": "Any String used to sign and verify JWT Tokens, Replace this string with your own Secret",
"issuer": "threenine.co.uk",
"audience": "SampleAudience",
"accessExpiration": 30,
"refreshExpiration": 60
},
"routeManagement": {
"Routes": [
{
"Endpoint": "/coupons",
"Destination": {
"Uri": "http://localhost:30561/coupons/",
"RequiresAuthentication": "true"
}
},
{
"Endpoint": "/songs",
"Destination": {
"Uri": "http://localhost:8091/songs/",
"RequiresAuthentication": "false"
}
}
]
}
}
Am I doing smth wrong? The following is the class RouteManagement
public class RouteManagement
{
public List<Routes> Routes { get; set; }
}
public class Routes
{
public string Endpoint { get; set; }
public Routes.DestinationManagement Destination { get; set; }
public class DestinationManagement
{
private DestinationManagement()
{
Uri = "/";
RequiresAuthentication = false;
}
public string Uri { get; set; }
public bool RequiresAuthentication { get; set; }
}
}

Follow steps below to resolve your issue:
Register RouteManagement
services.Configure<RouteManagement>(Configuration.GetSection("routeManagement"));
You need to make DestinationManagement() public, otherwise, it will fail to initialize the DestinationManagement
public class RouteManagement
{
public List<Routes> Routes { get; set; }
}
public class Routes
{
public string Endpoint { get; set; }
public Routes.DestinationManagement Destination { get; set; }
public class DestinationManagement
{
public DestinationManagement()
{
Uri = "/";
RequiresAuthentication = false;
}
public string Uri { get; set; }
public bool RequiresAuthentication { get; set; }
}
}

Have you registered the configuration instance which RouteManagement binds against in ConfigureServices method ?
services.Configure<RouteManagement>(Configuration);

Related

How to use class object instead of using JObject in .NET Core

I want to return C# class object instead of using JObject in here. Could someone can tell me how to use it.
private async Task<JObject> GetReceiptById(string Id, string name)
{
var response = await _ApiService.Get(Id, name);
var responseStr = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
return JObject.Parse(responseStr);
}
throw new Exception(responseStr);
}
this method is return (return JObject.Parse(responseStr)); below JSON output. for that how to create a new class. I am not sure how to apply all in one class.
{
"receipts": [
{
"ReceiptHeader": {
"Company": "DHSC",
"ErpOrderNum": "730",
"DateTimeStamp": "2022-05-14T13:43:57.017"
},
"ReceiptDetail": [
{
"Line": 1.0,
"ITEM": "PP1016",
"ITEM_NET_PRICE": 0.0
},
{
"Line": 2.0,
"ITEM": "PP1016",
"ITEM_NET_PRICE": 0.0
}
],
"XrefItemsMapping": [],
"ReceiptContainer": [],
"ReceiptChildContainer": [],
"rPrefDO": {
"Active": null,
"AllowLocationOverride": null,
"DateTimeStamp": null
}
}
]
}
You can bind the Response Content to a known Type using ReadAsAsync<T>().
https://learn.microsoft.com/en-us/previous-versions/aspnet/hh835763(v=vs.118)
var result = await response.Content.ReadAsAsync<T>();
In your example you will also run into further issues as you are not closing your response after getting it from the Api Service Get method.
Below is a possible solution where you send your object type to the Get method. (not tested)
public virtual async Task<T> GetApiCall<T>(Id, name)
{
//create HttpClient to access the API
var httpClient = NewHttpClient();
//clear accept headers
httpClient.DefaultRequestHeaders.Accept.Clear();
//add accept json
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//return the client for use
using (var client = await httpClient )
{
//create the response
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
//create return object
try
{
var result = await response.Content.ReadAsAsync<T>();
//dispose of the response
response.Dispose();
return result;
}
catch
{
throw;
}
}
// do something here when the response fails for example
var error = await response.Content.ReadAsStringAsync();
//dispose of the response
response.Dispose();
throw new Exception(error);
}
}
What you probably looking for is Deserialization
you can achieve it with
var model = JsonConvert.Deserialize<YourClass>(responseStr);
return model;
but the class (YourClass) properties must match the json string you provided in responseStr.
As the comments section you asked for a generated class:
here is what should look like, after you generate the class.
Note: most of the times, you will need to edit the generated class.
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Receipt
{
public ReceiptHeader ReceiptHeader { get; set; }
public List<ReceiptDetail> ReceiptDetail { get; set; }
public List<object> XrefItemsMapping { get; set; }
public List<object> ReceiptContainer { get; set; }
public List<object> ReceiptChildContainer { get; set; }
public RPrefDO rPrefDO { get; set; }
}
public class ReceiptDetail
{
public double Line { get; set; }
public string ITEM { get; set; }
public double ITEM_NET_PRICE { get; set; }
}
public class ReceiptHeader
{
public string Company { get; set; }
public string ErpOrderNum { get; set; }
public DateTime DateTimeStamp { get; set; }
}
public class Root
{
public List<Receipt> receipts { get; set; }
}
public class RPrefDO
{
public object Active { get; set; }
public object AllowLocationOverride { get; set; }
public object DateTimeStamp { get; set; }
}
generated by: https://json2csharp.com/

Returning List with Children in ASP.NET CORE with firebase

I am trying to do a get all with an ASP.NET Core project that uses this firebase library and I can't seem to return the children nested in an object. I have 3 classes: Route, Via & Waypoints(Serves as a bridge for JSON Deserialization).
public class Route
{
public string Route_ID { get; set; }
public string Destination { get; set; }
public string Origin { get; set; }
public Waypoints Stops { get; set; }
public Route()
{
}
}
public class Via
{
public string Via_ID { get; set; }
public string Route_ID { get; set; }
public int Seq_Number { get; set; }
public string Coordonnees { get; set; }
public string Description { get; set; }
public Via()
{
}
}
public class Waypoints
{
public List<Via> Vias;
public Waypoints()
{
}
}
In my GET method I go Fetch everything from my Routes and want to return it as one JSON List containing all my routes along with their waypoints but it only returns an empty list of Waypoints:
[HttpGet]
public async Task<IEnumerable<Route>> Get()
{
List<Route> routes = (await firebaseClient
.Child("routes")
.OrderByKey()
.OnceAsync<Route>())
.Select(item =>
new Route
{
Route_ID = item.Key,
Origin = item.Object.Origin,
Destination = item.Object.Destination,
Waypoints = item.Object.Waypoints
}).ToList();
foreach (Route route in routes)
{
List<Via> vias = (await firebaseClient
.Child("routes")
.Child(route.Route_ID)
.Child("Waypoints")
.OrderByKey()
.OnceAsync<Via>())
.Select(waypoint =>
new Via
{
Via_ID = waypoint.Key,
Route_ID = waypoint.Object.Route_ID,
Coordonnees = waypoint.Object.Coordonnees,
Seq_Number = waypoint.Object.Seq_Number,
Description = waypoint.Object.Description
}).ToList();
if(vias.Count > 0)
{
route.Stops.Vias = vias;
}
}
return routes;
}
My data structure:
{
"routes" : {
"987321": {
"Destination": "13.13;-12.34",
"Origin": "12.12;-12.12",
"Route_ID": "987321",
"Waypoints": {
"4d5e6f": {
"coordonnees": "45.8;-74.7",
"description": "Description",
"route_id": "987321",
"seq_number": 2,
"via_id": "4d5e6f"
},
"111222": {
"coordonnees": "45.8;-74.7",
"description": "Description",
"route_id": "987321",
"seq_number": 1,
"via_id": "111222"
}
}
}
}
}
And finally my call result:
[
{
"route_ID": "987321",
"destination": "13.13;-12.34",
"origin": "12.12;-12.12",
"waypoints": {}
}
]
It seems the Deserializing doesn't go further than the first layer of children. Is there any solution to this?
Thanks to Rena's suggestion, I figured out that the problem was located in my Waypoints bridging class that was missing a { get; set; }
Here is the change that was made to my class:
public class Waypoints
{
public List<Via> Vias { get; set; }
public Waypoints()
{
}
}

Accessing Json Array from appsettings using Options .NET C#

I've already searched, there are similar questions, but with JSON Array in answers they are using IConfigure in the controller. I can use IConfigure only in Startup.
I have this JSON Array in appsettings.json
{
"EmailList":[
{
"name":"John Algovich",
"email":"John.Algovich#mail.com"
},
{
"name":"Petr Algr",
"email":"Petr.Algr#mail.com"
},
{
"name":"Mathew Cena",
"email":"Mathew.Cena#mail.com"
}
]
}
EmailList.cs:
public class EmailAddress {
public string Name { get; set; }
public string Email { get; set; }
}
public class EmailList {
public List<EmailAddress> EmailArray { get; set; }
}
There is a lot of injections in Startup.cs, so I used the same code for mine:
services.Configure<EmailList>(Configuration.GetSection("EmailList"));
Controller:
public class DevController : Controller
{
private readonly EmailList _devEmailList;
private List<string> _emailList;
public DevController(
IOptions<EmailList> _devEmailList,
{
_devEmailList = devEmailList.Value;
_emailList = new List<string>();
}
}
public IActionResult Index()
{
var result = _devEmailList; // Returns null
var mailData2 = JsonConvert.DeserializeObject<EmailList>(_devEmailList.EmailArray.ToString()); // Returns null
}
Goal: How can get email adresses in Controller using Options and add it to the list?
Ok, so I was able to solve the problem:
I kept my appsettings.json the way it is with config classes.
I changed Startup code to this:
EmailInfo[] emails = Configuration.GetSection("EmailList").Get<EmailInfo[]>();
services.Configure<EmailList>(options => {options.EmailArray = emails.ToList();});
In my Controller:
This stays the same
public class DevController : Controller
{
private readonly EmailList _devEmailList;
private List<string> _emailList;
public DevController(
IOptions<EmailList> _devEmailList,
{
_devEmailList = devEmailList.Value;
_emailList = new List<string>();
}
}
Getting emails:
public IActionResult Index() {
var result = _udeEmailList.EmailArray;
foreach (var mailInfo in result)
{
emailsList.Add(mailInfo.Email);
}
}
what you are retrieving as your section is IEnumerable<EmailAddress> not EmailList. Read what you wrote, in your config there's no "EmailArray" definition.
You can add another level in your config (useful if you will have more things relative to email configuration in that section) or change the type to IEnumerable<EmailAddress> (not needed to be concretely IEnumerable, anything that implements it like an array or a list will work).
If you go for the first option you must do something like this:
In your config file...
{
"EmailConfig":{
"EmailList":[
{
"name":"John Algovich",
"email":"John.Algovich#mail.com"
},
{
"name":"Petr Algr",
"email":"Petr.Algr#mail.com"
},
{
"name":"Mathew Cena",
"email":"Mathew.Cena#mail.com"
}
]
//You can add here more properties
}
}
Your config classes:
public class EmailAddress
{
public string Name { get; set; }
public string Email { get; set; }
}
public class EmailConfig
{
public List<EmailAddress> EmailList { get; set; }
}
Your configuration:
services.Configure<EmailConfig>(Configuration.GetSection("EmailConfig"));
And the controller:
public class DevController : Controller
{
private readonly EmailConfig _mailConfig;
public DevController(IOptions<EmailConfig> mailConfig)
{
_mailConfig = mailConfig.Value;
}
public IActionResult Index()
{
var result = _mailConfig.EmailList;
}
}

Send JSON via POST in C# and Use LINQ to access Objects

I want to be able to access the JSON objects with LINQ when the JSON is returned.
I have referred to Send JSON via POST in C# and Receive the JSON returned? and Send and receive json via HttpClient
This is what I have so far
public static async Task<string> GetMailTip(string user)
{
var jsonData = new StringContent(FormatJson(CreateJsonGettingMailTip(user)), Encoding.UTF8, "application/json");
var payload = await client.PostAsync($"https://graph.microsoft.com/v1.0/users/{user}/getMailTips", jsonData);
string responseContent = "";
if (payload.Content != null)
{
responseContent = await payload.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
var getMailTip = responseContent["value"]
.Children()
.Where(i => i != null)
.Select(c => c[""][""].Value<string>().Trim());
return responseContent;
}
The returned JSON is
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.mailTips)",
"value": [
{
"emailAddress": {
"name": "",
"address": ""
},
"automaticReplies": {
"message": "",
"messageLanguage": {
"locale": "",
"displayName": ""
},
"scheduledStartTime": {
"dateTime": "",
"timeZone": ""
},
"scheduledEndTime": {
"dateTime": "",
"timeZone": ""
}
}
}
]
}
I want to be able to access the message property in the JSON with LINQ
Any help would be appreciated
You go to http://quicktype.io (or similar online service, jsonutils, json2csharp, or use the Visual studio Paste Json as Classes feature - of all the sites that do this QT is the most full featured) to turn your json into classes. This makes it nicer to work with:
// <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using SomeNamespaceHere;
//
// var rootClassNameHere = RootClassNameHere.FromJson(jsonString);
namespace SomeNamespaceHere
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class RootClassNameHere
{
[JsonProperty("#odata.context")]
public Uri OdataContext { get; set; }
[JsonProperty("value")]
public Value[] Value { get; set; }
}
public partial class Value
{
[JsonProperty("emailAddress")]
public EmailAddress EmailAddress { get; set; }
[JsonProperty("automaticReplies")]
public AutomaticReplies AutomaticReplies { get; set; }
}
public partial class AutomaticReplies
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("messageLanguage")]
public MessageLanguage MessageLanguage { get; set; }
[JsonProperty("scheduledStartTime")]
public ScheduledTime ScheduledStartTime { get; set; }
[JsonProperty("scheduledEndTime")]
public ScheduledTime ScheduledEndTime { get; set; }
}
public partial class MessageLanguage
{
[JsonProperty("locale")]
public string Locale { get; set; }
[JsonProperty("displayName")]
public string DisplayName { get; set; }
}
public partial class ScheduledTime
{
[JsonProperty("dateTime")]
public string DateTime { get; set; }
[JsonProperty("timeZone")]
public string TimeZone { get; set; }
}
public partial class EmailAddress
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("address")]
public string Address { get; set; }
}
public partial class RootClassNameHere
{
public static RootClassNameHere FromJson(string json) => JsonConvert.DeserializeObject<RootClassNameHere>(json, SomeNamespaceHere.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this RootClassNameHere self) => JsonConvert.SerializeObject(self, SomeNamespaceHere.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 }
},
};
}
}
(I chose "SomeNamespaceHere" and "RootClassNameHere" for the relevant names of namespace and class root; you might choose different)
And then you use it like this (the deser step will work differently depending on the service you used):
var rootClassNameHere = RootClassNameHere.FromJson(jsonString); //deser
var someLinq = rootClassNameHere.Value.Select(v => v.AutomaticReplies.Message); //query

Is there a built in way to serialize array configuration values?

I'm on a new ASP.NET 5 project.
I'm trying to read an array value, stored in my config.json file, that looks like this:
{
"AppSettings": {
"SiteTitle": "MyProject",
"Tenants": {
"ReservedSubdomains": ["www", "info", "admin"]
}
},
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=aspnet5-MyProject....."
}
}
}
How do I access this from my C# code?
At least with beta4 arrays aren't supported in config.json. See ASP.NET issue 620. But you could use the following config.json:
"AppSettings": {
"SiteTitle": "MyProject",
"Tenants": {
"ReservedSubdomains": "www, info, admin"
}
}
and map it to a class like this:
public class AppSettings
{
public string SiteTitle { get; set; }
public AppSettingsTenants Tenants { get; set; } = new AppSettingsTenants();
}
public class AppSettingsTenants
{
public string ReservedSubdomains { get; set; }
public List<string> ReservedSubdomainList
{
get { return !string.IsNullOrEmpty(ReservedSubdomains) ? ReservedSubdomains.Split(',').ToList() : new List<string>(); }
}
}
This can then be injected into a controller:
public class MyController : Controller
{
private readonly AppSettings _appSettings;
public MyController(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings.Options;
}

Categories