i wan to use Dependency Injection in blazor i am using visual studio preview the latest version i want to add this code in startup.cs
services.AddSingleton<SengaltonServices>();
but i can not find startup.cs in client to inject in Razor component
For Blazor WASM you setup the DI in Program using WebAssemblyHostBuilder.Services:
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddSingleton<SengaltonServices>();
await builder.Build().RunAsync();
}
}
Related
I'm just learning Entity Framework Core 3.1. I wondering why all learning contents learn it using ASP.Net Core!! So I decide to test some of the codes on a Class Library along withConsole Application. This is my very simple class library code:
public class ApplicationDbContext : DbContext
{
private static readonly string ConnectionString = "Server=.;Database=Northwind;Trusted_Connection=True;";
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<NimaCategory> NimaCategories { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(ConnectionString);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new NimaCategoryConfig());
}
}
I faced many strange errors for creating Migration but strangest is I must write all of these line of codes to my Console Application:
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello EF Core")
}
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder => webBuilder.UseStartup<Startup>());
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
=> services.AddDbContext<ApplicationDbContext>();
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
}
}
and the problem is IHostBuilder and ConfigureWebHostDefaults are for ASP.Net Core and it's dependency injection engine. So based on the below link I change my csproj file:
IHostBuilder does not contain a definition for ConfigureWebHostDefaults
Now I can't run my console application because It's nature has changed and converted to Web project. Then I add a window application and I can't add these codes for configurations:
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(
webBuilder => webBuilder.UseStartup<Startup>());
and:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
=> services.AddDbContext<ApplicationDbContext>();
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
}
}
I have some questions about this problems:
Why EF Core is restricted to ASP.Net Core? Are all the projects in the world written with ASP.Net Core?
Does anyone have experience working with EF core along with Windows Application or Console project and help to solve the issues?
Thanks
You can use EF Core everywhere.
Make a Console application project then install these packages
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.SqlServer/3.1.9
https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Tools/3.1.9
and put your connection string in OnConfiguringMethod.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=serverName;Database=dbName;Trusted_Connection=True;MultipleActiveResultSets=True");
}
and voila you can learn ef core in console app. they just teach ef core with ASP.NET Core because of UI.
and i think Julie Lerman Teaches EF Core in Console app, you can use Pluralsight platform for EF Core tutorials.
Here are some answers, as well as what I use to get my EF Core working.
Why EF Core is restricted to ASP.Net Core? Are all the projects in the world written with ASP.Net Core?
It's not restricted to ASP.Net Core, EF Core and Core itself is simply a console application. And no all projects in the work are not build with ASP.NET Core --- However, due to it's flexibility Microsoft is dropping support for all other versions of .Net. Meaning the next Release of .Net will actually be .NetCore. If you are building for a normal .Net application, it might be better to use EF 6 instead of Core. Core just allows crossplatform capabilities.
Does anyone have experience working with EF core along with Windows Application or Console project and help to solve the issues?
Well yes, also all Core applications are Console Projects. So if you are able to do it in a windows application you are able to do it in Core.
But now I will show you what I do. I work for a company and use EF core on multiple projects, my basic formula looks like this:
Nuget Packages:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Relational
Here is the code in the Startup file. Note it will look slightly different than yours because I put my Dbcontext in a different project than my entry point.
public void ConfigureServices(IServiceCollection services)
{
// Add the SQL db conneciton
/*
AddSQLContext is just a function in a different project. Not Needed
*/
services.AddSQLContext(options => options.UseSqlServer(
// This is simply the connection stirng
Configuration.GetConnectionString("SqlConnection"),
// We add a migration assembly only if the EF core DbContext is in another project
actions => actions.MigrationsAssembly("My.Other.Project.Assembly")
));
}
My code for calling the Context is in another project. I like to keep it seperate. But you don't have to do that.
Here are the Nuget packages I use, But I think the Tools and Design are only neccecary when doing a CodeFirst approach (building Database from EF core instead of Scaffolding):
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer.Design
Microsoft.EntityFrameworkCore.Tools
public static class ServiceCollectionExtentions
{
/*
SqlContext is my own custom context similar to your [ ApplicationDbContext ]
*/
public static IServiceCollection AddSQLContext(this IServiceCollection services, Action<DbContextOptionsBuilder> options) => services
.AddDbContext<SqlContext>(options);
}
public class SqlContext : DbContext
{
public SqlContext(DbContextOptions options)
: base(options){}
...
}
The solution is very simple: just add default constructor for the ApplicationDbContext:
public ApplicationDbContext()
{
}
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
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/.
I have a class library alone in a solution. This library will be published as a NuGet package.
So, I want to add the library to my project and I have to connect startup of the project to define this:
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(Configuration["ConnectionStrings:LocalConnectionString"]));
But there is no startup in my class library project. How can I define this in the library project for my actual projects ?
Let your library expose an extension point to be able to integrate with other libraries that want to configure your library.
public static class MyExtensionPoint {
public static IServiceCollection AddMyLibraryDbContext(this IServiceCollection services, IConfiguration Configuration) {
services.AddDbContext<DataContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:LocalConnectionString"]));
return services;
}
}
That way in the main Startup you can now add your library services via the extension.
public class Startup {
public void ConfigureServices(IServiceCollection services) {
//...
services.AddMyLibraryDbContext(Configuration);
services.AddMvc();
}
}
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();
}
}