Building workaround for HttpWebRequest timeout issue - wcf

I'm using the HTTP Web Request class to call a RESTful web service. I need to pass data and receive data and it all seems to work very well. Today I attempted to configure the time-out of the class because there is a high likelihood of the server running the service being offline and I don't want to waste time waiting. I configured it all but it seemed to make no difference. The call still waited over 10 seconds before failing.
On looking into it I found that the time-out only deals with the processing of the call and that the DNS lookup beforehand is not included. As this would be the problem it would make sense as to why the time-out wasn't working as I'd expected.
Further reading suggested using the HttpWebRequest class in an asynchronous style instead. I've had a look at the code to do so but don't understand how to retrieve the callback in my code which is effectively synchronous.
The code I have as follows is as so:
HttpWebRequest _serviceRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://mywebservice.com"));
_serviceRequest.Timeout = 3000;
HttpWebResponse response = (HttpWebResponse)_serviceRequest.GetResponse();
XmlReader reader = XmlReader.Create(response.GetResponseStream(), set);
The code I have to call asynchronously ends with the following line, but I'm not sure as to what I should do to get the response object.
IAsyncResult result = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(RespCallback), reqState);
I'm also concerned about a half baked asynchronous solution such as this. Is it good practice to use an asynchronous method through a synchronous piece of code.
Any helpers appreciated...

The response would be available when the callback function RespCallback is invoked. I don't know what reqState has, but I assume it contains a reference to the original HttpWebRequest object. If this is the case, this would be a simple implementation of the RespCallback method:
void RespCallback(IAsyncResult asyncResult)
{
ReqState reqState = (ReqState)asyncResult.AsyncState;
HttpWebResponse resp = (HttpWebResponse)reqState.Request.EndGetResponse(asyncResult);
// do what you need with the response.
}
Update: more info as asked in the comment
If you want the response in the same method where you did the Begin call, you can have an event which will be set when the callback is received, and you can wait on that event after the Begin call, like in the example below
class ReqState {
public HttpWebRequest Request { get; set; }
public HttpWebResponse Response { get; set; }
public AutoResetEvent Evt { get; set; }
}
void RespCallback(IAsyncResult asyncResult) {
ReqState reqState = (ReqState)asyncResult.AsyncState;
reqState.Response = (HttpWebResponse)reqState.Request.EndGetResponse(asyncResult);
reqState.Evt.Set();
}
void CallMethod() {
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(...);
// set properties on req
ReqState state = new ReqState();
state.Request = req;
state.Evt = new ManualResetEvent(false);
req.BeginGetResponse(RespCallback, state);
state.Evt.WaitOne(TimeSpan.FromSeconds(30)); // wait for 30 seconds
// access response via state.Response
}
Now notice that you're essentially doing a synchronous call in an asynchronous way. That gives you more control over the timeout, but with the price of code complexity. Another thing, this will not work on platforms such as Silverlight (and Windows Phone, IIRC), where synchronous calls (even those dressed up as asynchronous) are forbidden.

Related

WebClient synchronous call does not return from within a filter stack trace

In a Spring Gateway API I have a filter which calls a class to make a call to another API using WebClient. If I make the same call from say a controller the call returns. However when this webclient call is made from within the Filter stack it never returns. I am trying to make this call synchronously. I cannot use the block() method because Reactive classes error.
Here is the method in question:
public void doPost() {
ApiResponse<Void> response = webClientBuilder.build().post()
.uri("http://localhost:8080")
.retrieve()
.bodyToMono(new ParameterizedTypeReference<ApiResponse<Void>>() {})
.block();
}
I am very new to WebClient and need someone to tell me how I can synchronously make this call. I have tried another variation which is toFuture().get() instead of the last line but this also does not return.
It get the below error:
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-4
My mistake it is an authentication filter that this is being run from:
public class AuthServiceAuthenticationManager implements ReactiveAuthenticationManager {
private final MyClient myClient;
#Override
public Mono<Authentication> authenticate(Authentication authentication) {
//Below line does not return using my webclient
myClient.post();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), new ArrayList<GrantedAuthority>());
return Mono.just(token);
}
}
As I mentioned in comment, the reason is simple - you and blocking doPost is called from the reactive flow. WebClient is a non-blocking client and as you are using it from the ReactiveAuthenticationManager you could keep the whole flow reactive.
Solution:
Remove block() from the doPost and return Mono.
public Mono<ApiResponse<Void>> doPost() {
return webClientBuilder.build().post()
.uri("http://localhost:8080")
.retrieve()
.bodyToMono(new ParameterizedTypeReference<ApiResponse<Void>>() {})
}
Construct reactive flow in AuthServiceAuthenticationManager.
Logic of authenticate is not really clear but based on your example it could look like
public Mono<Authentication> authenticate(Authentication authentication) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(), new ArrayList<>());
return doPost()
.thenReturn(token);
}

Response pipeline

I came across a difficulty while was working with Asp.net core 1.0 RTM. For example in case bellow we will see output result as "-Message_1--Message_5-":
public class MessageMiddleware
{
private readonly RequestDelegate _next;
private readonly IApplicationBuilder _app;
public MessageMiddleware(RequestDelegate next, IApplicationBuilder app)
{
_next = next;
_app = app;
}
public async Task Invoke(HttpContext context)
{
var started1 = context.Response.HasStarted;//false
await context.Response.WriteAsync("-Message_1-");
var test = true; // will hit this line
var started2 = context.Response.HasStarted;//true
await context.Response.WriteAsync("-Message_5-");
await _next.Invoke(context);
}
}
But in this case (header "Content-Type" was added) the result will be only "-Message_1-" and execution is really stopped:
public class MessageMiddleware
{
private readonly RequestDelegate _next;
private readonly IApplicationBuilder _app;
public MessageMiddleware(RequestDelegate next, IApplicationBuilder app)
{
_next = next;
_app = app;
}
public async Task Invoke(HttpContext context)
{
var started1 = context.Response.HasStarted;//false
await context.Response.WriteAsync("-Message_1-");
var started2 = context.Response.HasStarted;//true
context.Response.ContentType = "text/html";
var test = true; // will NOT hit this line
var started3 = context.Response.HasStarted;//will NOT hit this line
await context.Response.WriteAsync("-Message_5-"); //will NOT hit this line
await _next.Invoke(context);
}
}
I found only this remark in official documentation:
Avoid modifying HttpResponse after invoking next, one of the next components in the pipeline may have written to the response, causing it to be sent to the client.
and this question at SO: Why can't the HttpResponse be changed after 'next' call?
But it's not enough to understand interaction with props of HttpContext.Response during middleware pipeline and how this interection affects on final result - headers and body content of HttpResponse.
Could somebody explain general behaviour of processing response by ASP.NET core? For example, when response headers are send to client and how setting HttpContext.Response properties(headers, body content) affects on this?
When pipeline inside(outside) middliware is terminated?
Thank you!
As a general rule, when the client makes a request to the server, it gets back a response. That response contains headers and a body. The headers contain many pieces of information about the response like the content type, encoding/compression used, cookies, etc. Here is an example of the headers sent back by the live.asp.net site as seen in the chrome developer tools:
The other part of the response is the body. It often contains html or json. Here is a screenshot of the body for the same response:
The easiest way to think about it is to think of these two being sent together to the client, first the headers then the body. So as a developer, your only opportunity to set any value on the response object that affects the headers is up to the point at which you start sending the body. One you begin sending the body of the response you can no longer change the headers because they are sent as the first part of the response just before the body begins sending.
That's why #tseng said "Don't set headers after you have written something to the response stream".
If a developer isn't familiar with http headers they might not realize that context.Response.ContentType = "text/html" is changing a header, but under the hood, that's exactly what it is doing. Likewise, setting a cookie changes a response header under the hood. In general, if you are changing some property of the response object you should ask yourself "will this change an http header?" and if the answer is "yes" then you need to do it before you make a call to Response.WriteAsync.

Actors ReceiveAsync method unable to POST data to the listener

Background
Notification service has a Notify method which is invoked when an event occurs, so here Im creating the FloorActor and sending the message consisting data and post url to the Actor.
public class NotificationService
{
//HttpClient client = new HttpClient();
ActorSystem notificationSystem = ActorSystem.Create("NotificationSystem");
public void Notify(int clientID, FloorEventData data)
{
try
{
string postUrl = "http://localhost:6001";
FloorData floorData = new FloorData() { Data = data,PostURL=postUrl };
//This commented line of code post data and listener gets the POST request
//client.PostAsJsonAsync<FloorEventData>(postUrl, data);
//Create Floor Actor
var floorActor = notificationSystem.ActorOf<FloorActor>("floorActor");
floorActor.Tell(data);
}
catch (Exception exception)
{
//Log exception
}
}
}
ReceiveAsync method of the Floor Actor data just posts the event data to the specified URL.Framework used to implement Actor Model :Akka.Net
public class FloorActor : ReceiveActor
{
HttpClient client = new HttpClient();
public FloorActor()
{
ReceiveAsync<FloorData>(floorActor => client.PostAsJsonAsync<FloorEventData>(floorActor.PostURL, floorActor.Data));
}
}
Issue-
When I debugged the issue the code flow works as expected:-
1) When event occurs Notify method is invoked
2) Notify method creates the Floor Actor and sends the data
3) Floor Actor's ReceiveAsync method is called and the line of code is executed without any errors or exceptions.But the POST listener, doesn't get the POST data request, so not sure what is happening ?
Tried POST data directly from the Notify method its works, the listener gets the POST request.You can see this code snippet commented above in the Notify method.
So when I try to POST data from my Actor's Receive method, the Http listener does not get the request and there is no errors or exception.
Please let me know if I have to change anything?
ActorSystem should be treated as a singleton for your entire system. So put that instance in a static somewhere and reference it from there.
Also try to await on client.PostAsJsonAsync

Is it possible to return a response from a Web API constructor?

I have a Web API ApiController base class and I would like to perform some validations in the constructor. This might include checking the current load on the server. If it's high, I'd like to return an appropriate HttpResponseMessage indicating the requestor should try again later.
Is something like this possible?
I Haven't tested it but that's not what the constructor is for. I don't think all plumbing is set at that time.
You could use global filters for this purpose. Here you have a sample that sets a global filter for authorization, you should use a similar logic but creating your own filter for your specific purposes.
A global filter would intercept all your requests and is executed before the controller actions so is a good place to perform your task.
Even though what you are doing sounds like it may be better to revise the approach. Note that you can throw HttpResponseException since the WebApi is Rest Service HttpResponseException is the recommended way to throw Exceptions back to the client.
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent("No idea what happened "),
ReasonPhrase = "Something was not Not Found"
}
throw new HttpResponseException(resp);
As long as you're using .NET 4.5, then you'd be better off creating a custom MessageHandler. You'll need to extend DelegatingHandler in order to do that.
public class MyHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(
HttpMessageRequest request, CancellationToken cancellationToken) {
// Access the request object, and do your checking in here for things
// that might cause you to want to return a status before getting to your
// Action method.
// For example...
return request.CreateResponse(HttpStatusCode.Forbidden);
}
}
Then inside your WebApiConfig, just add the following code to use the new Handler:
config.MessageHandlers.Add(new MyHandler());
You can't throw HttpResponseException in constructor, that will always cause 500.
Easiest way is to override ExecuteAsync():
public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) {
if (!myAuthLogicCheck()) {
// Return 401 not authorized
var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "User not logged in" };
throw new HttpResponseException(msg);
}
return base.ExecuteAsync(controllerContext, cancellationToken);
}

Protocol Violation - Verb does not allow content type

Update: I was at Build 2013, and Mark Simms looked at this and confirmed that HTTP request leaving the router does have a "Body" in the request. He felt that this was caused by the Get arriving at the SB, then packaged to be routed, then the package is managed again as a Messsage type, before sending it back out again. In between the packaging and routing, properties are left in the body of the request - which violates protocol for the "GET". All this however lives within MS framework either in the .NET, or in the ServiceBus. As the body is immutable (at least I can't find a way to alter it), the only means is to duplicate the request, and then update the original request on the way out.
This is a small part of a routing application that takes in a HTTP GET/POST request from a Azure ServiceBus endpoint, brings it down via the relay channel to my local workstation, where I rewrite the URL, and send it to my local web service.
Here is the interface - generic so that it can receive any type of call to a controller/action URL
// The Router, and general concept of how to recieve from the SB and redirect was taken from
// Tony Sneed Blog - which he documented here: http://blog.tonysneed.com/2012/04/24/roll-your-own-rest-ful-wcf-router/
//
[ServiceContract(Namespace = "urn:Twiddler")]
public interface IRoutingService
{
[WebInvoke(UriTemplate = "")]
[OperationContract(AsyncPattern = true, Action = "*", ReplyAction = "*")]
IAsyncResult BeginProcessRequest(Message requestMessage, AsyncCallback asyncCallback, object asyncState);
Message EndProcessRequest(IAsyncResult asyncResult);
}
}
Here is the code:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
AddressFilterMode = AddressFilterMode.Any, ValidateMustUnderstand = false)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class RoutingService : IRoutingService, IDisposable
{
private IRoutingService _client;
/// <summary>
/// when a message is received from the SB, it arrives here as simply a message -
/// </summary>
/// <param name="requestMessage"></param>
/// <param name="asyncCallback"></param>
/// <param name="asyncState"></param>
/// <returns></returns>
public IAsyncResult BeginProcessRequest(Message requestMessage, AsyncCallback asyncCallback, object asyncState)
{
string RequestMessageAction = requestMessage.Headers.Action;
IAsyncResult asyncResult = null;
//if the full URI for the namespace does not match the one contructed in Twiddler, then pass it through - we have nothing to do with it!
if (requestMessage.Headers.To.AbsoluteUri.Contains(Utilities.ServiceFormBridge.NameSpaceName) && requestMessage.Headers.To.AbsoluteUri.Contains(Utilities.ServiceFormBridge.EndPointName) == false)
return asyncResult;
//as the service bus will accept anything in terms of controllers and actions, we only need alter the DestinationAddress.Authority (host and port)
var RewriteTheURL = requestMessage.Headers.To.AbsoluteUri.Replace(string.Format("http://{0}.servicebus.windows.net/{1}/", ServiceFormBridge.NameSpaceName, ServiceFormBridge.EndPointName), ServiceFormBridge.DestinationWebSite);
Uri DestinationAddress = new Uri(RewriteTheURL);
System.ServiceModel.ChannelFactory<IRoutingService> factory = null;
factory = new ChannelFactory<IRoutingService>(new WebHttpBinding(), DestinationAddress.AbsoluteUri);
WebHeaderCollection httpHeaders = WebOperationContext.Current.IncomingRequest.Headers;
httpHeaders.Remove("Host");
httpHeaders.Add("Host", DestinationAddress.Authority); //give it the new host that we are re-directing to
httpHeaders.Remove("Connection"); //todo: not sure I need this, but without it there is an exception between Keep-Alive and Closed
// Set factory and message address
factory.Endpoint.Address = new EndpointAddress(DestinationAddress);
requestMessage.Headers.To = DestinationAddress;
_client = factory.CreateChannel();
asyncResult = _client.BeginProcessRequest(requestMessage, asyncCallback, asyncState);
return asyncResult;
}
}
On the BeginProcessRequest, I get an exception:
Protocol Violation: Cannot send a content-body with this verb-type
Which I have researched and I understand that under a GET request, there can't be anything in the body of the request.
As my code works for a POST, I can only assume that for some reason, there is something in the body.
However, as the originating request was a GET from a browser using the URL of the ServiceBus, I'm not sure why there would be anything in the body.
So:
I'm thinking I'm doing something in the code that is causing me a problem - if so I would like to know what!
If there is something in the incoming request, how can I remove it so I don't get the violation?
Any other suggestions, improvements to the code?
Placing this attribute on the operation, [WebInvoke(UriTemplate = "")], supports POST by default, but you can pass a parameter specifying other verbs, such as PUT, DELETE, etc. However, GET is supported by a different attribute, [WebGet]. I would suggest adding additional operations to the router, one with WebGet, and others with WebInvoke and different HTTP verbs.