I'm setting up some integration tests for mediatr handlers using xunit, respawn, and webapplicationfactory....
One of classes ultimately called by the mediatr handler that is being tested.. has a dependency on IHttpContextAccessor as you can see below
I feel like I've set up the "replacement" singleton that I want injected correctly as per below:
But when the integration test runs.. the httpContextAccessor is not null but the HttpContext is ALWAYS null.
I've tried about 6 million things :( Much sadness.
How can get the IHttpContextAccessor to resolve correctly to what I'm setting in ConfigureServices?
When the integration test runs.. the httpContextAccessor is not null but the HttpContext is ALWAYS null.How can get the IHttpContextAccessor to resolve correctly to what I'm
setting in ConfigureServices?
No we cannot, The HttpContext will only be available within the scope of the request because ConfigureServices invocked before constructing Startup so if we try to inject, it will through exception, even if we declare at global variable in that scenario it will always be null. Application startup happens only once, and long before any request has been received.
Let's try to access it within IConfiguration as following:
public Startup(IConfiguration configuration,IHttpContextAccessor httpContextAccessor)
{
Configuration = configuration;
HttpContextAccessor = httpContextAccessor;
}
public IConfiguration Configuration { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
Output:
As you can see, it doesn't allow us to do so.
Even if we try to inject it within configuration itself it will ended up with following exception:
Therefore, ConfigureServices runs once before any httprequest coming to application. If we forcefully try to call it outside of request life-cycle it will always ended up with NullReferenceException. You can get more details in the official document.
In addition to this, we can inject service reference within configuration as following:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
I needed to implement IHttpContextAccessor myself
Then utilise in the ConfigureTestServices of the WebApplicationFactory ConfigureWebHost
Related
In my Blazor Server app I have this code in a component that needs to read cookies from the Request (so I would read them before the render):
[Inject] private IHttpContextAccessor HttpCxAccessor { get; set; }
...
protected override void OnInitialized()
{
var context = HttpCxAccessor.HttpContext;
// context is null when on Local IIS
the code works when I run it from VS (IISExpress) but when I publish it on local IIS, the HttpContext is null
You shouldn't use HttpContextAccessor in Blazor Server because the Blazor Server works outside the .NetCore pipeline and basically there is no guarantee that you will have access to the desired amount of HttpContext everywhere for more info you can refer to this issue. However, If you have to use the HttpContext then you have to get the desired value(s) from HttpContext when rendering _Host.cshtml and save it in a variable and use that variable in the form of Cascading Parameters in the components in the rest of the program.
An Example of implementation is here.
I'm working into net core identity Server project. in the StartUp class this code create a log object
public Startup(IConfiguration configuration, ILogger<Startup> logger)
{
StaticConfig = configuration;
_logger = logger;
}
the same code is inside the api project. Both IdentityServer and Api needs to call functions from an old Soap service. So i create a new net core class Library called SoapClient to share the functions between the two projects.
this the code to instantiate soapClient from IS and Api projects:
SoapClient.Client client = new SoapClient.Client(
Startup.StaticConfig.GetValue<string>("soapClient:server")
);
Now i dont know how to inject the log instance inside SoapClient Library. i Tried this into the
constructor but logger is always null:
public Client(string serviceUrl, ILogger<Client> logger = null)
{
_ServiceUrl = serviceUrl;
logger.LogDebug("Created");
}
if remove the default null to logger parameter, the code does compiler because logger is expected to be passed when the costructor is called from IS project and Api project.
You should use dependency injection for this kind of scenarios. The callers should not be responsible of knowing how to create an instance of SoapClient.Client.
Just register your SoapClient.Client into DI. And naturally you can have both the config (via IOptions) and logger injected automatically.
If for whatever reason you don't want to use DI, the caller will have to have an ILoggerFactory injected and you can create ILogger instances using the ILoggerFactory.
In my solution I have projects for my API, my Web App and also have another project which includes services, that are getting some information from a database and formatting them, these are currently only used by this API, but these could be used by other API projects in the future.
My API have a couple controllers that are returning JSON data from the result returned by the services.
In some cases the services needs to call the API to process some information before calling the request to the database. Since I have dev/staging/prod environment with their own URL I don't want to hardcode the URLs in the services I want to use DI to get these dynamicaly depending on the context.
In the Startup.cs of my API I have added services.AddHttpContextAccessor(); in the ConfigureServices(IServiceCollection services) section to gain access to the current http context :
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpContextAccessor();
...
}
With that I know I can now access the information directly into my controller which I tried and it worked :
public class DataController : ControllerBase
{
...
private readonly string _baseUrl;
public FeaturesController(...
,IHttpContextAccessor httpContextAccessor)
{
...
_baseUrl = UrlHelpers.ShowBaseURL(httpContextAccessor) ?? throw new ArgumentNullException(nameof(_baseUrl));
}
}
public static class UrlHelpers
{
public static string ShowBaseURL(IHttpContextAccessor httpcontextaccessor)
{
var request = httpcontextaccessor.HttpContext.Request;
var absoluteUri = string.Concat(
request.Scheme,
"://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent());
return absoluteUri;
}
}
I could do just about the same thing in the services but to me they should not act directly on the httpcontext, since this is not the job they are meant to do. I am sure I could do better by adding a class injected of some sort that would have then make the specific value available to my services.
I know I could also pass the _baseUrl directly as an argument when calling the services from my controller but since I am trying to better understand DI and use it I would rather find another way if it is viable.
I can't give credit but I went with Steven solution which make the most sens
In our MultiTenant ASP.NET Core 2.2 app, we determine the tenant from the URI.
How can get the website URL from an IHostedService?
The HttpContext is always null.
The IHttpContextAccessor.HttpContext IS ALWAYS NULL
public MyHostedService(ILogger<TurnTimeTask> logger,
IHttpContextAccessor httpContextAccessor)
{
_logger = logger;
_httpContextAccessor = httpContextAccessor;
}
Even running the IHostedService in Scope also returns NULL for the httpContextAccessor.HttpContext
i.e. Injecting it through a Scoped Service doesn't work either.
public override Task ProcessInScope(IServiceProvider serviceProvider)
{
var request = _httpContextAccessor?.HttpContext?.Request;
//request is always null
}
Is there any other way to get the website's URL from an IHostedService?
HttpContext is populated when a http request hits your site (very simple explanation).
Think of a IHostedService as something that runs in the background independent of any http requests, it runs in a completely different context than for example the requests that hits your controllers.
HttpContext is heavily tied to ASP.NET Core while IHostedService does not need ASP.NET Core to run.
I have ASP.NET Core API. I have already gone through documentation here that shows how to do integration testing in asp.net core. The example sets up a test server and then invoke controller method.
However I want to test a particular class method directly (not a controller method)? For example:
public class MyService : IMyService
{
private readonly DbContext _dbContext;
public MyService(DbContext dbContext)
{
_dbContext = dbContext;
}
public void DoSomething()
{
//do something here
}
}
When the test starts I want startup.cs to be called so all the dependencies will get register. (like dbcontext) but I am not sure in integration test how do I resolve IMyService?
Note: The reason I want to test DoSomething() method directly because this method will not get invoked by any controller. I am using Hangfire inside this API for background processing. The Hangfire's background processing job will call DoSomething() method. So for integration test I want to avoid using Hangfire and just directly call DoSomething() method
You already have a TestServer when you run integration tests, from here you can easily access the application wide container. You can't access the RequestServices for obvious reason (it's only available in HttpContext, which is created once per request).
var testServer = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment("DevelopmentOrTestingOrWhateverElse"));
var myService = testServer.Host.Services.GetRequiredService<IMyService>();