.NET Core MVC Startup equivalent - c#

I am wondering is, since I would like to implement dependency injection container for my web application (MVC) controllers. In .NET Core framework, I used to have a Startup.cs file inside the project which was used for adding transients and dependency injections to the container, also for DbContext:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<LibraryContext>();
services.AddTransient<IGetBooksCommand, EfGetBooksCommand>();
}
I would like to know how could I achieve this in the full .NET Framework.

Prior to .Net Core, there is no built-in support for dependency injection the only way to get it was through the use of third-party frameworks such as Autofac, Castle Windsor, Unity, Ninject ..etc
You can check any of these frameworks and use them in your project.

.Net core Mvc supports built in dependency injection and it is capable of injecting dependencies in the controllers. So dependency registered as below can be used in controller
services.AddTransient<IGetBooksCommand, EfGetBooksCommand>();
However built in dependency injection functionality can be replaced by more mature DI frameworks. And that is very simple as below is the example for using Autofac
public IServiceProvider ConfigureServices(IServiceCollection services) {
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<EfGetBooksCommand>().As<IGetBooksCommand>();
var container = builder.Build();
return new AutofacServiceProvider(container);
}
ConfigureServices method now returns IServiceProvider instead of void. And dependencies will now be resolved using Autofac.
ref :
Dependency injection into controllers in ASP.NET Core
.Net Core Dependency Injection

Related

Use Serilog with Microsoft.Extensions.Logging.ILogger

I've created a .NET Core 3.1 project using a Host, the IoC container with IServiceCollection and implemented logging allover the place using the ILogger<T> interface from Microsoft.Extensions.Logging. I now need to implement more advanced logging and decided to use Serilog.
I assumed that it would be a breeze to switch from .NET built-in loggers to Serilog. But to my surprise, Serilog is using it's own ILogger interface - bummer! So now I needed to update ALL places to use Serilog ILogger, or to implement Serilog with a .NET Core ILogger<T> interface.
My question is - is it really not possible to use Serilog with the ILogger interface in Microsoft.Extensions.Logging? Would be so much smarter!
In the Serilog.Extensions.Logging assembly there is a extension method on IloggingBuilder called AddSerilog (it's in the Serilog namespace) that will allow you to use Serilog for logging. For example:
.NET Core 2.2 and earlier (using WebHost):
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddSerilog();
});
.NET Core 3.1 and later (using generic Host for either web or console apps):
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>()})
.UseSerilog();
Now the ILogger and ILogger<> implementation will call into Serilog.
For .NET 6 and later
using Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((ctx, lc) => lc
.WriteTo.Console()
.ReadFrom.Configuration(ctx.Configuration));
Reference: Here

Using Unity instead of ASP.Net Core DI IServiceCollection

More and more .NET Core libraries is bound to IServiceCollection. In example, I want to use HttpClientFactory described here in my NET Framework 4.7.1. desktop application. My application is using Unity IoC. I referenced Microsoft.Extensions.Http as NuGet.
But there is a problem: new ASP.Net Core components are bound to Microsoft DI framework for .NetCore - IServiceCollection. In example, registration of HttpClientFactory is here:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
}
I was going deeper into MS code and wanted to manually register corresponding interfaces and classes to Unity. This is how services are registered by IServiceCollection:
services.TryAddTransient<HttpMessageHandlerBuilder, DefaultHttpMessageHandlerBuilder>();
services.TryAddSingleton<IHttpClientFactory, DefaultHttpClientFactory>();
This would be no problem to move this to Unity IoC, but I am stucked when I want to register DefaultHttpMessageHandlerBuilder and DefaultHttpClientFactory which have internal visibility. So they are not available for registration outside of MS code.
Do I have any chance how to resolve this situation?
Edit 7.12.2022: Unity is now deprecated, so do not use it for new projects. I replaced it with Autofac.
Based on #davidfowl answer, I have used his second solution and completed code:
These packages need to be referenced from my project (snippet from .csproj):
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http">
<Version>2.1.1</Version>
</PackageReference>
<PackageReference Include="Unity.Microsoft.DependencyInjection">
<Version>2.0.10</Version>
</PackageReference>
</ItemGroup>
And here is the test that services from ServiceCollection can be resolved from Unity container:
using System;
using System.Linq;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Unity;
using Unity.Microsoft.DependencyInjection;
using Xunit;
namespace FunctionalTests
{
public class UnityWithHttpClientFactoryTest
{
/// <summary>
/// Integration of Unity container with MS ServiceCollection test
/// </summary>
[Fact]
public void HttpClientCanBeCreatedByUnity()
{
UnityContainer unityContainer = new UnityContainer();
ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient("Google", (c) =>
{
c.BaseAddress = new Uri("https://google.com/");
});
serviceCollection.BuildServiceProvider(unityContainer);
Assert.True(unityContainer.IsRegistered<IHttpClientFactory>());
IHttpClientFactory clientFactory = unityContainer.Resolve<IHttpClientFactory>();
HttpClient httpClient = clientFactory.CreateClient("Google");
Assert.NotNull(httpClient);
Assert.Equal("https://google.com/", httpClient.BaseAddress.ToString());
}
}
}
You have 2 options:
Create a ServiceCollection, add the factory and then call BuildServiceProvider and resolve the IHttpClientFactory. There's an uber sample here https://github.com/aspnet/HttpClientFactory/blob/64ed5889635b07b61923ed5fd9c8b69c997deac0/samples/HttpClientFactorySample/Program.cs#L21.
Use the unity adapter for IServiceCollection https://www.nuget.org/packages/Unity.Microsoft.DependencyInjection/.

Using IHostingEnvironment in .NetCore library

I build an ASP.NET Core application and I create a .NET Core Class Library for unit testing.
I want to use IHostingEnvironment in my library (to get physical path of a file), so I've added this line to Startup.cs of my ASP.NET Core application :
services.AddSingleton<IHostingEnvironment>();
In the Library I've added reference to my ASP.NET application, and in my class I wrote this:
private IHostingEnvironment _env;
public Class1(IHostingEnvironment env)
{
_env = env;
}
But when I run it then it gives me this error:
the following constructor parameters did not have matching fixture date : IHostingEnvironment env
What is the problem?
How can I use it in .NET Core Class Library?
EDIT: I tried to use this too:
IServiceCollection services = new ServiceCollection();
services.AddSingleton<IHostingEnvironment>();
IServiceProvider provider = services.BuildServiceProvider();
IHostingEnvironment service = provider.GetService<IHostingEnvironment>();
var p = service.WebRootPath;
The last one gives me this error:
Cannot instantiate implementation type 'Microsoft.AspNetCore.Hosting.IHostingEnvironment' for service type 'Microsoft.AspNetCore.Hosting.IHostingEnvironment'
Note: services.AddSingleton<IHostingEnvironment>(); means you are registering IHostingEnvironment as an implementation for IHostingEnvironment in a singleton scope (always reuse).
Since you can't create an instance of an interface, you get this error.
solution
define the class you want to be created (that implements IHostingEnvironment), eg:
services.AddSingleton<IHostingEnvironment>(new HostingEnvironment());
Behind the scenes dotnet core (Hosting nuget package)
In the WebHostBuilder The first row in the constructor is:
this._hostingEnvironment = (IHostingEnvironment) new HostingEnvironment();
This hosting environment is later filled with more settings, by the webhost builder.
You should look at their github page or decompile the sources: https://github.com/aspnet/Hosting
Note: Most of the properties/settings of HostingEnvironment are set on Build() method of the WebHostBuilder. If you want to moq/test this yourself you should set these properties yourself or just also include the WebHostBuilder in your test.
For my .net class library all I had to do is install the following nuget package for version 2.1.0:
Microsoft.AspNetCore.Hosting.Abstractions
https://www.nuget.org/packages/Microsoft.AspNetCore.Hosting.Abstractions/
and then I just injected IHostingEnvironment into my constructor.
I didn't even need to modify Startup.cs
This worked for me in both .net core class library and console application:
Using references,
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
Adding DI registration,
services.AddSingleton<IHostingEnvironment, HostingEnvironment>();
A note for reference as I ended up here.
If you target netstandard (netstandard2.0) in your class library, add Microsoft.Extensions.Hosting.Abstractions from NuGet to get the IHostingEnvironment interface without any implementations.
I know question specifies .net core, anyways.. might help out those being where I were.
Try this, its simple enough
private IHostEnvironment env;
public Startup(IHostEnvironment env)
{
this.env = env;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostEnvironment>(env);
}
then you can use it in your class
private IHostingEnvironment _env;
public Class1(IHostingEnvironment env)
{
_env = env;
}
hope it does the job ^_^

Ninject in .NET Core

I am trying to install Ninject 3.3.2 in .NET Core, Released in May 2016. I got an error: The dependency Ninject 3.2.2 does not support framework .NETCoreApp, Version=v1.0.
Does anybody had similar problem, and is there any solution for this?
Ninject 3.3.0 was released September 26th 2017 and now targets .NET Standard 2.0 and thus also runs on .NET Core 2.0.
From the course of things (see issues/discussions on GitHub) it seems likely that some of the changes in the 4.0-beta will be reverted. I would not expected a 4.0 final shortly. Hence I would advise to go with the current version 3 release.
Just wanted to add; while both of the previous answers are correct in that ASP.Net core does provide built in dependency injection, it is NOT sufficient for more advanced scenarios. As it does not support a whole host of features that Ninject, AutoFac, Unity, or StructureMap supports.
At present, the only DI libraries that I am aware of that fully supports .net core are AutoFac and now Unity as well. It is very simple to add this in. The only thing you need to do to replace the built in DI is as follows. This example is for AutoFac but its almost identical for Unity it looks like.
First, replace the void on ConfigureServices in startup.cs with an IServiceProvider (dependency from AutoFac) like so:
public IServiceProvider ConfigureServices(IServiceCollection services)
Then create a container builder, build and resolve an IServiceProvider from ConfigureServices:
var builder = new ContainerBuilder();
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
I have a wrapper around the this second part that allows you to dynamically load and build different configurations using AutoFac modules, that I might be convinced to upload to GitHub or something if there is any interest.
Ninject does not support .NET Core. You can check it's website to be sure if there is no version that supports it.
ASP.NET Core has its own Dependency Injection container build in. See here.
Ninject does not support .Net Core, instead of this we can use dependency injection of .net core. following are the steps to implement.
Go to startup.cs at public void
ConfigureServices(IServiceCollection services)
Add services.AddTransient<Interface, Class>();
Go to the controller where you want to apply dependency injection.
Create a global private Interface _propertyName;
Pass the interface type variable to the constructor like
public Constructor(Interface name)
{
_propertyName= name;
}
Now you can access the members of the class through _propertyName.

Convention based binding in ASP.NET 5 / MVC 6

It is possible to register dependencies manually:
services.AddTransient<IEmailService, EmailService>();
services.AddTransient<ISmsService, SmsService>();
When there are too much dependencies, it becomes difficult to register all dependencies manually.
What is the best way to implement a convention based binding in MVC 6 (beta 7)?
P.S. In previous projects I used Ninject with ninject.extensions.conventions. But I can't find a Ninject adapter for MVC 6.
No, there is no support for batch registration in the ASP.NET 5 built-in DI library. As a matter of fact, there are many features that are needed to build large SOLID applications, but are not included in the built-in DI library.
The included ASP.NET DI library is primarily meant to extend the ASP.NET system itself. For your application, you are best off using one of the mature DI libraries out there, and keep your configuration separate from the configuration that used to configure the ASP.NET system itself.
This removes the need for an adapter.
An MVC 6 adapter exists, but seeing as ASP.net 5 is still in Release candidate, it isn't yet available on NuGet so you'll need to add the ASP.NET 5 "master" branch feed from MyGet to your Visual Studio NuGet package sources.
A walkthrough to do this is available here:
http://www.martinsteel.co.uk/blog/2015/using-ninject-with-mvc6/
If it is still interesting for someone.
This is my solution of the issue with Autofac. It is required Autofac and Autofac.Extensions.DependencyInjection NuGet packages.
// At Startup:
using Autofac;
using Autofac.Extensions.DependencyInjection;
// ...
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Some middleware
services.AddMvc();
// Not-conventional "manual" bindings
services.AddSingleton<IMySpecificService, SuperService>();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule(new MyConventionModule());
containerBuilder.Populate(services);
var autofacContainer = containerBuilder.Build();
return autofacContainer.Resolve<IServiceProvider>();
}
This is the convention module:
using Autofac;
using System.Reflection;
using Module = Autofac.Module;
// ...
public class MyConventionModule : Module
{
protected override void Load(ContainerBuilder builder)
{
var assemblies = new []
{
typeof(MyConventionModule).GetTypeInfo().Assembly,
typeof(ISomeAssemblyMarker).GetTypeInfo().Assembly,
typeof(ISomeOtherAssemblyMarker).GetTypeInfo().Assembly
};
builder.RegisterAssemblyTypes(assemblies)
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
}
}

Categories