Say I put the settings below in appsettings.json.
"MySettings": {
"SmtpHost": "smtp.mydomain.com"",
"WebService": "http://localhost:1337"
}
And I have the class below to hold those settings.
public class MySettings
{
public string SmtpHost{ get; set; }
public string WebService{ get; set; }
}
With RC1 I would use the line of code below in the ConfigureServices() method to load those configuration settings.
services.Configure<MySettings>(Configuration.GetSection("MySettings"));
But in RC2 that same line of code gives me this error
Cannot convert from
'MicrosoftExtensions.Configuration.IConfigurationSection' to
'System.Action<MySettings>'.
You simply need to reference a different package with RC2. In your project.json simply add a reference to the "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-rc2-final" package, and you'll get the correct extension method that you're looking for.
"dependencies": {
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-rc2-final"
}
Like several of the changes with ASP.NET Core RC2, there was a lot of re-packing and moving of things. I put together a migration guide that you might find useful.
you need to add the package:
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0-rc2-final",
and make sure you have this using:
using Microsoft.Extensions.Configuration;
Related
I'm trying to generate JSON Schemas using Newtonsoft JSON Schema. Regular properties added in my POCO class are added to the schema when it is generated. I'm also using PostSharp Aspects to add properties, but none of those are added to the schema.
This is a Console application targeting .NET 4.7.2.
Here is my Console application:
public class Program
{
private static void Main(string[] args)
{
JSchemaGenerator gen = new JSchemaGenerator();
JSchema schema = gen.Generate(typeof(MyClass));
File.WriteAllText("C:\\Temp\\TestSchema.json", schema.ToString());
}
}
Here is my aspect:
[PSerializable]
public class TestAspect : InstanceLevelAspect
{
[IntroduceMember]
[JsonProperty(Required = Required.Always)]
public string AspectProp { get; set; }
}
And here is my POCO:
[TestAspect]
public class MyClass
{
public int MyProperty { get; set; }
}
Finally, here is the generated schema:
{
"type": "object",
"properties": {
"MyProperty": {
"type": "integer"
}
},
"required": [
"MyProperty"
]
}
The MyProperty property is in the schema, but AspectProp - the property added by the aspect - is not.
When I open the exe in a decompiler, I can see that AspectProp is actually added to MyClass:
I'm not sure if this is a problem with PostSharp or Newtonsoft JSON Schema or if I'm doing something wrong. It seems like this should be possible.
Edit 1: 20 May
I split my solution out into separate projects - one for the Console app, one for the Aspect and one for MyClass. After making sure I was referencing the generated MyClass DLL directly (i.e. not a project reference, I actually removed the project once MyClass was built) it did not make a difference. AspectProp is still not in the schema. Based on this and the serialization suggested below by #dbc, this leads me to believe it is a problem with the Newtonsoft schema generator
Edit 2: 20 May
Per Antonin's Answer below, I created a new ContractResolver:
public class AspectPropertyResolver : DefaultContractResolver
{
public AspectPropertyResolver()
{
SerializeCompilerGeneratedMembers = true;
}
}
And then registered it in my app before calling Generate:
gen.ContractResolver = new AspectPropertyResolver();
Now my schema includes the aspect-generated property.
Newtonsoft.Json has an opt-in feature to serialize compiler-generated properties. See Newtonsoft.Json.Serialization.DefaultContractResolver.SerializeCompilerGeneratedMembers property.
This doesn't do it
[JsonConverter(typeof(StringEnumConverter))]
public enum Numbers
{
[EnumMember(Value = "[")]
One,
[EnumMember(Value = "Two")]
Two
}
And nor does this on the POCO/DTO.
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public IEnumerable<Numbers> Numbers{ get; set; }
Why is this impossible?
So it turns out that out of the box it uses some JSON thing that isn't Newtonsoft and which ignores the Newtonsoft attributes. How very crap.
The fix is to install NuGet package Microsoft.AspNetCore.Mvc.NewtonsoftJson and in Startup.ConfigureServices to add:
services.AddControllersWithViews().AddNewtonsoftJson();
I'm currently building a simple website using ASP.NET Core 2 and bootstrap. The site will be deployed to a staging and production environment so I want to be able to configure some settings using Configuration Key/Value pairs I can set in Azure. I also want these values to be available to me in Javascript.
Thanks to this helpful blog post I have worked out how to create an AppSettings class and populate it. This post also covers using dependency injection to access AppSettings from a RazorPage model.
My appsettings.json file
{
"AppSettings": {
"TestProperty": "Test_Property"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Automatically bind my AppSettings class in Startup.cs
services.Configure<AppSettings>(Configuration.GetSection(nameOf(AppSettings)));
Accessing the settings via dependency injection:
public class HomeModel : PageModel
{
private readonly AppSettings _appSettings;
public string TestProperty {get; set;}
public HomeModel(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings.Value;
}
public IActionResult Index()
{
TestProperty = _appSettings.TestProperty;
return View();
}
}
Then on the page where I want to use this property in javascript I do the following to create a javascript property with the setting:
<script type="text/javascript">
var testProperty = '#Model.TestProperty';
</script>
This works but ideally I don't want to have to configure every page to use this dependency injection and expose my TestProperty on every page. I would like to be able to put the above code in my _Layout.cshtml in which every page's body is rendered (or somewhere else appropriate) so I can create a javascript variable for use on every page.
I have thought about using a BaseViewModel from which all my page's models are inherited but experimenting with this hasn't resulted in anything useful (just a exceptions).
How would you go about creating a javascript property from a configuration setting with the ability to configure only once?
I've come up with something that works the way I need but very interested to hear other suggestions, my way could well be far from the best..
I stumbled across this blog post which talks about the MVC6 keyword, #inject. Using this it is possible to inject dependencies into Razor views.
Using this I added the following to the top of my _Layout.cshtml file:
#inject IAppSettings AppSettings;
I could then reference properties of AppSettings in this view using:
<script type="text/javascript">
var testProperty = '#AppSettings.TestProperty';
</script>
I then edited my Startup.cs class to register IAppSettings and creates an AppSettings factory that reads the appsettings.json file and makes a new AppSettings class when required:
services.AddSingleton<IAppSettings, AppSettings>(e => Configuration.GetSection(nameof(AppSettings)).Get<AppSettings>());
This works a treat and I can access my javascript testProperty everywhere in my application but I'm curious if anyone has any other ideas as to how this could be done differently (perhaps using a BaseViewModel)?
Updated:
As requested, here is more information on my implementation:
My IAppSettingsService interface:
public interface IAppSettingsService
{
string AzureStorageAccountName { get; }
string AzureStorageAccountKey { get; }
}
My AppSettingsService implementation:
public class AppSettingsService : IAppSettingsService
{
public string AzureStorageAccountName { get; set; }
public string AzureStorageAccountKey { get; set; }
}
The AppSettings.json:
{
"AppSettings": {
"AzureStorageAccountName": "XXXXXXXXXX",
"AzureStorageAccountKey": "XXXXXXXXXX"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Then in the Azure Portal I can change these values at any time using AppSettings:AzureStorageAccountName and setting the value to the required information in the App Settings section.
not sure what exactly you are trying to achieve. But pretty much what you have is the way you will access the appsettings in JavaScript. Injecting objects/services to view is a great thing in ASP.NET Core.
if you are just looking at URLs for different environments - you can achieve it in your release pipelines. In my day job - i work on a web app which is asp.net core as host + angular 2 as UI framework. We have 4 environments. angular code always makes call to our asp.net core host. we have a middleware written which looks for api calls and forwards them to our APIs hosted on azure in respective environments. The domain of the api environment is kept as an appsetting key. In our release pipeline - we override the property for each environment release.
Its best to centralize everything in your asp.net server side code. The UI i.e. JavaScript should just ping your server side MVC controller end point. That way you can parameterize the application settings during release.
hope this helps.
we are trying to develop a asp core application (MVC) using ef code first . however it seems that requires the db context to be in an executable and not class library .
so the data context was added in the web UI project but the issue that how can the db context's dbset be made available in the repository project ..
example code is as under:
public class CompanyRepository : GenericRepository<Company>, /*IGenericRepository<Company>*/ ICompanyRepository
{
public CompanyRepository(DbContext dbContext) : base(dbContext)
{
}
public async Task<IEnumerable<Company>> GetAllAsync()
{
return await base.GetAllAsync<Company>();
}
}
MVC Project StartUp .cs
services.AddDbContext<DBContext>();
services.AddScoped<ICompanyRepository, CompanyRepository>();
DBCOntext.cs in MVC Project
public class DBContext : DbContext
{
private IConfigurationRoot _config;
public DBContext(IConfigurationRoot config, DbContextOptions options):base(options)
{
_config = config;
}
}
currently it seems to raise following error:
An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve
service for type 'Microsoft.EntityFrameworkCore.DbContext' while
attempting to activate
'On.Store.Repository.Companies.CompanyRepository'.
We have two problems here:
1) When you configure services in a Startup class, you are configuring your custom context (for easier reference, let's name it CustomDbContext):
public class CustomDbContext: DbContext
{
... and in the Startup class:
services.AddDbContext<CustomDbContext>();
... so in your repository, you need to inject a context of declared class, instead of base DbContext class:
// THIS WILL NOT WORK
public class CompanyRepository : GenericRepository<Company>, ICompanyRepository
{
public CompanyRepository(DbContext dbContext) : base(dbContext)
{
}
}
// THIS WILL WORK
public class CompanyRepository : GenericRepository<Company>, ICompanyRepository
{
public CompanyRepository(CustomDbContext dbContext) : base(dbContext)
{
}
}
2) Problem number two is revealed directly from the first problem. So you have CustomDbContext declared in a MVC project, so cannot be used in a referenced repository project. So the solution seems to be easy, you need to move the CustomDbContext out of the MVC project (either to repository project or any other/third project which could be referenced by both MVC and repository). In such way you will easy configure your CustomDbContext in a Startup class, as well as use this context in repositories.
3) As it comes to registering context from external library you can do it easily with MigrationsAssembly method, it will look like this:
services.AddDbContext<CustomDbContext>(options => options.UseSqlServer(
_configuration.GetConnectionString("YourConnectionStringName"),
b => b.MigrationsAssembly("YourExternalAssemblyName")));
This is an very simples project that can help you and other developers.
Generic Repository Pattern in ASP.NET Core
This is addressing your orginal issue of being unable to use migration command line tools and allow you to keep proper separation of layers.
This is a know issue (tracked here) and there are two workarounds as of now, directly taken from the EntityFramework Core documentation:
Workaround 1 - Utilize a separate startup project
Convert the class library project into an “app” project. This can either be a .NET Core app or a desktop .NET app.
Example:
{
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0-*"
}
}
}
}
}
Be sure to register the EntityFramework Tools as a project dependency and in the tools section of your project.json.
Example:
{
"dependencies": {
"Microsoft.EntityFrameworkCore.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
}
},
"tools": {
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
}
}
Finally, specify a startup project that is a “runnable app.”
Example:
dotnet ef --startup-project ../MyConsoleApplication/ migrations list
Workaround 2 - Modify your class library to be a startup application
Convert the class library project into an “app” project. This can either be a .NET Core app or a desktop .NET app.
To make the project a .NET Core App, add the “netcoreapp1.0” framework to project.json along with the other settings in the sample below:
{
"buildOptions": {
"emitEntryPoint": true
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0-*"
}
}
}
}
}
To make a desktop .NET app, ensure you project targets “net451” or newer (example “net461” also works) and ensure the build option "emitEntryPoint" is set to true.
{
"buildOptions": {
"emitEntryPoint": true
},
"frameworks": {
"net451": { }
}
}
What is the available implementation of the System.Net.IWebProxy (from System.Net.Primitives, DNX Core)? By application requirement, the only framework can be used in dnxcore50, so what is the right NuGet package that contains proxy implementations?
What is the correct way to resolve such questions? Related functionality seems to be split among dozen of packages.
Despite the name, IWebProxy implementation does not actually need to implement any proxying, it just provides information about the proxy. So, you can create your own implementation:
public class MyProxy : IWebProxy
{
public Uri GetProxy(Uri destination)
{
return new Uri("http://localhost:8888");
}
public bool IsBypassed(Uri host)
{
return false;
}
public ICredentials Credentials { get; set; }
}
There is a WebProxy class in the System.Net namespace (source here) that you can use.
Make sure your project.json file has these two lines under "dependencies"
"frameworks": {
"dotnet5.4": {
"dependencies": {
"Microsoft.Net.Http": "2.2.29",
"System.Net.Primitives": "4.0.11-beta-23516"
}
}
}