I've got the following code block. I'm confused how the code can go past the
Response.Redirect("~..")
Indeed it does. I thought any lines past that would automatically not execute. Am I missing somethig basic here? I find the debugger actually executing the next lines.
public ActionResult Index()
{
Response.Redirect("~/Default.aspx", true);
string year =
Utils.ConvertCodeCampYearToActualYear(
Utils.GetCurrentCodeCampYear().ToString(CultureInfo.InvariantCulture));
var viewModel = GetViewModel(year);
return View(viewModel);
}
You need to return it. It's a function. In your case you can use Redirect:
return Redirect("~/Default.aspx");
All Response.Redirect() does (really) is set location= response header to the specified URI and sets the http status to 302 Found. It also writes a little stub HTML in the response with a link to the new URI as well, but that's a mere decoration.
Unless you use the overload that allows you to specify whether or not processing should be continued via a bool flag, processing continues. If that bool flag is true, response processing is terminated by aborting the thread processing the request, throwing a ThreadAbortException as a side effect.
Related
I am trying to use ActionFilters to capture the result in my api call and change it if needed.
But it appears to change only the object i pass not the result type. (from OK to BadRequest)
return Ok(await _Data.Remove());
The above code in my controller leads to my filter:
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var resultContext = await next();
Guid userId = await _data.GetId();
BaseModel baseModel = (BaseModel)((ObjectResult)resultContext.Result).Value;
if (baseModel.ApiResponse == ApiResponse.AllGood)
{
BaseModel m = _data.GetBaseModel(userId);
m.ApiResponse = baseModel.ApiResponse;
resultContext.Result = new OkObjectResult(m);
}
else if (baseModel.ApiResponse == ApiResponse.NotFound)
resultContext.Result = new NotFoundObjectResult(baseModel);
else
resultContext.Result = new BadRequestObjectResult(baseModel);
}
The model is correctly captured and i can check against its contents. And i can change it and pass it back. But it always goes back to the controller and then returns the "ok" with the new model.
What i want is it returning BadRequest
I have tried putting doing this:
resultContext.Result = new BadRequestObjectResult(baseModel);
As you can see from the above code, but it does not work.
The reason you cannot get it to work, is because this approach isn't possible (in the general case, at least).
The async variant of the ActionFilter combines both the pre and post variants of the synchronous variant, in one callback, by giving you next().
Once you have called and successfully returned from next(), you are in 'executed' land, not 'executing' land anymore.
The trouble is, if next() has started sending the response to the client, it is too late to change the response. Your receiving client may already sit with 'http 200 ok' in his hand!
You can observe this, by trying to write to the response in context.HttpContext.Response (You can set the Http Status Code on it, and use WriteAsync on it),
in the spot where you attempt to modify Result.
If next had already started the response, you'll get a direct exception telling you this.
However, IF next() hadn't begun the response, you may actually be able to control the response.
A last-resort option you have, is to throw at this point, it will (mostly) break your http response into http-500 server error. This may or may not be good for your client.
Lastly, your resultContext actually has a 'Cancelled' attribute which you can flag.
However I don't know if that has any effect if the response has already begun (it might affect the middleware server side).
In my own case for this, I concluded it was the wrong place to solve our issue, so I moved our necessary handling to a wrapper in the controller method return statement.
I.e. you then get
return wrapper(OK(response));
where wrapper will decide whether to pass on OK(..) unharmed.
If you use this approach, be careful if you had
return OK(responseWIthSideEffect(..));
in that case, you must make sure the side effect code is forced to execute,
before your wrapper makes its decision (i.e. assuming the wrapper checks something that might depend on that side effect).
We had a problem recently where one of the developers had changed a line of code from using HttpResponse.End to using HttpApplication.CompleteRequest when forcing a PDF to download in a similar fashion to the following:
https://stackoverflow.com/a/8590579/3856039
Doing so caused some PDF's to fail to download due to a non-breaking space issue so the code was changed back to using HttpResponse.End.
However, in helping my colleague I was carrying out some research and I came across the following question:
Is Response.End() considered harmful?
Which links to:
https://blogs.msdn.microsoft.com/aspnetue/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation/
Given what is documented in the MSDN blog post, it sounds like using HttpResponse.End is the wrong approach, so I was wondering if it is even needed or whether there is a better approach?
Here is the actual code from Response.End:
public void End()
{
if (this._context.IsInCancellablePeriod)
{
HttpResponse.AbortCurrentThread();
return;
}
this._endRequiresObservation = true;
if (!this._flushing)
{
this.Flush();
this._ended = true;
if (this._context.ApplicationInstance != null)
{
this._context.ApplicationInstance.CompleteRequest();
}
}
}
The ThreadAbortException is used for control of flow-- basically allowing you to use Response.End in place of return. But if you've designed your handler well, you may not need it, e.g. if there is no code after Response.End(). It is generally better not to throw the exception if you can avoid it, since it (like all exceptions) will cause a stack unwind and some performance overhead.
Perhaps you can write your own version of Response.End and pick and choose which lines of code actually execute, e.g. maybe you want to flush the buffer and call CompleteRequest but you don't want to throw the exception.
Here is the approach I have used in the past
// Sends all currently buffered output
HttpContext.Current.Response.Flush(); to the client.
// Gets or sets a value indicating whether to send HTTP content to the client.
HttpContext.Current.Response.SuppressContent = true;
/* Causes ASP.NET to bypass all events and filtering in the HTTP pipeline
chain of execution and directly execute the EndRequest event. */
HttpContext.Current.ApplicationInstance.CompleteRequest();
I have a huge website with a huge backend. Somewhere, somehow, there is a Response.Redirect called while trying to open a site (debug environment).
Is there a way to find out, which Response.Redirect causes the redirect?
An certain way would be to set a debug breakpoint on every Response.Redirect in the whole website. But this is a lot of effort.
Another idea I had was to stop at the "ThreadAbortException" (which is thrown by Response.Redirect) with "Debug->Exceptions..". But this doesn't work. Seems like the frame or whatever is no longer executed to get a break on it.
Last attempt was to watch the call-stack. But the stack never gets to the last Response.Redirect because it is a new frame call.
Well, I got an idea which solved my problem but required massive code replacement (which is not a problem with 'Find and replace').
I created an static class:
public static class OwnResponse
{
public static void Redirect(string Url, bool EndResponse = true)
{
HttpContext.Current.Response.Redirect(Url, EndResponse); // set the breakpoint here
}
}
Then I replaced every Response.Redirect in the code with OwnResponse.Redirect. Now I was able to set my breakpoint onto the first line in the class. I called the website and the breakpoint got hit. Then I just watched the call-stack and knew where the redirect occurs.
There is another possible solution, which requires a bit more work. You have to get "Stepping into .NET code" to run. Then you can easily set a break point in the .NET method's first line.
Open the Exception Settings window and search for "threadabort". Check the checkbox for the ThreadAbortException. Now, when a redirect is executed from code, your debug session will enter break mode.
You can use below code in landing page:-
string yourPreviousUrl = Request.UrlReferrer.ToString();
if(!string.IsNullOrEmpty(yourPreviousUrl))
{
//Referrer was found!
}
else
{
//Unable to detect a Referrer
}
As mention in official site :-
HttpRequest.UrlReferrer Property
Gets information about the URL of the client's previous request that
linked to the current URL.
You could try to implement tracing and save the results to a file. The trace data might help you to pinpoint your redirect.
Here is a link with some more background on ASP.NET tracing:
http://www.codeproject.com/Articles/82290/Step-by-Step-Guide-to-Trace-the-ASP-NET-Applicatio
Use fiddler or another http traffic capture tool and capture the network traffic. You should be able to see the request that was initiated and take it from there.
I have a .NET web service which is protected by a custom authentication module. The module returns a 403 status code and ends the response (see appendix.)
The authentication module is working as expected, valid authorised users are correctly able to see the properly rendered ASMX content. However, in IIS6 (or the Visual Studio Development Server) the following response is given for unauthorised users;
IIS express (correctly) gives;
(I've not tested this in IIS7, I assume the response would be similar to directly above, I'd be grateful if someone could verify this.)
Looking at the HTTP headers, the 403 status code is being returned to the client alongside the XML Parsing error. I'd like understand why the parsing error is generated (after the response should have been flushed and ended) and how to force the web server to serve a simple 403 response instead.
Appendix
public class IPAuthentication : IHttpModule {
public void Init(HttpApplication application) {
application.AuthenticateRequest += new EventHandler(Application_AuthenticateRequest);
}
private void Application_AuthenticateRequest(object sender, EventArgs e) {
if (!allowed) { //pseudo-code
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.StatusCode = 403;
HttpContext.Current.Response.StatusDescription = "Access denied.";
HttpContext.Current.Response.SuppressContent = true;
HttpContext.Current.Response.End();
}
}
public void Dispose() { }
}
The XML error is being caused by HttpContext.Current.Response.End();.
Try using HttpContext.Current.ApplicationInstance.CompleteRequest(); or HttpContext.Current.Reponse.Redirect(url, false); instead.
More information about using CompleteRequest was provided in this StackOverflow answer.
From the StackOverlow posted answer above,
"use CompleteRequest() to end a normal request.
CompleteRequest causes the ASPNET 'pipeline' to jump ahead to the EndRequest event, after the current HttpApplication event completes.
So if you call CompleteRequest, then write something more to the response, the write will be sent to the client."
And here is another good post that I found, describing why Response.Close and Response.End should never be used except in rare error conditions.
Info from that link that I found useful is that "You might consider calling CompleteRequest instead if you want to jump ahead to EndRequest and send a response to the client."
And in one of the comments to the blog post at that link, "CompleteRequest causes the 'pipeline' to jump ahead to the EndRequest event, but this only happens after the current HttpApplication event completes. Frequently the code that runs in the current HttpApplication event, after you call CompleteRequest, does not harm anything. In the case here, the page handler continues to run, so all the page events will fire. If that is causing harm, and you can’t mitigate that by remembering whether or not you called CompleteRequest, then you may need to use Response.Redirect(url, true) instead."
However, on the MSDN Response.Redirect page it says, "When you use this method in a page handler to terminate a request for one page and start a new request for another page, set endResponse to false and then call the CompleteRequest method. If you specify true for the endResponse parameter, this method calls the End method for the original request, which throws a ThreadAbortException exception when it completes. This exception has a detrimental effect on Web application performance, which is why passing false for the endResponse parameter is recommended. For more information, see the End method.", which indicates to me that Response.Redirect(url, false) should be used in most cases instead of passing true, and is safer than using CompleteRequest.
Here #GlennBlock mentioned that throwing HttpResponseException immediately stops request execution while returning HttpResponseMessage does not stop request propagation (as I understood it).
The exception is useful to immediately stop processing and exit.
If instead I return HttpResponseMessage, the request will happily continue the rest of it's processing and return a 404. The main difference being end the request or not.
In .NET Web API 2 you can also return IHttpActionResult from ApiController. Does it stop request propagation or it works similar to HttpResponseMessage?
Thank you;)
I think #GlennBlock is technically wrong here. Throwing an HttpResponseException does not do anything significantly different than returning an HttpResponseMessage.
Here is the pattern used in ASP.NET Web API courtesy of the source code:
try
{
return await SendAsyncCore(request, cancellationToken);
}
catch (HttpResponseException httpResponseException)
{
return httpResponseException.Response;
}
catch (Exception exception)
{
exceptionInfo = ExceptionDispatchInfo.Capture(exception);
}
At this point in the pipeline if you had thrown an HttpResponseException it gets treated the same as if you returned an HttpResponseMessage... it behaves exactly the same.
One thing you will notice is that when debugging with Visual Studio the debugger will break on a thrown HttpResponseException (since the catch is not happening in user code). If it's an expected error that happens commonly in normal operation of your site then this can get really annoying! In this case you probably instead want to return an error code with HttpResponseMessage.
On the other hand, if it's a bizarre error which should theoretically not happen then you want to be alerted by the debugger. You don't want the error to be quietly ignored. You want to know about it so you can theoretically fix it. In this case throwing the HttpResponseException makes more sense.
About the only other difference I can tell is that throwing an HttpResponseException allows you to catch it with an IExceptionFilter. Similar to how you can apply an action filter or an authorization filter to a method or controller, you can apply an exception filter to handle all exceptions. Perhaps you want to log them in your database. It's obviously a lot easier to apply an attribute filter than to have to write a try/catch in every single action method.
In this case throwing an exception actually does more work and takes longer than simply returning a response. But it is one difference.
An IHttpActionResult is used to create an HttpResponseMessage. Think of it as a HttpResponseMessage factory where you can write it once and use it by multiple action methods. In this case you could throw the HttpResponseException from within the IHttpActionResult. It's not any different than doing it directly from the action.