ASP.NET Core Expose Config to DI Injected Service - configuration

I have a ASP.NET Core WebAPI project and I am trying to add configuration to my IEmailServicethat I am injecting through DI like this:
services.AddTransient<IEmailSender, AuthMessageSender>();
How can instances of AuthMessageSender get to settings in the config file?

You should use the options pattern with strongly typed configuration:
Create your EmailSettings strongly typed configuration class:
public class EmailSettings
{
public string HostName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
Update your appsettings.json to include a configuration section that maps to your EmailSettings configuration class:
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"EmailSettings": {
"HostName": "myhost.com",
"Username": "me",
"Password": "mysupersecretpassword",
}
}
In the ConfigureServices call of your Startup class, bind appsettings.json to your config class
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MySettings>(
options => Configuration.GetSection("EmailSettings").Bind(options));
}
In your AuthMessageSender class, inject an instance of IOptions<EmailSettings> into the constructor
public class AuthMessageSender
{
private readonly EmailSettings _settings;
public AuthMessageSender(IOptions<EmailSettings> emailSettings)
{
_settings = emailSettings.Value;
// _settings.HostName == "myhost.com";
}
}
Note that in step 3, you can also use
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MySettings>(Configuration.GetSection("EmailSettings"));
}
If you add a reference to Microsoft.Extensions.Options.ConfigurationExtensions in project.json:
{
"dependencies": {
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0"
}
}

The recommended pattern is to read the specific config entries you need at startup and store them in an Options instance in DI, and inject that specific options type into your other components.

Related

Reading data from appsettings.json it does not work

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; }
}

Actually read AppSettings in ConfigureServices phase in ASP.NET Core

I need to setup a few dependencies (services) in the ConfigureServices method in an ASP.NET Core 1.0 web application.
The issue is that based on the new JSON configuration I need to setup a service or another.
I can't seem to actually read the settings in the ConfigureServices phase of the app lifetime:
public void ConfigureServices(IServiceCollection services)
{
var section = Configuration.GetSection("MySettings"); // this does not actually hold the settings
services.Configure<MySettingsClass>(section); // this is a setup instruction, I can't actually get a MySettingsClass instance with the settings
// ...
// set up services
services.AddSingleton(typeof(ISomething), typeof(ConcreteSomething));
}
I would need to actually read that section and decide what to register for ISomething (maybe a different type than ConcreteSomething).
That is the way you can get the typed settings from appSettings.json right in ConfigureServices method:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MySettings>(Configuration.GetSection(nameof(MySettings)));
services.AddSingleton(Configuration);
// ...
var settings = Configuration.GetSection(nameof(MySettings)).Get<MySettings>();
int maxNumberOfSomething = settings.MaxNumberOfSomething;
// ...
}
// ...
}
Starting from ASP.NET Core 2.0 we do configuration setup in Program class when building WebHost instance. Example of such setup:
return new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((builderContext, config) =>
{
IHostingEnvironment env = builderContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
})
Among others, this allows using configuration directly in Startup class, getting an instance of IConfiguration via constructor injection (thank you, built-in DI container):
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
...
}
You can access appsettings.json values by Configuration["ConfigSection:ConfigValue"])
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyContext>(o =>
o.UseSqlServer(Configuration["AppSettings:SqlConn"]));
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"System": "Information",
"Microsoft": "Warning"
}
},
"AppSettings": {
"SqlConn": "Data Source=MyServer\\MyInstance;Initial Catalog=MyDb;User ID=sa;Password=password;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;"
}
}
The appsettings.json file :
"MyApp": {
"Jwt": {
"JwtSecretConfigKey": "jwtSecretConfigKey",
"Issuer": "appIssuer",
"Audience": "appAudience",
"ExpireMinutes": 60
}
}
add a class to bind Jwt section of "MyApp" ...
public class JwtConfig
{
public string JwtSecretConfigKey { get; set; }
public string Issuer { get; set; }
public string Audience { get; set; }
public int ExpireMinutes { get; set; }
}
In ConfigureServices method :
//reading config from appsettings.json
var jwtConfig = Configuration.GetSection("MyApp:Jwt").Get<JwtConfig>();
//using config data ....
services.AddJwt(new AddJwtOptions(jwtConfig.JwtSecretConfigKey, jwtConfig.Issuer, jwtConfig.Audience, jwtConfig.ExpireMinutes));
The code below is the same as above. it works as well...
var jwtConfig = Configuration.GetSection("MyApp").GetSection("Jwt").Get<JwtConfig>();
Hope this helps..
This took me a horrifically long time but I got there in the end using IConfiguration.Bind().
I particularly wanted a flat configuration file rather than having to define a section.
Example appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"MyApiBaseUrl": "https://api.example.com",
"MyApiKey": "example-api-key",
"AllowedHosts": "*"
}
We need a helper class to bind to CustomApplicationConfiguration:
public class CustomApplicationConfiguration
{
public string MyApiBaseUrl { get; set; }
public string MyApiKey { get; set; }
}
Then define and bind inside ConfigureServices(IServiceCollection services):
public void ConfigureServices(IServiceCollection services)
{
var settings = new ApplicationConfiguration();
Configuration.Bind(settings);
Console.WriteLine(settings.MyApiBaseUrl); // https://api.example.com
Console.WriteLine(settings.MyApiKey); // example-api-key
Try next:
var settings = new MySettings();
Configuration.GetSection(nameof(MySettings)).Bind(settings);

How to use an external Json File to serve as a data source for webapi

Following is my code snippet which works fine, my query follows the code:
Model:
namespace CVHub.Models
{
[DataContract]
public class Context
{
[DataMember]
public int sessionID { get; set; }
[DataMember]
public string Name { get; set; }
public static List <Context> Contexts= new List<Context>
{
new Context{sessionID=1,Name="Name1"},
new Context {sessionID=2,Name="Name2"},
new Context {sessionID=3,Name="Name3"}
};
}
}
Controller:
namespace CVHub.Controllers
{
public class ContextController : ApiController
{
List<Context> items;
// GET api/values
public IEnumerable<Context> Get()
{
//return Context.Contexts;
return items;
}
}
}
Question: I want to use an external json file (residing in app_data folder) to serve same data instead of doing new Context{sessionID=1,Name="Name1"},
how to use a data I read from json file? I am very new to MVC and webApi, so it will be of great help if the experts can post the entire working code or as much details as possible please.
You can return a HttpResponseMessage with your JSON file loaded into StringContent.
public class JsonFileController : ApiController
{
public HttpResponseMessage Get()
{
var json = File.ReadAllText(Server.MapPath(#"~/App_Data/contexts.json");
return new HttpResponseMessage()
{
Content = new StringContent(json, Encoding.UTF8, "application/json"),
StatusCode = HttpStatusCode.OK
};
}
}
App_Data/contexts.json
[
{
"sessionId": 1,
"name": "name1"
},
{
"sessionId": 2,
"name": "name2"
},
{
"sessionId": 3,
"name": "name3"
}
]

Spring not accepting embedded json

I am stuck with a JSON and need assistance for the same.
I've a JSON like below which I'm getting from client. i'm using Chrome rest client to pass parameters.The content-type is "application/json"
My controller and bean classes are below. When I am making a post call I'm getting 400 bad request error.Please let me what is wrong? Is there any other way to implement apart from using so many bean classes?
{
"addSurveyRequest": {
"data": {
"suveyName": "abcde",
"surveyDesc": "pqrst",
"surveyFromDate": "MM-DD-YYYY",
"surveyToDate": "MM-DD-YYYY",
"surveyOptions": [
{
"surveyOptionName": "abc",
"surveyOptionDesc": "qwerty"
},
{
"surveyOptionName": "pqr",
"surveyOptionDesc": "asdfg"
}
]
}
}
}
I've my controller like
#RequestMapping(value = "/add", method = RequestMethod.POST, consumes="application/json", produces="application/json")
public #ResponseBody String addSurvey(#RequestBody AddSurveyRequest addSurveyRequest) throws Exception
{
String surveyId=null;
logger.debug("surveyName"+addSurveyRequest.getDataDTO().getSurveyDTO().getSurveyName()+"surveyDesc "+addSurveyRequest.getDataDTO().getSurveyDTO().getSurveyDesc()+"fromdate"+addSurveyRequest.getDataDTO().getSurveyDTO().getSurveyFromDate());
}
I've my bean class like below.
public class AddSurveyRequest{
private DataDTO data;
//setteres and getters
}
public class DataDTO{
private SurveyDTO surveyDTO;
//setteres and getters
}
public class SurveyDTO {
private int surveyId;
private String surveyName;
private String surveyDesc;
private Date surveyFromDate;
private Date surveyToDate;
private List<SurveyOptionDTO> surveyOptions;
//setteres and getters
}
public class SurveyOptionDTO {
private String surveyOptionName;
private String surveyOptionDesc;
//setteres and getters
}
Any help greatly appreciated. Thanks in advance!
I would say you should change the JSON input removing the outer addSurveyRequest as you declared the AddSurveyRequest type as parameter:
{
"data": {
"suveyName": "abcde",
"surveyDesc": "pqrst",
"surveyFromDate": "MM-DD-YYYY",
"surveyToDate": "MM-DD-YYYY",
"surveyOptions": [
{
"surveyOptionName": "abc",
"surveyOptionDesc": "qwerty"
},
{
"surveyOptionName": "pqr",
"surveyOptionDesc": "asdfg"
}
]
}
}
I made the variable name's in my Java class same as JSON parameter name and it worked out for me. I got this answer from another link, missed the link.
Below are the changes I made and it worked!
public class AddSurveyRequest{
private DataDTO addSurveyRequest;
//setteres and getters
}
public class DataDTO{
private SurveyDTO data;
//setteres and getters
}

Jax-RS API POST and GET methods (RESTful Services)

I have a project (homework) about JAX-RS. I'm working with NetBeans, Jersey and Tomcat. In the post method for example:
'{"user":{"username":"accavdar", "gender":"M", "birthDate":"06.11.1982"}}'
when such a request comes I have to parse this input and add new user to my system. The sample response must be:
{
"meta": {
"code": 200
},
"data": {
"message": "You successfully created a user."
}
}
Expectable error can be like that:
{
"meta": {
"code": 101,
"type": "FieldError",
"errors": [
{
"fieldName": "fullname",
"rejectedValue": null
}
]
}
}
Another problem is that: With using Get method the develepor can want to list all user in the system. The response must be like that :
{
"meta": {
"code": 200
},
"data": [
{
"id": 1,
"username": "sample",
"fullname": "sample",
"gender": "M",
"birthDate": "12.02.1990"
},
{
"id": 2,
"username": "sample",
"fullname": "sample",
"gender": "M",
"birthDate": "21.09.1940"
}
]
}
I want to keep users in a text file, there is no limitation about the way of keeping users.(You can keep in database or in memory) But I have no idea about how to handle request input and generate a response like that. I don't want you to do my homework but could anyone give tips about my problem, please?
NOTE: We will work only with JSON "Content-Type: application/json" "Accept: application/json"
EDİT: #Bogdan , Thank you very much for your answer. I searched the web sites you gave. I want to learn that how is that output produced?:
{
"meta": {
"code": 200
},
"data": {
"message": "You successfully created a user."
}
}
or
{
"meta": {
"code": 200
},
"data": {
"id": 1,
"username": "jack",
"fullname": "jack",
"gender": "M",
"birthDate": "12.12.2012"
}
}
I have "meta" and "user" classes.
#XmlRootElement(name="data")
public class User {
#XmlElement
public int id ;
#XmlElement
public String username;
#XmlElement
public String fullname;
#XmlElement
public String gender;
#XmlElement
public String birthDate;
public User(){
}
#XmlRootElement(name="meta")
public class Meta {
#XmlElement
int code=200;
public Meta(){
}
Also I have this jaxbcontextresolver class
#Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext>{
private JAXBContext context;
private Class[] types = {User.class, Meta.class};
public JAXBContextResolver() throws Exception {
this.context =
new JSONJAXBContext( JSONConfiguration.mapped().nonStrings("id").nonStrings("code").build(), types);
}
#Override
public JAXBContext getContext(Class<?> objectType) {
for (Class type : types) {
if (type == objectType) {
return context;
}
}
return null;
}
}
but how to create this response constructs, could any help me?
Your application works with users. This is the resource that you application deals with and your client interacts with for creating, updating, deleting and getting (basically CRUD).
But a user is an abstract resource so your server and client interact with each other by using representations of this resource. The representations can be in JSON format (as in your example), XML etc. Your client specifies what type of representation it wants and the server specifies the representation type it returns by means of the Content-Type. The body of the request/response matches the content type.
This is a Java application so in your application code the users are represented as Java objects. You need to transform the request/response body into objects with getters and setters. You can use JAXB to do the XML transformation, and with a library like Jackson you can transform JSON. You can off course do it manually and parse strings into objects and output strings from objects but that would be more work.
A client submits JSON and after transformation you will have your Java objects that you can handle. You can keep them in memory inside an application scope map or write them inside a file or database and change their representation once again.
Your application will bind URLs to specific actions that transform the request representation into objects, perform operations on the objects then return them to be transformed again into the representation the client expects.
The above are just basic explanations. All your questions can be answered if you follow some JAX-RS tutorials (e.g. a quick search returns REST with Java (JAX-RS) using Jersey - Tutorial or REST: CRUD with JAX-RS (Jersey). I'm sure there are lots other). Your question is too open ended so just dig in and return with specific questions on stackoverflow when you hit road blocks.
EDIT : seems you are struggling with this a little so I'll add a basic service to get you started, let's say for the list of users.
You didn't mention so far nothing about your service class. That's the important one, something like:
package com.test;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/api")
public class Test {
#GET
#Path("/users")
#Produces({ MediaType.APPLICATION_JSON })
public UsersResponseWrapper getUsers() {
List<User> users = new ArrayList<User>();
User u1 = new User();
u1.setId(1);
u1.setFullname("Joe Doe");
u1.setGender("M");
u1.setUsername("joe.doe");
u1.setBirthDate("1919-12-12");
User u2 = new User();
u2.setId(1);
u2.setFullname("John Smith");
u2.setGender("M");
u2.setUsername("john.smith");
u2.setBirthDate("1990-01-01");
users.add(u1);
users.add(u2);
UsersResponseWrapper resp = new UsersResponseWrapper();
resp.setMeta(new Meta(200));
resp.setData(users);
return resp;
}
}
Then your user and meta classes:
package com.test;
public class Meta {
private int code;
public Meta(int code) {
this.code = code;
}
public Meta() {
this.code = 200;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.test;
public class User {
private int id;
private String username;
private String fullname;
private String gender;
private String birthDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthDate() {
return birthDate;
}
public void setBirthDate(String birthDate) {
this.birthDate = birthDate;
}
}
A JAXB provider:
package com.test;
import java.util.ArrayList;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
#Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
private JAXBContext context;
private static Class<?>[] types = {UsersResponseWrapper.class, User.class, Meta.class, ArrayList.class};
public JAXBContextResolver() throws Exception {
this.context = JAXBContext.newInstance(types);
}
#Override
public JAXBContext getContext(Class<?> objectType) {
for (Class<?> type : types) {
if (type == objectType) {
return context;
}
}
return null;
}
}
Something from web.xml:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>RestService</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.test</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>RestService</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
And a wrapper for your result:
package com.test;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class UsersResponseWrapper {
private Meta meta;
private List<User> data;
public Meta getMeta() {
return meta;
}
public void setMeta(Meta meta) {
this.meta = meta;
}
public List<User> getData() {
return data;
}
public void setData(List<User> data) {
this.data = data;
}
}
I think this last class is what put you in difficulty since your result is formed of both meta content and data content. Remember you need to return objects (the default Jackson mapper from Jersey distribution will then take care of it) and it happens you have a complex one. The above should return this (formatting not included):
{
"data": [
{
"birthDate": "1919-12-12",
"fullname": "Joe Doe",
"gender": "M",
"id": "1",
"username": "joe.doe"
},
{
"birthDate": "1990-01-01",
"fullname": "John Smith",
"gender": "M",
"id": "1",
"username": "john.smith"
}
],
"meta": {
"code": "200"
}
}
That's about as much I can add to this as details. It's your homework after all :). You are doing fine, just keep going.