Get HttpContext in AspNet Core 1.0.0 outside a Controller - asp.net-core

I need to get the HttpContext in AspNet Core outside a controller. In the older AspNet 4 I could get it using HttpContext.Current, but it seems to be removed in the new AspNet. The only workaround I have found is resolving an IHttpContextAccessor by dependency injection and asking it the HttpContext, but to inject the IHttpContextAccessor I need to add IHttpContextAccessor as a singleton in the application Startup:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
I researched it and this is the only way I found. I google it and IHttpContextAccessor was removed as a default in the dependency resolver because it is very heavy dependency. Is there any other way to achieve this?
Edit:
I wonder if instead of adding it as a Singleton to the dependency resolver, I could get in that same place the instance of the HttpContextAccessor to save it in my own singleton class?

If you are porting a legacy application to ASP.Net Core that is reasonably complex, it would require totally reengineering to work properly with the .Net Core DI system. If you don't want to do this, you can 'cheat' by making this functionality global again in a Service Locator. To do this (which is not recommended if you can avoid it):
public class RequestContextManager
{
public static RequestContextManager Instance { get; set; }
static RequestContextManager()
{
Instance = new RequestContextManager(null);
}
private readonly IHttpContextAccessor contextAccessor;
public RequestContextManager(IHttpContextAccessor contextAccessor)
{
this.contextAccessor = contextAccessor;
}
public HttpContext CurrentContext
{
get
{
if (contextAccessor == null)
return null;
return contextAccessor.HttpContext;
}
}
}
// In Startup.cs
public void Configure(IApplicationBuilder app,...)
{
...
RequestContextManager.Instance = new RequestContextManager(app.ApplicationServices.GetService<IHttpContextAccessor>());
...
}
// In your code
var httpContext = RequestContextManager.Instance.CurrentContext;

For HttpContext to be valid, the program flow calling your class must originate in a controller or some middleware component. You could just pass a reference to HttpContext to your class.

To directly answer the question of why, this GitHub Announcement states that it's non-trivial to keep the HttpContext state tracked in IHttpContextAccessor. So it was moved to as-needed only. The HttpContext is still available in a Controller, however, without this being injected.
I don't believe you're pulling in a new dependency on the project level, just into classes via dependency injection, or grabbing it from IServiceProvider when you need it.

Related

Resolve scoped service from singleton service

Is it somehow possible to resolve a scoped service in a singleton service's method being called by a scoped one?
E.g. i have a singleton service "GlobalService" and a scoped one "UserService".
If the UserService executes a method "Job" in "GlobalService", is it somehow possible to get scoped services in this method by using Assembly.GetCallingAssembly()? Otherwise I need to pass all the required parameters.
Thank you ✌
#DeepkaMishra's answer won't work in all scenarios.
I used it myself in blazor webassembly loggingprovider and httpcontext came as null.
For more details, read this, just adding quoted text here.
Think of HttpContext as a telephone call. If you pick the phone up
when no-one has called then there is no context i.e. it is null. When
someone does call then you have a valid context. This is the same
principal for a web call. The Configure method in Startup is not a web
call and, as such, does not have a HttpContext.
Working solution, I found is provided in this.
public class PersistedConfigurationService : IPersistedConfigurationService
{
private readonly IServiceProvider _serviceProvider;
public PersistedConfigurationService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task Foo()
{
using (var scope = _serviceProvider.CreateScope())
{
//here you can get the scoped service
var context = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
// do something with context
}
}
}
Singleton would have one single instance which can be used by your scoped service. Your scoped service method can use singleton service instance.
If you call a singleton service's method, you can get the scoped service object in it. You can use IHttpcontextAccessor to resolve the scoped service instance inside that method.
internal class Singleton
{
private readonly IHttpContextAccessor httpContextAccessor;
public Singleton(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public int Job()
{
return httpContextAccessor.HttpContext.RequestServices.GetRequiredService<Scoped>().MyProperty;
}
}
You would need to register these service in Startup's ConfigureServices method:
services.AddHttpContextAccessor();
services.AddScoped<Scoped>();
services.AddSingleton<Singleton>();

Simplified approach to IOptions<T>

I am trying to get a .NET Framework class library in line with an ASP.NET Core 2.1 application while using builtin DI mechanism. Now, I created a config class and added appropriate section to appsettings.json:
services.Configure<MyConfig>(Configuration.GetSection("MyConfiguration"));
services.AddScoped<MyService>();
In class lib:
public class MyService
{
private readonly MyConfig _config;
public MyService(IOptions<MyConfig> config)
{
_config = config.Value;
}
}
However, in order to build this classlib I have to add Microsoft.Extensions.Options NuGet package. The problem is that package carries a hell of a lot of dependencies which seem rather excessive to add just for the sake of one interface.
So, the question ultimately is, "is there another approach I can take to configure a DI service located in .NET Framework class library which is not dependency heavy?
Check this article written by Filip Wojcieszyn.
https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/
You add extension method:
public static class ServiceCollectionExtensions
{
public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
var config = new TConfig();
configuration.Bind(config);
services.AddSingleton(config);
return config;
}
}
Apply it in configuration:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.ConfigurePOCO<MySettings>(Configuration.GetSection("MySettings"));
}
And then use it:
public class DummyService
{
public DummyService(MySettings settings)
{
//do stuff
}
}
I bumped into this problem a little while ago, if you can even call it a problem really. I think we all tend to get a little shell-shocked when we see a dependency list like that. But as #Tseng mentioned, it's really not a big deal to include a bunch of extra tiny assemblies (they'll be included in the bin already anyways by virtue of a reference in another project). But I will admit it's annoying to have to include them just for the options interface.
How I solved it was by resolving the service dependency in startup.cs and adjust the service's constructor accordingly:
services.AddTransient<MyService>(Configuration.GetConfiguration("MyConfiguration"));
If you don't care about whatever IOptions provides you, why not just inject IConfiguration into your service?
public class MyService
{
private readonly IConfiguration _config;
public MyService(IConfiguration config)
{
_config = config;
}
public void DoSomething()
{
var value = _config["SomeKey"];
// doing something
}
}

Inject HttpContext in ASP.Net 5

I want to inject HttpContext into my controller's constructor. Anyone knows how to configure it in ConfigureServices()?
Thanks
Injecting HttpContext directly in your dependencies is not the recommended approach. Instead, you should use IHttpContextAccessor:
public class MyComponent : IMyComponent {
private readonly IHttpContextAccessor contextAccessor;
public MyComponent(IHttpContextAccessor contextAccessor) {
this.contextAccessor = contextAccessor;
}
public string GetDataFromSession() {
return contextAccessor.HttpContext.Session.GetString(*KEY*);
}
}
That said, it's usually not needed in a controller, where you can easily retrieve the current HttpContext using the Context property.
Of course, due to the way controllers are created, this property is unavailable when you instantiate a controller, so don't try to access it from the constructor. In this case, try to refactor your code to avoid accessing HttpContext there or use IHttpContextAccessor as a replacement.

What is an analog of WebActivator in ASP.NET 5

Previously (in asp.net 4.x) there was common practice to use WebActivator class for register bootstrap logic.
I understand that now we have Startup class where everything can be configured. But with WebActivator I had more options - it was possible to drop-in an assembly into an app (add a nuget) and the assembly registered everything it needs on its own. For this an assemble had assembly level attribute with a type which should be called:
[assembly: WebActivator.PreApplicationStartMethod(typeof (ModuleBootstrapper), "Start")]
What is recommended approach for such things ("lib initialization") in the new glory asp.net 5 now?
The functionality you can get with WebActivator is not possible under ASP.NET 5 and I strongly believe that it won't ever be because one of the great things about ASP.NET 5 pipeline is that you are responsible building up your request pipeline. So, the decision should be deliberately made. As an example:
I have a middleware:
public class MonitoringMiddlware
{
private RequestDelegate _next;
public MonitoringMiddlware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
// do some stuff on the way in
await _next(httpContext);
// do some stuff on the way out
}
}
I can package this up and publish to a NuGet feed. Consumer needs to pull this in and add this into the appropriate place inside the pipeline:
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// configure services here
}
public void Configure(IApplicationBuilder app)
{
app.UseStatusCodePages();
app.UseFileServer();
// I want middleware to sit here inside the pipeline.
app.UseMiddleware<MonitoringMiddlware>();
app.UseMvc(routes =>
{
routes.MapRoute("areaRoute", "{area:exists}/{controller}/{action}");
routes.MapRoute(
"controllerRoute",
"{controller}",
new { controller = "Home" });
});
}
}
So, whenever I come into this code, I can see how the pipeline is being built without any magic. In the WebActivator case, you would need to look into a few other places to figure out your pipeline and most of all, you wouldn't be making the decision where it sits.
So, it was not a bad thing to get rid of it.

How to use dynamic module loading in an onion architecture using MVC4 as frontend

I'm trying to wrap my head around dependency injection in the Onion Architecture, I've found this solution which uses a dependency resolution layer around the onion. But there is so much going on that I'm completely lost.
So I setup a project to try it out. I like to start off simple, so a simple log entry on a (MVC) controller method would be a good start.
I'd like to use Dynamic Module Loading (kernel.Load("*.dll");) since it comes recommended from the Ninject wiki.
My solution looks like this: (For now)
Solution
- Core.Services
- Infrastructure.Logging
- DependencyResolution
- UI.MVC (default internet template)
I'd like to follow the guides lines for dependency resolution outlined here.
Ilogger
namespace Core.Services
{
public interface ILogger
{
void Log(string message);
}
}
Logging Implementation
namespace Infrastructure.Logging
{
public class DebugLogger : ILogger
{
public void Log(string message)
{
Debug.WriteLine(message);
}
}
}
Dependency Resolution
namespace DependencyResolution
{
public class TestModule : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<DebugLogger>();
}
}
}
What I want to accomplish
UI
namespace UI.MVC.Controllers
{
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger logger)
{
_logger = logger;
}
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
_logger.Log("It works!");
return View();
}
}
}
I need to run kernel.Load("*.dll"); somehow and I need to setup my MVC to use DI. I'm just now sure how since the UI cannot know about the Dependency Resolution layer.
Your DI container should be composed somewhere. This place is called the composition root and is the outermost layer. In your case that would be the ASP.NET MVC application. So saying that it should not know about the DI simply doesn't make sense. The Ninject.MVC3 package comes with a custom dependency resolver implementation that gets plugged into the application and you will get automatic DI in your controllers.