I'd like to access IWebHostEnvironment.WebRootPath anywhere in the asp.net core mvc application. For instance, some random class deep in the class hierarchy. Is there a static class or some other method to do so?
I am aware that I can inject IWebHostEnvironment or that I can cache the value on the startup of the application. My question is strictly about accessing it without these methods.
I am aware that I can inject IWebHostEnvironment or that I can cache the value on the startup of the application. My question is strictly about accessing it without these methods.
No, you cannot. There's no static built in here with access to this information. You can create your own though.
You can achieve this y doing the following
In your Shared project or common project which is reference by the Web project add the below interface
public interface IApplicationContext
{
public string BaseUrl { get; }
}
Then, in the web project add below code
public sealed class ApplicationContext : IApplicationContext
{
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IHttpContextAccessor _httpContextAccessor;
public ApplicationContext(IWebHostEnvironment webHostEnvironment, IHttpContextAccessor httpContextAccessor)
{
_webHostEnvironment = webHostEnvironment;
_httpContextAccessor = httpContextAccessor;
}
public string BaseUrl
{
get
{
var baseUrl = _webHostEnvironment.IsDevelopment() ? AppConstants.BaseUrl.FELocalHostBaseUrl :
_httpContextAccessor.HttpContext?.Request.BaseUrl();
return baseUrl!;
}
}
}
Then, in you need to configure the dependency injection in your Startup.cs or any where that you configure DI as below
services.AddHttpContextAccessor();
services.AddScoped<IApplicationContext, ApplicationContext>();
Then you can inject the IApplicationContext in any service class constructor and access the baseUrl like below
public sealed class SecurityService
{
private readonly IApplicationContext _applicationContext;
public SecurityService(IApplicationContext applicationContext)
{
_applicationContext = applicationContext;
}
public async Task<ResponseResult> SendResetPasswordEmail(ForgotPasswordModel forgotPasswordModel, CancellationToken cancellationToken)
{
var baseUrl = _applicationContext.BaseUrl;
return new ResponseResult();
}
}
Related
Using Asp.Net Core we can make use of Dependency Injection in controllers/repositories.
However, I wish do do some logging in my Entity Class.
class Person
{
private ILogger<Person> _logger;
private List<Pets> pets;
public Person(ILogger<Person> logger)
{
_logger = logger;
}
public bool HasCat()
{
_logger.LogTrace("Checking to see if person has a cat.");
// logic to determine cat ownership
hasCat = true;
return hasCat;
}
}
When the Person class is instantiated by EntityFramework it does not attempt to inject any dependencies.
Can I force this? Am i going about it in completely the wrong way?
Ultimatley I just want to be able to use logging consistently throughout the application.
Thanks,
It is possible but I don't recommend it because I agree with commenters that logging belongs in your services and controllers.
EF Core 2.1 allows injecting the DbContext into a private constructor that EF will invoke. See the official docs.
First you need to expose a LoggerFactory property in your DbContext class.
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options, ILoggerFactory loggerFactory = null)
{
LoggerFactory = loggerFactory;
}
public ILoggerFactory LoggerFactory { get; }
}
Then you can inject the DbContext into a private constructor in your entity class.
public class Person
{
private readonly ILogger _logger;
public Person() { } // normal public constructor
private Person(MyDbContext db) // private constructor that EF will invoke
{
_logger = db.LoggerFactory?.CreateLogger<Person>();
}
public bool HasCat()
{
_logger?.LogTrace("Check has cat");
return true;
}
}
I am using SimpleInjector for my DI in Mvc Core and I have a class that accepts ISession at the constructor.
public SessionAppAdminAuthorization(ISession session)
I need to register this at the DI configuration in StartUp.Configure method but I don't know how the get the scoped session variable.
container.Register<IAppAdminAuthorization>(() => {
return new SessionAppAdminAuthorization([I Need the ISession]); },
Lifestyle.Scoped);
ASP.NET Core's ISession can be accessed through the HttpContext.Session property. Since HttpContext is runtime data, the Session is as well. Runtime data should not be injected into your components' constructors, so your SessionAppAdminAuthorization should not depend on ISession directly.
The simplest fix is to let SessionAppAdminAuthorization depend on IHttpContextAccessor instead and call IHttpContextAccessor.HttpContext.Session later on. Example:
public class SessionAppAdminAuthorization : IAppAdminAuthorization
{
private readonly IHttpContextAccessor accessor;
public SessionAppAdminAuthorization(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public void DoSomethingUseful() {
if (this.accessor.HttpContext.Session.GetBoolean("IsAdmin")) {
// ...
} else {
// ...
}
}
}
Now you can make the registrations as follows:
public void ConfigureServices(IServiceCollection services)
{
// You need to register IHttpContextAccessor.
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment e, ILoggerFactory f)
{
container.RegisterSingleton(
app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
container.Register<IAppAdminAuthorization, SessionAppAdminAuthorization>();
// ...
}
Although this will effectively solve your problem, you might want to take it up one step. In general it's better to hide framework components and abstractions like IHttpContextAccessor, HttpContext and ISession from application components. Instead the Dependency Inversion Principle guides us towards application-specific abstractions implemented by adapters that allow translating these application-specific calls onto framework components. For instance:
// Application-specific abstraction (part of your application's core layer)
public interface IUserContext
{
bool IsAdmin { get; }
}
// Adapter implementation (placed in the Composition Root of your web app)
public class AspNetSessionUserContextAdapter : IUserContext
{
private readonly IHttpContextAccessor accessor;
public AspNetSessionUserContextAdapter(IHttpContextAccessor accessor) {
this.accessor = accessor;
}
public bool IsAdmin => this.accessor.HttpContext.Session.GetBoolean("IsAdmin");
}
// Improved version of SessionAppAdminAuthorization
public class SessionAppAdminAuthorization : IAppAdminAuthorization
{
private readonly IUserContext userContext;
// This class can now be moved to the business layer, since there's no
// more dependency on ASP.NET.
public SessionAppAdminAuthorization(IUserContext userContext) {
this.userContext = userContext;
}
public void DoSomethingUseful() {
if (this.userContext.IsAdmin) {
// ...
} else {
// ...
}
}
}
Registration:
public void Configure(IApplicationBuilder app, IHostingEnvironment e, ILoggerFactory f)
{
var accesr = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
container.RegisterSingleton<IUserContext>(new AspNetSessionUserContextAdapter(accesr));
container.Register<IAppAdminAuthorization, SessionAppAdminAuthorization>();
// ...
}
I have an ASP.NET Core 1.0 Solution with the following project structure:
Web App (ASP.NET MVC6)
BusinessLibrary (Class Library Package)
DataLibrary(Class Library Package)
Tests (Class Library Package w/ XUnit)
I am attempting to use Microsoft's new built-in dependency injection all throughout the entire system.
Here is how everything currently flows from my ASP.NET MVC App all the way down to my Repository layer
//Startup.cs of MVC Web App
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSingleton(_=> Configuration);
services.AddTransient<ICustomerService, CustomerService>();
services.AddTransient<ICustomerRepository, CustomerRepository>();
}
public class CustomersController : Controller
{
private ICustomerService _service;
public CustomersController(ICustomerService service)
{
_service= service;
}
}
public class CustomerService : ICustomerService
{
private ICustomerRepository _repository;
public PriceProtectionManager(ICustomerRepository repository)
{
_repository = repository;
}
}
public class CustomerRepository : BaseRepository, ICustomerRepository
{
public CustomerRepository(IConfigurationRoot config)
: base(config)
{
}
}
public class BaseRepository
{
private IConfigurationRoot _config;
public BaseRepository(IConfigurationRoot config)
{
_config = config;
}
}
Now how can I get something similar to work with XUnit project so I can access CustomerService and call the functions?
Here is what my Fixture class looks like:
public class DatabaseFixture : IDisposable
{
public ICustomerService CustomerService;
public DatabaseFixture(ICustomerService service)
{
CustomerService = service;
}
public void Dispose()
{
}
}
The problem is that ICustomerService is unable to be resolved... This is probably because I don't have a Startup.cs like my WebApp. How do I replicate this behavior with the test project? I don't know where to create my TestServer because if I do it in the fixture it will be too late.
Well, you can provide your own dependencies to your SUT (which is the way you should want it IMHO). I've just answered a similar question here.
If you want to define your connectionstring at one place you could use xUnit's ability to use shared context (fixtures).
Update: Examples incorperating fixtures and DI...
Your testclass should implement IClassFixture and contain for example the following fields and constructor:
public class AspnetCoreAndXUnitPrimeShould: IClassFixture<CompositionRootFixture>
{
private readonly TestServer _server;
private readonly HttpClient _client;
private readonly CompositionRootFixture _fixture;
public AspnetCoreAndXUnitPrimeShould(CompositionRootFixture fixture)
{
// Arrange
_fixture = fixture;
_server = new TestServer(TestServer.CreateBuilder(null, app =>
{
app.UsePrimeCheckerMiddleware();
},
services =>
{
services.AddSingleton<IPrimeService, NegativePrimeService>();
services.AddSingleton<IPrimeCheckerOptions>(_ => new AlternativePrimeCheckerOptions(_fixture.Path));
}));
_client = _server.CreateClient();
}
Notice that AspnetCoreAndXUnitPrimeShould is the name of the testclass in my example. The fixture looks like:
public class CompositionRootFixture
{
public string Path { get; }
public CompositionRootFixture()
{
Path = "#/checkprime";
}
}
This is just a quick adoptation from another example, but you should understand how you can fix your problem now. AlternativePrimeCheckerOptions takes a string in the constructor, just like your Configuration class could. And with a fixture you arrange this connectionstring at one place.
Update
Sample: https://github.com/DannyvanderKraan/ASPNETCoreAndXUnit
I'm using vNext implementation of DI.
How to pass parameters to constructor?
For example, i have class:
public class RedisCacheProvider : ICacheProvider
{
private readonly string _connectionString;
public RedisCacheProvider(string connectionString)
{
_connectionString = connectionString;
}
//interface methods implementation...
}
And service register:
services.AddSingleton<ICacheProvider, RedisCacheProvider>();
How to pass parameter to constructor of RedisCacheProvider class?
For example for Autofac:
builder.RegisterType<RedisCacheProvider>()
.As<ICacheProvider>()
.WithParameter("connectionString", "myPrettyLocalhost:6379");
You can either provide a delegate to manually instantiate your cache provider or directly provide an instance:
services.AddSingleton<ICacheProvider>(provider => new RedisCacheProvider("myPrettyLocalhost:6379"));
services.AddSingleton<ICacheProvider>(new RedisCacheProvider("myPrettyLocalhost:6379"));
Please note that the container will not explicitly dispose of manually instantiated types, even if they implement IDisposable. See the ASP.NET Core doc about Disposal of Services for more info.
If the constructur also has dependencies that should be resolved by DI you can use that:
public class RedisCacheProvider : ICacheProvider
{
private readonly string _connectionString;
private readonly IMyInterface _myImplementation;
public RedisCacheProvider(string connectionString, IMyInterface myImplementation)
{
_connectionString = connectionString;
_myImplementation = myImplementation;
}
//interface methods implementation...
}
Startup.cs:
services.AddSingleton<IMyInterface, MyInterface>();
services.AddSingleton<ICacheProvider>(provider =>
RedisCacheProvider("myPrettyLocalhost:6379", provider.GetService<IMyInterface>()));
You can use :
services.AddSingleton<ICacheProvider>(x =>
ActivatorUtilities.CreateInstance<RedisCacheProvider>(x, "myPrettyLocalhost:6379"));
Dependency Injection : ActivatorUtilities will inject any dependencies to your class.
Here is the link to the MS docs: Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance
Also: See #poke's answer here for more information. Basically it pulls from the provided services and any other params you pass, like a composit constructor.
You can use something like the example code below.
Manager class:
public class Manager : IManager
{
ILogger _logger;
IFactory _factory;
public Manager(IFactory factory, ILogger<Manager> logger)
{
_logger = logger;
_factory = factory;
}
}
Startup.cs class:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFactory, Factory>(sp =>
{
var logger = sp.GetRequiredService<ILogger<Factory>>();
var dbContext = sp.GetRequiredService<MyDBContext>();
return new Factory(dbContext, logger);
});
services.AddTransient<IManager, Manager>(sp =>
{
var factory = sp.GetRequiredService<IFactory>();
var logger = sp.GetRequiredService<ILogger<Manager>>();
return new Manager(factory, logger);
});
}
You can read the full example here: DI in Startup.cs in .Net Core
A bit late to the party, but you could DI inject a factory that creates and exposes an instance of your provider class.
I used to have a UserFactory (before vNext) that used HttpContext.Current but since that is now gone I am having trouble recreating it.
I want it to be a static class that sets and gets the current user to access user data throughout the application.
I know I must use the DI system but not sure how.
Code so far:
public class CurrentContext : IHttpContextAccessor
{
private IHttpContextAccessor ctx;
public HttpContext HttpContext
{
get
{
return ctx.HttpContext;
}
set
{
ctx.HttpContext = value;
}
}
}
services.AddTransient<IHttpContextAccessor, CurrentContext>();
public class UserFactory
{
private IHttpContextAccessor _context;
public UserFactory(IHttpContextAccessor Context)
{
_context = Context;
}
public void Add(string s) => _context.HttpContext.Session.SetString(s, s);
public string Get(string s) => _context.HttpContext.Session.GetString(s);
}
How can I get a UserFactory instance anywhere in my app with the current context?
I suggest you make the UserFactory class non-static and register it as scoped:
services.AddScoped<UserFactory>();
This will create one instance per web request. You can inject this into every other class and let the UserFactory take a dependency on IHttpContextAccessor to get the current HttpContext.
This adheres to the dependency inversion philosophy Microsoft is trying to implement in ASP.NET 5. Static classes do not really fit into this and should be avoided as much as possible.
Example
UserFactory class:
public class UserFactory
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserFactory(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
// other code...
}
ConfigureServices() in Startup class:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddScoped<UserFactory>();
// ...
}
Now you can inject an instance of UserFactory in a controller for example:
public class SomeController : Controller
{
private readonly UserFactory _userFactory;
public SomeController(UserFactory userFactory)
{
_userFactory = userFactory;
}
// ...
}
Now when UserFactory is begin resolved, IHttpContextFactory inside UserFactory will also be resolved.