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 ^_^
Related
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.
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()
{
}
In the Startup class of my project I have the following Configure method:
private void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
loggerFactory.AddNLog();
...
}
This worked OK in .NET Core 2.2, but after upgrading to 3.0, I get the warning Method 'NLog.Extensions.Logging.ConfigureExtenstions.AddNLog' is obsolete: instead use ILoggingBuilder.AddNLog() or IHostBuilder.UseNLog().
So I tried to update the method to
private void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggingBuilder loggingBuilder)
{
...
loggingBuilder.AddNLog();
...
}
or
private void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostBuilder hostBuilder)
{
...
hostBuilder.UseNLog();
...
}
But in both cases I got a DI exception: Could not resolve a service of type {Microsoft.Extensions.Logging.ILoggingBuilder/Microsoft.Extensions.Hosting.IHostBuilder} for the parameter {loggingBuilder/hostBuilder} of method 'Configure' on type 'MyProject.Startup'.
I could not find any viable source on how to change the NLog configuration fro .NET Core 3.0 and there is nothing about logging in the official Microsoft guide. Does anyone know how to solve this issue?
With ASP.NET Core 2+, the pattern to bootstrap an ASP.NET Core site has changed. NLog adapts that. With the latest version of NLog.Extensions.Logging.ConfigureExtenstions, the old methods are made obsolete.
For example, ASP.NET Core nowadays uses a CreateHostBuilder.
I would recommend to follow:
Migrate from ASP.NET Core 2.2 to 3.0 | Microsoft Docs
And then: Getting started with ASP.NET Core 3 ยท NLog/NLog Wiki
What is the equivalent of HttpRuntime.AppDomainAppPath in .NET Core? I moved a project from ASP.NET to core, and a few Libraries are not included (Such as System.Web). Here is a small example:
sb.AppendLine("\"New Path\": \"" + newFile.FullName.Replace(HttpRuntime.AppDomainAppPath, "/");
Any help would be appreciated, thanks
The IWebHostEnvironment interface provides information about the environment including the base path (ContentRootPath). You can get an instance using dependency injection.
public class Startup
{
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// env.ContentRootPath;
}
}
EDIT: Previous version of this answer was using now obsolete IHostingEnvironment. Consider using it with .net core version 2.2 or earlier. Credit for pointing this out goes to #Jack Miller.
Environment
I am writing a Web API using ASP.NET 5 1.0.0-rc1-update1 and Visual Studio Code on Mac. I scaffolded the default Web API app using Yeoman generator-aspnet. I am using DNX Mono to run the app via the default web command.
Missing output from System.Diagnostics.Debug
I want to log debug output to Terminal or to Visual Studio Code Output. I tried to do so using System.Diagnostics.Debug class, but the code above produces zero output.
System.Disagnostics.Debug.WriteLine("This is your message");
What am I missing? Do I need to declare DEBUG symbol somewhere to see debug output?
Missing from Microsoft.Extensions.Logging.Debug.DebugLogger
I also tried DebugLogger provided by Microsoft.Extensions.Logging.Debug package, but with no luck. Which I guess makes sense since it's a wrapper on top of System.Diagnostics.Debug. My Startup.cs configuration looked like:
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddDebug(LogLevel.Debug);
// Configuring other middleware
}
I createdILogger in my controller as follows:
public ProductsController(ILoggerFactory logFactory)
{
_logger = logFactory.CreateLogger(nameof(ProductsController));
}
And used ILogger as follows:
public IActionResult Ping()
{
_logger.LogDebug("Debug message");
}
You have to add a TraceListener,
TextWriterTraceListener writer = new TextWriterTraceListener(System.Console.Out);
Debug.Listeners.Add(writer);
Also, set the DEBUG flag in the Visual Studio project properties
While #Martin answers fixes the issue completely, I wanted to elaborate on logging Debug output in ASP.NET 5 a little.
Using System.Diagnostics.Debug
System.Diagnostics.Debug.Listeners has only System.Diagnostics.DefaultTraceListener by default which doesn't seem to write to console. If you add a console listener like #Martin suggested in his answer, both System.Diagnostics.Debug and Microsoft.Extensions.Logging.Debug.DebugLogger messages will start showing up in the console. For the latter to work, you also need to specify DEBUG symbol for your build.
It is worth noting that System.Diagnostics.Debug.Listeners property and System.Diagnostics.TextWriterTraceListener are not available in Core CLR 5.0.
Using Microsoft.Extensions.Logging.Console.ConsoleLogger
Initially, I tried the recommended way to log messages to console in ASP.NET 5 is the new Microsoft.Extensions.Logging API. My loggerFactory was configured as follows:
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(LogLevel.Debug);
// Configuring other middleware
}
And I was trying to log debug messages using _logger.LogDebug("Debug message");. It didn't work and led me to try System.Diagnostics.Debug instead.
The gotcha was that ASP.NET 5 v1.0.0-rc1-update1 uses ILoggerFactory.MinimumLevel in addition to the log level provided when configuring a specific logger (e.g. loggerFactory.AddConsole(LogLevel.Debug)). As described here
The minimum level indicates that any logs below the specified minimum
will not even be seen by loggers, no matter how hard they try.
This value defaults to Verbose which in 1.0.0-rc1-update1 is higher that Debug. Thus, unless you set ILoggerFactory.MinimumLevel to LogLevel.Debug, you won't see any debug output. See a similar issues reported here.
Seems a little confusing, right? Good news is that ASP.NET 5 team has already fixed this "issue" and removed ILoggerFactory.MinimumLevel property whatsoever in 1.0.0-rc2.
If you are still using 1.0.0-rc1-update1, then you need to configure logging as follows:
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
// This line can be removed if you are using 1.0.0-rc2 or higher
loggerFactory.MinimumLevel = LogLevel.Debug;
loggerFactory.AddConsole(LogLevel.Debug);
// Configuring other middleware
}