.NET Core 2, DI, configuration file - asp.net-core

I am studying .NET Core 2 and I don't like how DI is managed... on the web I read something like the following steps:
creating an interface like IService
creating an implementation for IService
adding it on the scope of .NET Core container into Startup.Configuration method resolving the dependency.
finally I can use it into the constructor of my custom controller.
In .NET classic I used a dedicated XML configuration file to manage dependencies: can I use a configuration file (JSON or XML are the same) to do the same I would have to do into Startup.Configuration method?
...otherwise someone can explain me the reason why configure the services into Startup.Configuration is the better way?
Thanks so much...

First, to answer your question "can I use a configuration file", the answer is emphatically "yes". Why shouldn't you is answered later, but for now, here's a poor man's version of how you might do this by adding to your appsettings.json file. Note that this code is not optimal, but is designed to show you how you could implement this solution.
Let's start with some classes to hold the data:
public class ServicesConfiguration
{
public IEnumerable<ServiceItem> Singleton { get; set; }
public IEnumerable<ServiceItem> Transient { get; set; }
}
public class ServiceItem
{
public string Service { get; set; }
public string Implementation { get; set; }
}
Now add a section to your JSON file, you may even want to keep this file external to the main config, but that's an implementation detail I will leave up to you:
{
//snip main config....
"Services" : {
"Singleton": [
{
"Service": "YourNamespace.IFoo1, YourNamespace",
"Implementation": "YourNamespace.Foo1, YourNamespace"
},
{
"Service": "YourNamespace.IFoo2, YourNamespace",
"Implementation": "YourNamespace.Foo2, YourNamespace"
}
],
"Transient": [
{
"Service": "YourNamespace.IBar1, YourNamespace",
"Implementation": "YourNamespace.Bar1, YourNamespace"
}
]
}
}
And now an extension method to configure it all:
public static IServiceCollection AddFromConfigurationFile(this IServiceCollection services,
IConfigurationSection configuration)
{
var servicesConfiguration = configuration.Get<ServicesConfiguration>();
foreach(var service in servicesConfiguration.Singleton)
{
services.AddSingleton(Type.GetType(service.Service), Type.GetType(service.Implementation));
}
foreach(var service in servicesConfiguration.Transient)
{
services.AddTransient(Type.GetType(service.Service), Type.GetType(service.Implementation));
}
//Other scopes here...
return services;
}
And call it in ConifigureServices like this:
services.AddFromConfigurationFile(Configuration.GetSection("Services"));
So, nice and simple right? Why shouldn't you do this? A few ideas off the top of my head:
Why change how almost all DI implementations work? If it ain't broke, why fix it? Just because you are used to a particular method, doesn't mean it's a good idea.
Type safety: You lose compile time checking of the types you specify in the configuration file.
Security: Having this in a config file would let someone change the implementation to a class of their own choice.
I'm sure there are more, but... it's your app!

Related

Simplified approach to IOptions<T>

I am trying to get a .NET Framework class library in line with an ASP.NET Core 2.1 application while using builtin DI mechanism. Now, I created a config class and added appropriate section to appsettings.json:
services.Configure<MyConfig>(Configuration.GetSection("MyConfiguration"));
services.AddScoped<MyService>();
In class lib:
public class MyService
{
private readonly MyConfig _config;
public MyService(IOptions<MyConfig> config)
{
_config = config.Value;
}
}
However, in order to build this classlib I have to add Microsoft.Extensions.Options NuGet package. The problem is that package carries a hell of a lot of dependencies which seem rather excessive to add just for the sake of one interface.
So, the question ultimately is, "is there another approach I can take to configure a DI service located in .NET Framework class library which is not dependency heavy?
Check this article written by Filip Wojcieszyn.
https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/
You add extension method:
public static class ServiceCollectionExtensions
{
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig();
configuration.Bind(config);
services.AddSingleton(config);
return config;
}
}
Apply it in configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigurePOCO<MySettings>(Configuration.GetSection("MySettings"));
}
And then use it:
public class DummyService
{
public DummyService(MySettings settings)
{
//do stuff
}
}
I bumped into this problem a little while ago, if you can even call it a problem really. I think we all tend to get a little shell-shocked when we see a dependency list like that. But as #Tseng mentioned, it's really not a big deal to include a bunch of extra tiny assemblies (they'll be included in the bin already anyways by virtue of a reference in another project). But I will admit it's annoying to have to include them just for the options interface.
How I solved it was by resolving the service dependency in startup.cs and adjust the service's constructor accordingly:
services.AddTransient<MyService>(Configuration.GetConfiguration("MyConfiguration"));
If you don't care about whatever IOptions provides you, why not just inject IConfiguration into your service?
public class MyService
{
private readonly IConfiguration _config;
public MyService(IConfiguration config)
{
_config = config;
}
public void DoSomething()
{
var value = _config["SomeKey"];
// doing something
}
}

Automapper unmaped property found

Hi guys I have found a very strange thing and I want to ask you about that.
I am using AutoMaper in my .dotnet core Web Api project. And during mapping i get the AutoMapperConfigurationException.
Here is a reference I am currently using:
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="5.0.1" />
I have a Blog entity class :
public class BlogEntity
{
public string Title { get; set; }
public int BlogEntityId { get; set; }
public List<Post> Posts { get; set; }
}
And my DTO class which I am using to create a new blank blog entity:
public class BlogCreateDto
{
public string Title { get; set; }
}
Here is my mapper profile:
public class BlogMappingProfile : Profile
{
public BlogMappingProfile()
{
CreateMap<BlogCreateDto,BlogEntity>();
}
}
Here is a line that i used in Startup.cs to set up automapper
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAutoMapper();
....
Here is a message that i get in exception:
Unmapped members were found. Review the types and members below.\nAdd
a custom mapping expression, ignore, add a custom resolver, or modify
the source/destination type\nFor no matching constructor, add a no-arg
ctor, add optional arguments, or map all of the constructor
parameters\n==========================================================\r\nAutoMapper created this type map for you, but your types cannot be mapped using
the current configuration.
I tried a lot of things, Ignore of members, constructors, inheritance etc and none of them didn't work. I resolved it by adding configuration in Startup.cs and adding my automapper profile by hand like this:
services.AddAutoMapper(cfg => cfg.AddProfile(new BlogMappingProfile()));
It is working but still i have a confusion about that i miss something and didn't do it in properly way. What I am doing wrong ? Or maybe I miss something in configuration?
You have to provide the assemblies or the assembly, where your profiles are located. The extension is using assembly-scanning to find given types to register. If your profiles are in the same project as your startup class, you can do the following
services.AddAutoMapper(typeof(Startup).Assembly);
You will also need that to automatically register all other AutoMapper types like IValueResolver<,,> and ITypeConverter<,> for instance.
You can find the registration process of that extension here.
In my case, I've forgotten to add the Profile file into the AutoMapperConfig class
something like this
public static void Configure(MapperConfigurationExpression config)
{
config.AddProfile<SettingsProfile>();
}

ASP.NET Core MVC App Settings

I'm trying to use configuration variables on my ASP.NET Core MVC project.
This is where I've got so far:
Created an appsettings.json
Created an AppSettings class
Now I'm trying to inject it on the ConfigureServices, but my Configuration class is either not recognized or when using the full reference: "Microsoft.Extensions.Configuration" the GetSection Method is not recognized, i.e.
Configuration class not being recognized
GetSection method not being recognized
Any ideas on how to use this?
The whole configuration approach in .NET Core is really flexible, but not at all obvious at the beginning. It's probably easiest to explain with an example:
Assuming an appsettings.json file that looks like this:
{
"option1": "value1_from_json",
"ConnectionStrings": {
"DefaultConnection": "Server=,\\SQL2016DEV;Database=DBName;Trusted_Connection=True"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
To get the data from appsettings.json file you first need to set up a ConfigurationBuilder in Startup.cs as follows:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsDevelopment())
{
// For more details on using the user secret store see https://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
You can then access the configuration directly, but it's neater to create Options classes to hold that data, which you can then have injected into your controller or other classes. Each of those options classes represent a different section of the appsettings.json file.
In this code the connections strings are loaded into a ConnectionStringSettings class and the other option is loaded into a MyOptions class. The .GetSection method gets a particular part of the appsettings.json file. Again, this is in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
... other code
// Register the IConfiguration instance which MyOptions binds against.
services.AddOptions();
// Load the data from the 'root' of the json file
services.Configure<MyOptions>(Configuration);
// load the data from the 'ConnectionStrings' section of the json file
var connStringSettings = Configuration.GetSection("ConnectionStrings");
services.Configure<ConnectionStringSettings>(connStringSettings);
These are the classes that the settings data are loaded into. Note how the property names pair up with the settings in the json file:
public class MyOptions
{
public string Option1 { get; set; }
}
public class ConnectionStringSettings
{
public string DefaultConnection { get; set; }
}
Finally, you can then access those settings by injecting an OptionsAccessor into the controller as follows:
private readonly MyOptions _myOptions;
public HomeController(IOptions<MyOptions > optionsAccessor)
{
_myOptions = optionsAccessor.Value;
var valueOfOpt1 = _myOptions.Option1;
}
Generally, the whole configurations settings process is pretty different in Core. Thomas Ardal has a good explanation of it on his site here: http://thomasardal.com/appsettings-in-asp-net-core/
There's also a more detailed explanation of Configuration in ASP.NET Core in the Microsoft documentation.
NB: This has all evolved a bit in Core 2, I need to revisit some of the answer above, but in the meantime this Coding Blast entry by Ibrahim Ĺ uta is an excellent introduction with plenty of examples.
NB No. 2: There are a number of configuration mistakes that are easy to make with the above, have a look at this answer if it doesn't behave for you.
tomRedox 's answer was highly helpful - Thanks.
Also, I've changed the following references to the following versions, to get it working.
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.2",
"Microsoft.Extensions.Configuration.Json": "1.1.1"

Calling WCF service with parameter

I am developing a SharePoint addin which has a SharePoint-hosted part and a provider-hosted part. In my provider hosted part, I have a couple of services that install a couple of things like Taxonomy and Search. I use C# CSOM for this. This is the only purpose of the provider-hosted part. When the addin is installed, a AppInstalled Event Triggers which calls a remote event receiver. This remote event receiver should then call my WCF services one by one.
Now to my actual question: I currently use this approach for consuming my services:
var taxBinding = new BasicHttpBinding();
var taxEndpoint = new EndpointAddress(remoteUrl.ToString() + "/Services/TaxonomySetupService.svc");
var taxChannelFactory = new ChannelFactory<ISetupService>(taxBinding, taxEndpoint);
ISetupService taxClient = null;
try
{
taxClient = taxChannelFactory.CreateChannel();
taxClient.SetAppWebUrl(appWebUrl.ToString());
if (!taxClient.IsInstalled())
taxClient.Install();
string logs = taxClient.GetLogs();
((ICommunicationObject)taxClient).Close();
}
catch (Exception ex)
{
if (taxClient != null)
{
((ICommunicationObject)taxClient).Abort();
}
}
ISetupService:
[ServiceContract]
public interface ISetupService
{
string OpenText { get; }
string DoneText { get; }
string AppWebUrl { get; set; }
[OperationContract]
bool IsInstalled();
[OperationContract]
void SetLogComponent(LogList logList);
[OperationContract]
void SetAppWebUrl(string url);
[OperationContract]
void WriteToLog(string message);
[OperationContract]
string GetLogs();
[OperationContract]
void Install();
}
My solution doesn't have to follow this approach though so I am looking for something better. Specifically, I need to pass a ClientContext object into my ISetupService constructor. What would be the simplest approach here?
Option 1 - Lazy Injectable property
Why in the constructor? Why not have a Lazy Injectable property?
internal IClientContext Context
{
get { return _Context ?? (_Context = SomeStaticHelper.Context); }
set { _Context = value; } // Allows for replacing IContext for unit tests
} private IClientContext _Context;
public class SomeStaticHelper
{
public static IContext Context { get; set; } // Set this in global.asax
}
Pro: No additional library
Pro: Your can replace IContext in Unit Tests easily (use InternalsVisibleTo)
Con: Class is coupled to SomeStaticHelper for compile.
Con: Doing this for one class is nice, but doing this for 100 classes is not so nice.
Option 2 - Dependency Injection
Or you could use straight up dependency injection, such as Autofac.
http://docs.autofac.org/en/latest/getting-started/
Pro: The class is decoupled and the dependency is injected.
Pro: If you have many classes that need dependency injection, this is the way to go because the overhead is now a couple class files instead of a property in every class file.
Con: You have to add a framework to your code.
Con: You now need more code and other objects to configure the dependency injection.
Use option 1 for small projects that have little need for dependency injection. I think this is the simplest approach here.
Use option 2 for large projects that use DI all the time.

MEF example in Silverlight 4

Although there are many examples of Silverlight projects using MEF (Managed Extensibility Framework), since the System.ComponentModel.Composition.Packaging.Toolkit package was removed in the version that is shipped inside Silverlight 4, these projects are away from helping to run some basic MEF example.
Some tutorials using the newer API will be very beneficial.
Thanks.
Although I can't point you in the direction of a concrete example, it's quite trivial to start composing parts of your Silverlight 4 application. Given the example:
public partial class MainPage : UserControl, IContext
{
[ImportMany]
public IEnumerable<IPlugin> Plugins { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
Plugins.First().Run(this);
}
public void ShowMessage(string message)
{
textBox1.Text = message;
}
}
public interface IContext
{
void ShowMessage(string message);
}
public interface IPlugin
{
void Run(IContext context);
}
[Export(typeof(IPlugin))]
public class SamplePlugin : IPlugin
{
public void Run(IContext context)
{
context.ShowMessage("Hello World");
}
}
The CompositionInitializer type provides SatisfyImports methods which action a default CompositionContainer which is plugged into a catalog that reads parts from your deployed XAP files. If you want more fine grained control over how the catalog is created, you can always create your own CompositionContainer.
Are there any particular aspects of MEF with Silverlight you are looking for advice on?
I wrote a blog post how you can implement MEF into you Silverlight applictaion see
http://www.arrangeactassert.com/solid-design-principles-using-mef-in-silverlight-and-wpf/
I think this is what you are after.