I am creating a class which reads the header using IHttpContextAccessor and reads the values from header.
Like ".net framework" we can access context in static manner HttpContext.Current... so shall I inject my class as Singlton or Scoped as the context or context.header value is going to change in each request.
Below is what I am trying
public class RequestHeaderHelper
{
private readonly IHttpContextAccessor httpContext;
public RequestHeaderHelper(IHttpContextAccessor httpContext)
{
this.httpContext = httpContext;
}
public string BrowserIP
{
get
{
if (httpContext.HttpContext.Request.Headers.ContainsKey("X-Client-IP"))
return httpContext.HttpContext.Request.Headers.ContainsKey("X-Client-IP").ToString();
else
return string.Empty;
}
private set { }
}
....
}
Edit 1
Further I am going to use this class inside my other classes like logger. I have created action filter and exception logger where I am going to use this.
I am also using wcf client class to call the service. I am using logging there as well using beforesend and aftersend. I am adding endpoint behavior.
I want to use wcf client as singlton but use the above class in logger.
I have a series of services I am configuring in my application and one of those services require a base URL to a specific route so I can create links based on it. So if we have:
My Controller
[Route("api/v1/fancy")]
public class FancyController {
[HttpPost]
[Route("{fancyID}")]
public async Task<IActionResult> SubmitFancy(string fancyID){
// Do fancy stuff
}
}
My business class
public class Business {
private string _baseUrl;
public Business(string baseUrl){
_baseUrl = baseUrl
}
}
My Startup.cs
...
public void ConfigureServices(IServiceCollection services) {
services.AddScoped<Business>(provider => {
Business business = new Business("http://someweb.com/api/v1/fancy"); //TODO:REMOVE Hard Coded
return business;
}
services.AddRazorPages();
}
...
I have tried to use UrlHelper by adding a few more scoped services for IActionContextAccessor and IUrlHelperFactory, but I am getting null on ActionLink and RouteUrl methods, and I am not sure why.
Any ideas as to how I would go about solving this issue?
Please let me know if you need more clarification.
Thank you very much.
Inject a LinkGenerator & IHttpContextAccessor into your service;
public class Business {
private readonly LinkGenerator generator;
private readonly IHttpContextAccessor accessor;
public Business (LinkGenerator generator, IHttpContextAccessor accessor){...}
public void Foo(){
var context = accessor.HttpContext;
var link = generator.GetUriByAction(
context,
"SubmitFancy",
"Fancy",
new { fancyID="..." });
}
}
services.AddScoped<Business>();
You can use LinkGenerator without a reference to a HttpContext, but you'd need to supply the host, scheme and pathBase from somewhere else. Either from configuration, or perhaps by implementing middleware to capture them from the first request.
You can't use a string for an attribute routing. You need a CONSTANT string. Constants are immutable values which are known at compile time and do not change for the life of the program.
But if you need a route to use in ajax or httpclient, it takes several steps to get a string from appsettings.
create AppUrl section in appsettings.json
"AppUrl": {
"BusinessUrl": "http//..",
.... another urls if needed
},
2.Create class for this section
public class AppUrlSettings
{
public string BusinessUrl{ get; set; }
....another urls
}
configure settings in startup
services.Configure<AppUrlSettings>(Configuration.GetSection("AppUrl"));
now you can use them like this
public class MyClass
{
private readonly IOptions<AppUrlSettings> _appUrls;
public MyClass (IOptions<AppUrlSettings> appUrls)
{
_appUrls = appUrls;
}
public string GetBusinessUrl()
{
return _appUrls.Value.BussinesUrl;
}
}
I am using ASP.NET Core and want to add a service to the IServiceProvider at runtime, so it can be used across the application via DI.
For instance, a simple example would be that the user goes to the settings controller and changes an authentication setting from "On" to "Off". In that instance I would like to replace the service that was registered at runtime.
Psuedo Code in the Settings Controller:
if(settings.Authentication == false)
{
services.Remove(ServiceDescriptor.Transient<IAuthenticationService, AuthenticationService>());
services.Add(ServiceDescriptor.Transient<IAuthenticationService, NoAuthService>());
}
else
{
services.Remove(ServiceDescriptor.Transient<IAuthenticationService, NoAuthService>
services.Add(ServiceDescriptor.Transient<IAuthenticationService, AuthenticationService>());
}
This logic works fine when I am doing it in my Startup.cs because the IServiceCollection has not been built into a IServiceProvider. However, I want to be able to do this after the Startup has already executed. Does anyone know if this is even possible?
Instead of registering/removing service at runtime, I would create a service factory that decides the right service at runtime.
services.AddTransient<AuthenticationService>();
services.AddTransient<NoAuthService>();
services.AddTransient<IAuthenticationServiceFactory, AuthenticationServiceFactory>();
AuthenticationServiceFactory.cs
public class AuthenticationServiceFactory: IAuthenticationServiceFactory
{
private readonly AuthenticationService _authenticationService;
private readonly NoAuthService _noAuthService;
public AuthenticationServiceFactory(AuthenticationService authenticationService, NoAuthService noAuthService)
{
_noAuthService = noAuthService;
_authenticationService = authenticationService;
}
public IAuthenticationService GetAuthenticationService()
{
if(settings.Authentication == false)
{
return _noAuthService;
}
else
{
return _authenticationService;
}
}
}
Usage in a class:
public class SomeClass
{
public SomeClass(IAuthenticationServiceFactory _authenticationServiceFactory)
{
var authenticationService = _authenticationServiceFactory.GetAuthenticationService();
}
}
Something of the sort is possible in Autofac:
private ILifetimeScope BeginChildScope()
{
return _lifetimeScope.BeginLifetimeScope(x =>
{
x.Register<IAuthenticationService>(b => new AuthenticationService());
});
}
using (var childScope = BeginChildScope())
{
// Do sth here
}
For .NET Core, I think this is the only possible solution atm.:
Best strategy for creating a child container (or isolated scope) with Microsoft.Extensions.DependencyInjection
Microsoft states unsupported features of ASP.NET Core DI here:
https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines#default-service-container-replacement
I have static helper class
public static class Current
{
public static string Host
{
get { return "httpContextAccessor here"; }
}
}
How I can get access to current HttpContext inside Host property?
You can't and you shouldn't. This beats the whole purpose of having a dependency injection system at all. Static classes (for runtime data or Service Locator) is an anti-pattern.
In ASP.NET Core you have to inject IHttpContextAccessor in classes where you need it. You can make a non-static class and do something along the lines of:
public class RequestInformation : IRequestInformation
{
private readonly HttpContext context;
public RequestInformation(IHttpContextAccessor contextAccessor)
{
// Don't forget null checks
this.context = contextAccessor.HttpContext;
}
public string Host
{
get { return this.context./*Do whatever you need here*/; }
}
}
and in your class library inject it:
public class SomeClassInClassLibrary
{
private readonly IRequestInformation requestInfo;
public SomeClassInClassLibrary(IRequestInfomation requestInfo)
{
// Don't forget null checks
this.requestInfo = requestInfo;
// access it
var host = requestInfo.Host;
}
}
Be aware that your SomeClassInClassLibrary must be resolved with either Scoped or Transient mode and it can't be Singleton, because HttpContext is only valid for the duration of the request.
Alternatively if SomeClassInClassLibrary has to be singleton, you have to inject a factory and resolve the IRequestInformation on demand (i.e. inside an action).
Last but not least, IHttpContextAccessor isn't registered by default.
IHttpContextAccessor can be used to access the HttpContext for the current thread. However, maintaining this state has non-trivial performance costs so it has been removed from the default set of services.
Developers that depend on it can add it back as needed:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Source: The IHttpContextAccessor service is not registered by default
At this point I'm injecting things into my Controllers with ease, in some cases building my own ResolverServices class. Life is good.
What I cannot figure out how to do is get the framework to automatically inject into non-controller classes. What does work is having the framework automatically inject into my controller IOptions, which is effectively the configuration for my project:
public class MessageCenterController : Controller
{
private readonly MyOptions _options;
public MessageCenterController(IOptions<MyOptions> options)
{
_options = options.Value;
}
}
I'm thinking whether I can do the same for for my own classes. I assume I'm close when I mimic the controller, like this:
public class MyHelper
{
private readonly ProfileOptions _options;
public MyHelper(IOptions<ProfileOptions> options)
{
_options = options.Value;
}
public bool CheckIt()
{
return _options.SomeBoolValue;
}
}
I think where I'm failing is when I call it like this:
public void DoSomething()
{
var helper = new MyHelper(??????);
if (helper.CheckIt())
{
// Do Something
}
}
The problem I have tracking this down is practically everything that talks about DI is talking about it at the controller level. I tried hunting down where it happens in the Controller object source code, but it gets kinda crazy in there.
I do know I can manually create an instance of IOptions and pass it to the MyHelper constructor, but it seems like I should be able to get the framework do that since it works for Controllers.
Below is a working example of using DI without anything that involves MVC Controllers. This is what I needed to do to understand the process, so maybe it will help somebody else.
The ShoppingCart object gets, via DI, an instance of INotifier (which notifies the customer of their order.)
using Microsoft.Extensions.DependencyInjection;
using System;
namespace DiSample
{
// STEP 1: Define an interface.
/// <summary>
/// Defines how a user is notified.
/// </summary>
public interface INotifier
{
void Send(string from, string to, string subject, string body);
}
// STEP 2: Implement the interface
/// <summary>
/// Implementation of INotifier that notifies users by email.
/// </summary>
public class EmailNotifier : INotifier
{
public void Send(string from, string to, string subject, string body)
{
// TODO: Connect to something that will send an email.
}
}
// STEP 3: Create a class that requires an implementation of the interface.
public class ShoppingCart
{
INotifier _notifier;
public ShoppingCart(INotifier notifier)
{
_notifier = notifier;
}
public void PlaceOrder(string customerEmail, string orderInfo)
{
_notifier.Send("admin#store.com", customerEmail, $"Order Placed", $"Thank you for your order of {orderInfo}");
}
}
public class Program
{
// STEP 4: Create console app to setup DI
static void Main(string[] args)
{
// create service collection
var serviceCollection = new ServiceCollection();
// ConfigureServices(serviceCollection)
serviceCollection.AddTransient<INotifier, EmailNotifier>();
// create service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
// This is where DI magic happens:
var myCart = ActivatorUtilities.CreateInstance<ShoppingCart>(serviceProvider);
myCart.PlaceOrder("customer#home.com", "2 Widgets");
System.Console.Write("Press any key to end.");
System.Console.ReadLine();
}
}
}
Let's say MyHelper is used by MyService which in turn is used by your controller.
The way to resolve this situation is:
Register both MyService and MyHelper in Startup.ConfigureServices.
services.AddTransient<MyService>();
services.AddTransient<MyHelper>();
The controller receives an instance of MyService in its constructor.
public HomeController(MyService service) { ... }
MyService constructor will in turn receive an instance of MyHelper.
public MyService(MyHelper helper) { ... }
The DI framework will be able resolve the whole object graph without problems. If you are worried about new instances being created every time an object is resolved, you can read about the different lifetime and registration options like the singleton or request lifetimes.
You should be really suspicious when you think you have to manually create an instance of some service, as you might end up in the service locator anti-pattern. Better leave creating the objects to the DI Container. If you really find yourself in that situation (let's say you create an abstract factory), then you could use the IServiceProvider directly (Either request an IServiceProvider in your constructor or use the one exposed in the httpContext).
var foo = serviceProvider.GetRequiredService<MyHelper>();
I would recommend reading the specific documentation about the ASP.Net 5 DI framework and about dependency injection in general.
Unfortunately there is no direct way. The only way I managed to make it work is by creating a static class and using that everywhere else as below:
public static class SiteUtils
{
public static string AppName { get; set; }
public static string strConnection { get; set; }
}
Then in your startup class, fill it in as below:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//normal as detauls , removed for space
// set my variables all over the site
SiteUtils.strConnection = Configuration.GetConnectionString("DefaultConnection");
SiteUtils.AppName = Configuration.GetValue<string>("AppName");
}
Although this is bad pattern, as this will stay for the whole life cycle of the application and I couldn't find better way to use it outside controller.
Here's a more complete example to directly answer the OP's question, based on the current .NET Core 2.2 DI documentation here. Adding this answer since it may help someone that's new to .NET Core DI, and because this question is Google's top search result.
First, add an interface for MyHelper:
public interface IMyHelper
{
bool CheckIt();
}
Second, update the MyHelper class to implement the interface (in Visual Studio, press ctrl-. to implement the interface):
public class MyHelper : IMyHelper
{
private readonly ProfileOptions _options;
public MyHelper(IOptions<ProfileOptions> options)
{
_options = options.Value;
{
public bool CheckIt()
{
return _options.SomeBoolValue;
}
}
Third, register the interface as a framework-provided service in the DI service container. Do this by registering the IMyHelper service with the concrete type MyHelper in the ConfigureServices method in Startup.cs.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IMyHelper, MyHelper>();
...
}
Fourth, create a private variable to reference an instance of the service. Pass the service as an argument in the constructor (via constructor injection) then initialize the variable with the service instance. Reference any properties or call methods on this instance of the custom class via the private variable.
public class MessageCenterController : Controller
{
private readonly MyOptions _options;
private readonly IMyHelper _myHelper;
public MessageCenterController(
IOptions<MyOptions> options,
IMyHelper myHelper
)
{
_options = options.value;
_myHelper = myHelper;
}
public void DoSomething()
{
if (_myHelper.CheckIt())
{
// Do Something
}
}
}
You may use Activator.CreateInstance(). Here is a wrapper function for it. The way you use this is as follows.
var determinedProgrammatically = "My.NameSpace.DemoClass1"; // implements IDemo interface
var obj = CreateInstance<My.NameSpace.IDemo, string>(determinedProgrammatically, "This goes into the parameter of the constructor.", "Omit this parameter if your class lives in the current assembly");
Now you have an instance of obj which is instantiated from type determined programmatically. This obj can be injected into non controller classes.
public TInterface CreateInstance<TInterface, TParameter>(string typeName, TParameter constructorParam, string dllName = null)
{
var type = dllName == null ? System.Type.GetType(typeName) :
System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith(dllName, System.StringComparison.OrdinalIgnoreCase)).GetType(typeName);
return (TInterface)System.Activator.CreateInstance(type, constructorParam);
}
PS: You may iterate through System.AppDomain.CurrentDomain.GetAssemblies() to determine the name of the assembly that houses your class. This name is used in the 3rd parameter of the wrapper function.
TL;DR: You can save a singleton in a static var and then access it form other classes, but this an anti-pattern, use with caution.
Long version:
As per this question Resolving instances with ASP.NET Core DI from within ConfigureServices
Any services registered in ConfigureServices() can then be injected
into the Configure() method
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<FooService>();
}
public void Configure(IApplicationBuilder app, FooService fooService)
{
FooServiceInstance = fooService;
}
public static FooService FooServiceInstance { get; private set; }
And then call it from your other code MyStartupClass.FooService.DoStuff()