I am trying to access the Request property in my ApiController-derived class.
For some reason, Request is null in ExecuteAsync method. I've seen the other questions, so before you ask:
I am not initializing the controller by calling the constructor, it's a regular HTTP POST API call from an external device.
I've tried the same request locally with Fiddler, the behavior is identical.
I am not unit testing.
Before hitting the ExecuteAsync method, my request passes through a delegating handler, and in the delegating handler, my request object exists (I even add some properties without any problem).
At the last line of delegating handler, I call return await base.SendAsync(request, cancellationToken); without a problem and request exists.
Right after than in API controller, HttpContext.Current.Request is not null and accessible without problem.
In API controller, RequestContext is not null and accessible without problem.
In that same line, Request is null.
Why would this occur? I'm on Web API 2.2 (and MVC 5, if relevant).
This is probably due to the fact that you're trying to access HttpContext while working with async/await.
So, you have two options:
Access the request via the ExecuteAsync method 'HttpControllerContext' parameter - controllerContext.Request.
Make sure your web.config is targeting .NET 4.5 and update appSettings with aspnet:UseTaskFriendlySynchronizationContext set to true.
You can read more here - Using HttpContext Safely After Async in ASP.NET MVC Applications.
To better understand what's going on under the hood, I'd recommend:
Understand what is SynchronizationContext - ExecutionContext vs SynchronizationContext
Understand how it is related to ASP.NET - Understanding the SynchronizationContext in ASP.NET.
In a very very high level: in a synchronous server implementations, where the entire request is processed by the same thread, the execution context is stored using TLS (thread local storage), means HttpContext is available anywhere in your code.
In an asynchronous server implementation (async/await), the request may be processed by several threads, and there's a need to pass the execution context between those threads.
Related
Over the past couple weeks I've been working with an ASP.NET Core Backend(Remote Ubuntu Machine, SSH only, Kestrel).
When sending an HTTP-Request to the Server oftentimes it won't be handled the way I expected it to.
Examples:
For POSTs: An action parameter will be null or 0 or an empty string
the action method isn't executed at all
Is there a way to see the headers, body, etc. of the request that arrived at the Server?
How is the body data processed before the corresponding action method is called?
I've been reading the Console Output and setting breakpoints to figure out whats going on.
Which is fine if there's an Exception thrown or theres something going wrong inside the action method.
But it doesn't help me understand what's happening before the action method is executed.
You can add a middleware in the pipeline to inspect any requests. In the middleware, you will have access to the HttpContext and all its properties (i.e. the request and its headers). As long as you place your app.Use() call before your app.UseMvc() call, you will have access to the request before it enters an action.
More info on middleare is here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware
Once it enters an action, you have access to the Request object in the controller as well. So you can inspect anything on the request (i.e. headers) however you prefer (locals window, watch window, etc.).
All the properties you can access if you inherit from ControllerBase are here: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.controllerbase
As Polyfun mentioned, the best approach would be to add robust logging.
We're all being taught to use Dependency-Injection for coding in ASP.NET Core applications, but all of the examples I've seen so far that related to the retrieval of services via DI relate to situations where the method that has the service reference injected is strictly bound to a specific HTTP request (HttpContext) (e.g. MVC controllers, Routing delegates).
Service location is warned against as an anti-pattern, but I'm not sure on how to obtain a proper service (e.g. DbContext) reference via DI in code that is not bound a specific HTTP request, e.g. code that has to respond to messages arriving over a websocket.
Although the websocket itself is set-up initially with a specific HTTP request, messages will get responses over potentially a long lifetime of the websocket (as long as the user web session lasts). The server should not reserve/waste a DbContext/DB connection over this entire lifetime (this would result in exhaustion quickly), but rather obtain a DB connection temporarily when a message arrives and requires a response; discarding the DbContext/connection immediately afterwards - while the original HTTP request that set-up the websocket in the very beginning of the user-session technically is still there.
I haven't been able to find anything else but using:
httpContext.RequestServices.GetService(typeof(<MyNeededDbContext>)
This way I use the initial httpContext (obtained via DI when the websocket was set up), but at multiple times after that whenever a websocket message needs a response I can request a transient service object (a DbContext in this example), that may be recycled or pooled after the message response is complete, but while the original httpContext is very much still alive.
Anyone aware of a better approach?
You can create a new service scope to manage the lifetime of services yourself;
IServiceProvider provider = ...;
using (var scope = provider.CreateScope())
{
var context = scope.ServiceProvider.GetService<MyNeededDbContext>();
...
}
I have a legacy application where HostingEnivronment.RegisterObject is used.
I have been tasked with converting this to asp.net core 2.0. however I am unable to find a way to either implement this or find an alternative to this in asp.net core 2.0.
the namespace Microsoft.AspNetCore.Hosting.Internal does not contain the registerobject method nor does it have the IRegisteredObject interface. I am at a loss on how to get this implemented.
The way to achieve similar goal in asp.net core is to use IApplicationLifetime interface. It has two properties two CancellationTokens,
ApplicationStopping:
The host is performing a graceful shutdown. Requests may still be
processing. Shutdown blocks until this event completes.
And ApplicationStopped:
The host is completing a graceful shutdown. All requests should be
completely processed. Shutdown blocks until this event completes.
This interface is by default registered in container, so you can just inject it wherever you need. Where you previously called RegisterObject, you instead call
// or ApplicationStopped
var token = lifeTime.ApplicationStopping.Register(OnApplicationStopping);
private void OnApplicationStopping() {
// will be executed on host shutting down
}
And your OnApplicationStopping callback will be invoked by runtime on host shutdown. Where you previously would call UnregisterObject, you just dispose token returned from CancellationToken.Register:
token.Dispose();
You can also pass these cancellation tokens to operations that expect cancellation tokens and which should not be accidentally interrupted by shutdown.
I need to be able to call my SS services from the controllers of an MVC application. Ideally i'd like to call them in-process to avoid the overhead of buiding a http request etc.
From scouring documentation I feel there are 2 suggested methods, but neither work fully.
1) ServiceGateway - Use the service gateway. This calls validation filters, but does not call other customer filters I've added. No option to applyFilters.
2) HostContext.ServiceController.Execute - There is a dedicated option on this method called applyFilters, and when I set it to true it works and applies filters and validation (though it only executes GlobalFilters, not TypedRequestFilters). However, if [CacheResponse] attribute is set on the service it overwrites and flushes a response to my client overriding the flow of the MVC controller and i don't know how to stop this. It does not do this if I set to applyFilters to false or if I take CacheResponse off. Changing the priority of the cache has no effect.
I'm calling the Execute method as follows from within an Action method on my controller:
HostContext.ServiceController.Execute(serviceRequest, HostContext.GetCurrentRequest(), true);
Before this method even returns control a response is flushed to the webpage on Chrome and then nothing/null is returned from method.
I feel there is regarding point 1) a feature missing and point 2) a bug in the implementation, though am not confident enough in my knowledge of SS to remedy either! Please help!
Thanks.
Filters are executed as part of the HTTP Request Pipeline and can terminate the current Request with a custom HTTP Response. You can check IRequest.IsClosed after executing the Request to check if it has been terminated by a Request Filter. They're behavior is incompatible with internal Gateway requests so there's no option to execute them in the Gateway.
I've marked these ServiceController methods as an In Process Request in this commit which should resolve the issue with the [CacheResponse] attribute which ignores In Process Requests.
This change is available from v4.5.13 that's now available on MyGet.
I'm very new to Web API and I have an unusual pattern that I need to implement. In the Post method of my controller, it is to take an object which includes a CallbackURL. It will then immediately return an HTTP response to the caller. Afterwards, it will use a 3rd party, off-site API to perform some work with the object. Once that work is done, the controller is to post the results of that work to the CallbackURL.
However, I do not know how to implement this in Web API. Once I return the HTTP response, the controller's lifecycle is over, correct? If so, how do I perform the work I need to do after I return the response?
If you only need to post results to a url and not to the client that initiated the call, you could possibly do something as easy as this:
public string MyAPIMethod(object input)
{
Task.Factory.StartNew(() =>
{
//call third-party service and post result to callback url here.
});
return "Success!";
}
The api call will return right away, and the Task you created will continue the processing in a different thread.
Creating a task to finish up the request (as suggested by Jason P above) will most likely solve the problem, thread-safety provided. However that approach might hurt the performance of your Web service if calls to the 3rd party API take a significant amount of time to complete and/or you are expecting many concurrent clients. If that was the case, your problem seems to be the perfect candidate for a service pattern called "Request/Acknowledge/Callback" (also "Request/Acknowledge/Relay"). Using that pattern, your Web API method will just store each request (including the callback URL) into a queue/database and return quickly. A separate module (possibly running on more than one machine, depending on the number and complexity of the tasks) will take care of completing the tasks, and subsequently notifying completion through the callback URL (please see http://servicedesignpatterns.com/ClientServiceInteractions/RequestAcknowledge).
This is presuming you want to return the results of your 3rd-party query to the caller.
You're correct, this is outside of what's possible with WebAPI. Once you return the HTTP Response, the client also has no connection to your server.
You should look into Asp.Net SignalR, which allows a persistent connection between the client and server, working in modern browsers, and even back to IE7 (though officially unsupported), as well as supporting non-browser clients.
You can then do a couple of things, all of which require the client to connect to SignalR first.
Option 1: You can call your WebApi controller, which can return, but not before launching a task. This task can query the 3rd party api, then invoke a function on the caller via SignalR with the results that you want to provide.
Option 2: You can call a SignalR Hub action, which can talk back to your client. You can tell your client the immediate response, query the 3rd-party api, then return the results you want to provide.