How to add service.AddDbContext in class library .NET CORE - c#

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();
}
}

Related

Mediatr Handler was not found for request of type

I come to you because I have the following problem and I need your help.
I have 2 projects as you can see in the image.
The _admin project is the main project and the _config project once compiled remains as a plugin of the _admin project (This loads all the dependencies of the config project).
In both cases I am using Mediatr and they work perfectly when I run the applications separately.
But when I compile the _config project to be run as part of the _admin project I get the following error.
Handler was not found for request of type MediatR.IRequestHandler`2[...Plugins.Configurations.Application.ConfigurationValues.Querys.GetConfigurationValuesQuery,System.Collections.Generic.IEnumerable`1[...Plugins.Configurations.Application.ConfigurationValues.Dtos.ConfigurationValueDto]]. Register your handlers with the container. See the samples in GitHub for examples.
The code you used is the following (I also tried using the class GetConfigurationValuesQueryHandler):
Plugins.Configurations.Application.DependencyInjection.cs
public static class DependencyInjection
{
public static IServiceCollection AddConfigurationApplication(this IServiceCollection services)
{
services.AddAutoMapper(Assembly.GetExecutingAssembly());
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
services.AddMediatR(Assembly.GetExecutingAssembly());
//services.AddMediatR(typeof(GetConfigurationValuesQueryHandler).Assembly);
return services;
}
}
Plugins.Configurations.Mvc.Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddBaseApplication();
services.AddConfigurationApplication();//<-- Here
services.AddBaseInfrastructure();
services.AddConfigurationInfrastructure(Configuration);
services.AddHttpContextAccessor();
services.AddHealthChecks().AddDbContextCheck<ConfigurationDbContext>();
services.AddControllersWithViews();
}
This error only occurs when the _config project acts as an _admin plugin. When I run the _config project individually it works perfectly.
Could it be that _config being an _admin plugin, the Startup.cs class of the _config project is not executed? If it were this, how could I solve it so that it executes the AddConfigurationApplication method in a dynamic way.
If not point 1. How could I solve this? without having the need to add the _config project as a direct reference in the _admin project.
In advance I thank you for the help you can give me.
services.AddMediatR(Assembly.GetExecutingAssembly());
The above code snippet is not a pure method. This method will behave differently depending on the change of the startup project.
When you choose the Admin project as the startup project, the AddConfigurationApplication method will add the Automapper classes, Validation classes and Mediatr classes in the Admin project not Configuration project.
Your problem will be resolved when you provide assembly information about the Configuration project strictly.
public static IServiceCollection AddConfigurationApplication(this IServiceCollection services)
{
Assembly configurationAppAssembly = typeof(CLASS_FROM_CONFIGURATION_PROJECT).Assembly;
...
serviceCollection.AddMediatR(configurationAppAssembly);
}
The AddMediatr extension method takes an array of assemblies, so you may want to utilize that:
var assembly1 = Assembly.GetExecutingAssembly();
var assembly2 = typeof(GetConfigurationValuesQueryHandler).Assembly;
services.AddMediatR(assembly1, assembly2);
That way it will add all your handlers from both projects.

Using Entity Framework Core 3.1 with Windows Application or Console Application

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()
{
}

Dependency Inject Blazor Version

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();
}
}

.NET Core MVC Startup equivalent

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

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 ^_^

Categories