ASP.NET Core 2.0 Configuration Binding - asp.net-core-2.0

I am using Visual Studio 2017, Version 15.7.2 and working with an answer in the following link:
net core 1 (dnx 4.5.1) with enterpriselibrary 6 - setting up the connection string
public class DataConfiguration
{
public string DefaultDatabase { get; set; }
public List<ConnectionStringSettings> ConnectionStrings { get; set; }
}
public class Startup
{
public Startup(IConfiguration configuration)
{
//Get the Database Connections from appsettings.json
DataConfig = configuration.Get<DataConfiguration>();
var defaultDb = DataConfig.ConnectionStrings?.Find(c => c.Name == DataConfig.DefaultDatabase);
DatabaseFactory.SetDatabases(() => new SqlDatabase(defaultDb.ConnectionString), GetDatabase);
Configuration = configuration;
}
public Database GetDatabase(string name)
{
var dbInfo = DataConfig.ConnectionStrings.Find(c => c.Name == name);
if (dbInfo.ProviderName == "System.Data.SqlClient")
{
return new SqlDatabase(dbInfo.ConnectionString);
}
return new MySqlDatabase(dbInfo.ConnectionString);
}
The part I cannot get to work is:
//Get the Database Connections from appsettings.json
DataConfig = configuration.Get<DataConfiguration>();
configuration.Get<DataConfiguration>() returns an empty instance of DataConfiguration. I expected it to populate or bind to DataConfiguration in the appsettings file.
My appsettings.json:
{
"DataConfiguration": {
"DefaultDatabase": "MyDB",
"ConnectionString": "Server=MyServer;Database=MyDB;Integrated Security=True;MultipleActiveResultSets=true",
"ProviderName": "System.Data.SqlClient"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
My Startup.cs
public class DataConfiguration
{
public string DefaultDatabase { get; set; }
public string ConnectionString { get; set; }
public string ProviderName { get; set; }
}
public class Startup
{
public DataConfiguration DataConfig;
public Startup(IConfiguration configuration)
{
DataConfig = configuration.Get<DataConfiguration>();
DatabaseFactory.SetDatabases(() => new SqlDatabase(DataConfig.ConnectionString), GetDatabase);
Configuration = configuration;
}
public Database GetDatabase(string name)
{
if(DataConfig.ProviderName == "System.Data.SqlClient")
{
return new SqlDatabase(DataConfig.ConnectionString);
}
return null;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var config = new DataConfiguration();
Configuration.Bind("DataConfiguration", config);
services.AddMvc();
services.AddSingleton(config);
//services.AddSingleton<IConfiguration>(Configuration);
services.AddTransient<IPatientRepository, PatientRepository>();
}
What am I missing?

So, if you want use settings file this way, you have to write:
var DataConfig = new DataConfiguration();
Configuration.GetSection(nameof(DataConfiguration)).Bind(DataConfig);
But usually settings and configurations uses another way:
https://learn.microsoft.com/aspnet/core/fundamentals/startup?view=aspnetcore-2.0
or even easier:
services.Configure<DataConfiguration>configuration.GetSection(nameof(DataConfiguration)))
services.AddScoped(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<DataConfiguration>>();
return new SqlDatabase(options.Value.ConnectionString);
});
I hope its clear, but maybe final example should be slightly corrected :)

Related

IncludeMembers of Automapper not works as expected

According to automapper docs, I can map nested objects to destination using IncludeMembers function. I have issues with next sample.
Code is available on net fiddle, below is quick reference:
How I map:
var source = new CategoryStatus
{
Subgroup = new CategorySubgroup
{
SubgroupCode = "SubgroupCode",
CategoryGroup = new CategoryGroup { GroupCode = "SubgroupCode" }
}
};
var result = Mapper.Map<Dest, CategoryStatus>(source);
My classes:
public class Dest
{
public string SubgroupCode { get; set; }
public string GroupCode { get; set; }
}
public class CategoryStatus
{
public CategorySubgroup Subgroup { get; set; }
}
public class CategorySubgroup
{
public string SubgroupCode { get; set; }
public CategoryGroup CategoryGroup { get; set; }
}
public class CategoryGroup
{
public string GroupCode { get; set; }
}
My Configuration:
var cfg2 = new MapperConfiguration(cfg => {
cfg.CreateMap<CategoryStatus, Dest>()
.IncludeMembers(x => x.Subgroup);
cfg.CreateMap<CategoryGroup, Dest>();
cfg.CreateMap<CategorySubgroup, Dest>()
.IncludeMembers(x => x.CategoryGroup);
});
Error:
[System.ArgumentException: Property 'System.String GroupCode' is not defined for type 'CategorySubgroup']
Any ideas about configuration setup? Automapper version is 10.0.0
Update
Version 9.0.0 works. Possible latest will also work, but it contains some breaking changes for me, so I didn't test it.

Configure Column Options for Serilog Sinks MsSqlServer in AppSettings.json

I'm trying to determine if it's possible to configure the column options for serilog sink mssqlserver in the appsettings.json file for an ASP.Net Core 2 project.
I create and configure the logger in the Program.cs file.
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
.Build();
public static int Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
//.Enrich.WithProperty("AppName", "One Badass App") // Adds property to XML structure in properties column
.ReadFrom.Configuration(Configuration)
.CreateLogger();
try
{
Log.Information("Starting web host");
BuildWebHost(args).Run();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
I can build the configuration file from the appsettings.json file, which contains a Serilog node with information for which connection string and table to use.
{
"AppSettings": {
"Application": {
"Name": "Payment Processing API",
"Version": "1.0"
}
},
"ConnectionStrings": {
"localPaymentProcessingDb": "Server=(localdb)\\mssqllocaldb;Database=PaymentProcessing;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Serilog": {
"MinimumLevel": "Information",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=(localdb)\\mssqllocaldb;Database=PaymentProcessing;Trusted_Connection=True;MultipleActiveResultSets=true",
"tableName": "Logs"
}
}
]
}
There's an open issue on Github for this, but I haven't found any other information about it.
If column options can't be configured in the appsettings.json, where and how should they be configured in an ASP.Net Core 2 project?
If anyone else stumbles across this same issue the linked GitHub issue in the question now contains the answer:
This is now possible with the latest SQL sink and
Serilog.Settings.Configuration packages.
Also, I know this question asks for a .NET Core 2 answer, and it sounds like the linked GitHub page answers this for 2, I am using .NET Core 3.1 and the following worked for me (hopefully it works for 2 as well)
I installed the Serilog.Settings.Configuration Nuget package and used the following Serilog appsettings.json configuration:
"Serilog":{
"MinimumLevel":"Information",
"WriteTo":[
{
"Name":"MSSqlServer",
"Args":{
"connectionString":"DbContext",
"tableName":"EventLog",
"autoCreateSqlTable":true,
"columnOptionsSection":{
"addStandardColumns":[
"LogEvent"
],
"removeStandardColumns":[
"MessageTemplate",
"Properties"
]
}
}
}
]
}
For accessing Serilog from appsettings in Code, you could bind Serilog node to Serilog class.
Here are the detail steps.
1. Create Serilog Configuration Class
public class SerilogConfiguration
{
public LogEventLevel MinimumLevel { get; set; }
public List<WriteTo> WriteTo { get; set; }
}
public class WriteTo
{
public string Name { get; set; }
public Args Args { get; set; }
}
public class Args
{
public string ConnectionString { get; set; }
public string TableName { get; set; }
public List<StandardColumn> Add { get; set; }
public List<StandardColumn> Remove { get; set; }
}
Configure appsettings.json
Code:
{
"Serilog": {
"MinimumLevel": "Error",
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "<our connection string>",
"tableName": "Log",
"Remove": [ "Properties" ],
"Add": [ "LogEvent" ]
}
}
]
}
}
Bind appsetting.json to class
public void ConfigureServices(IServiceCollection services)
{
services.Configure<SerilogConfiguration>(Configuration.GetSection("Serilog"));
}
Access Configuration
public class HomeController : Controller {
private readonly SerilogConfiguration _configuration;
public HomeController(IOptions<SerilogConfiguration> configuration)
{
_configuration = configuration.Value;
}
public IActionResult AppSettings()
{
var columnOptions = new ColumnOptions();
var MSSqlServer = _configuration.WriteTo.Where(wt => wt.Name == "MSSqlServer").FirstOrDefault();
// Don't include the Properties XML column.
foreach(var columnRemove in MSSqlServer.Args.Remove)
{
columnOptions.Store.Remove(columnRemove);
}
// Do include the log event data as JSON.
foreach (var columnAdd in MSSqlServer.Args.Add)
{
columnOptions.Store.Add(columnAdd);
}
Log.Logger = new LoggerConfiguration()
.WriteTo.MSSqlServer(MSSqlServer.Args.ConnectionString, MSSqlServer.Args.TableName, columnOptions: columnOptions,
restrictedToMinimumLevel: _configuration.MinimumLevel)
.CreateLogger();
return Ok("OK");
} }

ServiceStack - injecting Properties

I am getting very confused with the Funq container.
I have the following:
public interface IConnectionString
{
string ConnectionString { get; set; }
}
public class FoundationConnection : IConnectionString
{
public FoundationConnection(string connectionString)
{
ConnectionString = connectionString;
}
public string ConnectionString { get; set; }
}
Now in my AppHost, I would like to register
container.Register<IConnectionString>(c=> new FoundationConnection(AppSettings.Get(
"FoundationConnectionString", "").MapHostAbsolutePath()));
In my ServiceInterface I want to call this injected method somehow:
public class ServiceInterface : Service
{
public IConnectionString foundationConnection { get; set; }
public object Any(SomeRequest request)
{
string injectedProperty = foundationConnection.ConnectionString;
}
}
}
Issue is that foundationConnection is null and never injected.
I hope this makes sense?
Personally I would use AppSettings to access config settings which would allow you to source configuration from a number of different and cascading configuration sources.
But I've tested this using these types:
public interface IConnectionString
{
string ConnectionString { get; }
}
class FoundationConnectionString : IConnectionString
{
public FoundationConnectionString(string connectionString)
{
ConnectionString = connectionString;
}
public string ConnectionString { get; set; }
}
and it's working correctly after registering it in the AppHost.Configure():
public override void Configure(Container container)
{
container.Register<IConnectionString>(c =>
new FoundationConnectionString("My Connection"));
}
and accessing it from a test service:
[Route("/test")]
public class Test : IReturn<string> { }
public class TestService : Service
{
public IConnectionString Config { get; set; }
public object Any(Test request)
{
return Config.ConnectionString;
}
}
Which returns "My Connection" when called.

Registering and resolving named instances in Castle.Windsor

I can't seem to be able to get the proper instance injected into a class ctor. Here is what I am trying to do:
class Program
{
static void Main(string[] args)
{
WindsorContainer container = new WindsorContainer();
container.Register(
Component.For<ISessionFactory>()
.UsingFactoryMethod(() => GetSessionFactory("1"))
.Named("1"),
Component.For<ISessionFactory>()
.UsingFactoryMethod(() => GetSessionFactory("2"))
.Named("2"));
container.Register(
Component.For<IRepository>()
.ImplementedBy<Repository>()
.DependsOn(container.Resolve<ISessionFactory>("1")),
Component.For<IReadOnlyRepository>()
.ImplementedBy<ReadOnlyRepository>()
.DependsOn(container.Resolve<ISessionFactory>("2")));
var connectionString1 = container.Resolve<IRepository>().Factory.ConnectionString;
var connectionString2 = container.Resolve<IReadOnlyRepository>().Factory.ConnectionString;
//These should not be equal!!!
Console.WriteLine(connectionString1);
Console.WriteLine(connectionString2);
}
public static SessionFactory GetSessionFactory(string connectionString)
{
return new SessionFactory { ConnectionString = connectionString };
}
public static bool Blah(Type accepted)
{
int d = 3;
return true;
}
}
public interface ISessionFactory
{
string ConnectionString { get; set; }
}
public class SessionFactory : ISessionFactory
{
public string ConnectionString { get; set; }
}
public interface IRepository
{
ISessionFactory Factory { get; set; }
}
public class Repository : IRepository
{
public ISessionFactory Factory { get; set; }
public Repository(ISessionFactory factory)
{
this.Factory = factory;
}
}
public interface IReadOnlyRepository
{
ISessionFactory Factory { get; set; }
}
public class ReadOnlyRepository : IReadOnlyRepository
{
public ISessionFactory Factory { get; set; }
public ReadOnlyRepository(ISessionFactory factory)
{
this.Factory = factory;
}
}
Can anyone spot the problem?
try this:
container.Register(
Component.For<ISessionFactory>()
.UsingFactoryMethod(() => GetSessionFactory("1"))
.Named("1"),
Component.For<ISessionFactory>()
.UsingFactoryMethod(() => GetSessionFactory("2"))
.Named("2"),
Component.For<IRepository>()
.ImplementedBy<Repository>()
.DependsOn(Dependency.OnComponent(typeof(ISessionFactory),"1")),
Component.For<IReadOnlyRepository>()
.ImplementedBy<ReadOnlyRepository>()
.DependsOn(Dependency.OnComponent(typeof(ISessionFactory), "2")));

Orchard Content Type is null

i am new in orchard module development.i create a module.when i try to save data.
i use this code fore save data
public ActionResult Create(FormCollection input)
{
var product = contentManager.New<ProductPart>("Product");
product.EmployeeName = input["EmployeeName"];
product.EmployeeFathersName = input["EmployeeFathersName"];
product.DOB = Convert.ToDateTime(input["DOB"]);
product.Email = input["Email"];
product.Address = input["Address"];
product.JoiningDate = Convert.ToDateTime(input["JoiningDate"]);
if (!ModelState.IsValid)
{
return View(product);
}
contentManager.Create(product);
return RedirectToAction("Index");
}
this class i use in Model
public class ProductRecord:ContentPartRecord
{
public virtual string EmployeeName { get; set; }
public virtual string EmployeeFathersName { get; set; }
public virtual DateTime DOB { get; set; }
public virtual string Email { get; set; }
public virtual string Address { get; set; }
public virtual DateTime JoiningDate { get; set; }
}
public class ProductPart : ContentPart<ProductRecord>
{
/*
public int Id
{
get { return Record.Id; }
set{Record.Id = value;}
}
*/
[Required]
public string EmployeeName
{
get { return Record.EmployeeName; }
set { Record.EmployeeName = value; }
}
[Required]
public string EmployeeFathersName
{
get { return Record.EmployeeFathersName; }
set { Record.EmployeeFathersName = value; }
}
[Required]
public DateTime DOB
{
get { return Record.DOB; }
set { Record.DOB = value; }
}
[Required]
public string Email
{
get { return Record.Email; }
set { Record.Email = value; }
}
[Required]
public string Address
{
get { return Record.Address; }
set { Record.Address = value; }
}
[Required]
public DateTime JoiningDate
{
get { return Record.JoiningDate;}
set { Record.JoiningDate = value; }
}
}
i use content type "Product" but when it goes orchard ContentCreateExtension in belows method
public static T New<T>(this IContentManager manager, string contentType) where T : class, IContent {
var contentItem = manager.New(contentType);
if (contentItem == null)
return null;
var part = contentItem.Get<T>();
if (part == null)
throw new InvalidCastException();
return part;
}
here i face var part is null that means it content part is null.
please help me....
Have you setup your migrations class?
i.e.
public class Migrations : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("ProductRecord",
table => table
.ContentPartRecord()
.COLUMNS NEED TO BE SPECIFIED
);
ContentDefinitionManager.AlterTypeDefinition("Forum",
cfg => cfg
.WithPart("ProductPart")
.WithPart("CommonPart")
);
Also have you setup your repository?
i.e.
public class ProductPartHandler : ContentHandler {
public ProductPartHandler(IRepository<ProductPartRecord> repository) {
Filters.Add(StorageFilter.For(repository));
}
In addition to the Nicholas answer, I want to mention, that missing driver for the ProductPart can cause such error. Make sure, that you have at least empty driver defined.
public class ProductPartDriver : ContentPartDriver<ProductPart> {}
Just went through a similar situation, be sure that the handler class is declared as public.

Resources