I put the authentication attribute that sets:
filterContext.Result = new HttpUnauthorizedResult();
so when I try to access
http://www.mysite.com/Forum/Polls
and I am not authenticated I am redirected to:
http://www.mysite.com/Account/Log?ReturnUrl=%2FForum%2FPolls
I want to have the following line instead:
http://www.mysite.com/Account/Log?back=%2FForum%2FPolls
, so instead of 'ReturnUrl' need 'back'. Where I can ovveride this behaviour. Thanks.
You can rewrite "ReturnURL" on EndRequest event.
This is sample code.
protected void Application_EndRequest()
{
if (Response.StatusCode != 301 && Response.StatusCode != 302) return;
var targetUrl = Response.RedirectLocation.Replace("ReturnUrl","back");
Response.RedirectLocation = targetUrl;
}
Hope this code.
It doesn't look like you can. That comes from System.Web.Security.FormsAuthentication.GetLoginPage()
If you look at the code, you see that it is indeed a hard coded literal. At least in System.Web version 2.0.0.0
Related
I'm coding a simple URL shortener.
Everything is working, except the redirection.
Here is the code that tries to redirect:
public async Task<ActionResult> Click(string segment)
{
string referer = Request.UrlReferrer != null ? Request.UrlReferrer.ToString() : string.Empty;
Stat stat = await this._urlManager.Click(segment, referer, Request.UserHostAddress);
return this.RedirectPermanent(stat.ShortUrl.LongUrl);
}
When I input a link that is shortened, like this http://localhost:41343/5d8a2a, it redirects me to http://localhost:41343/www.google.com.br instead of www.google.com.br.
EDIT
After checking the answer, it works. Here is the final snippet of code.
if (!stat.ShortUrl.LongUrl.StartsWith("http://") && !stat.ShortUrl.LongUrl.StartsWith("https://"))
return this.RedirectPermanent("http://" + stat.ShortUrl.LongUrl);
else
return this.RedirectPermanent(stat.ShortUrl.LongUrl);
Thanks!
Instead of RedirectPermanent() try using Redirect() like below. The specified URL has to be a absolute URL else it will try to redirect to within your application.
You can check for existence of http:// and add it accordingly
if(!stat.ShortUrl.LongUrl.Contains("http://"))
return Redirect("http://" + stat.ShortUrl.LongUrl);
(OR)
Use StartsWith() string function
if(!stat.ShortUrl.LongUrl.StartsWith()("http://"))
return Redirect("http://" + stat.ShortUrl.LongUrl);
So I am returning detailed 400 error responses from my MVC web app. Setting existingResponse="PassThrough" works, but that's not what I want. I don't want to expose all failures, I only want to expose them when I have custom responses.
Auto, is set by default, but I deliberately set it. However, the documentation says "SetStatus" flag must be set, but I have no idea how to do such a thing. I wrote the following four controller methods in order to test it, and only BadRequestD works. The others set the status code and the status just fine, but the body content is "Bad Request".
public ActionResult BadRequestA()
{
Response.StatusCode = 400;
return Content("weeeeee");
}
public ActionResult BadRequestB()
{
Response.Status = "400 U DUN MESSED UP";
return Content("weeeeee");
}
public ActionResult BadRequestC()
{
Response.Status = "400 U DUN MESSED UP";
Response.StatusCode = 400;
return Content("weeeeee");
}
public ActionResult BadRequestD()
{
Response.StatusCode = 400;
Response.TrySkipIisCustomErrors = true;
return Content("weeeeee");
}
However, the documentation says "SetStatus" flag must be set, but I have no idea how to do such a thing
It's actually talking about the fTrySkipCustomErrors flag/argument to the IHttpResponse::SetStatus method in the IIS C++ SDK (see note I added to bottom of documentation here). But in ASP.NET the flag is exposed as Response.TrySkipIisCustomErrors. So according to:
http://www.iis.net/configreference/system.webserver/httperrors
Auto = Leaves the response untouched only if the SetStatus flag is set
I would expect to see IIS replace the response with its own html error page content (you can configure what that content is) by default unless you set:
Response.TrySkipIisCustomErrors = true;
Which is what you're seeing.
Additional related info, in MVC5 it seems to act as if that flag is true even if it's false for uncaught exceptions which I don't see in WebForms. As a workaround in Global.asax I'm:
protected void Application_Error()
{
var error = Server.GetLastError();
Server.ClearError();
//code to log error here
var httpException = error as HttpException;
Response.StatusCode = httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;
}
If you need to have custom responses with 4xx http statuses and still want to use Custom Error Pages here's what you should do:
set existingResponse="Auto" in web.config;
set TrySkipIisCustomErrors = true in your action (one that returns 4xx status and a content);
clear server error in global.asax (in Application_Error() - Server.ClearError()) and re-set the status code (Reponse.StatusCode = ((HttpException)Server.GetLastError()).GetHttpCode())
It's weird that IIS team didn't implement existingResponse attribute for specific status codes, so it's impossible to use existingResponse="PassThrough" just for one (or few) codes.
In my C# .NET 4 MVC 3 application I have a delete controller for a set of CRUD pages which uses the Post Redirect Get pattern to redirect to an Index controller after a successful delete. I would like to render a button on the Index page only if this page was NOT redirected to by such an action. Is there a simple way to detect if the current page was redirected to (i.e. was reached as the result of a PRG redirect)?
After reading http://blog.simonlovely.com/archive/2008/11/26/post-redirect-get-pattern-in-mvc.aspx my current approach is to set this in my delete controller with TempData after the DeleteMyEntity method has succeeded:
try {
MyService.DeleteMyEntity(MyViewModel.MyEntity);
TempData["Redirected"] = true;
args = new RouteValueDictionary(new { Foo = 1, Baa = 2 });
return RedirectToAction("Index", args);
} catch (Exception e)
{
//Logging etc. - redirect should never be reached on exception (and TempData item not set)
throw(e);
}
then in my Index controller I check to see if this value exists and is true:
if (TempData["Redirected"] != null)
{
//we can then do something useful with this
}
Another opportunity I see would be to add another item to args and check for this in the controller, but in this case I may as well just use TempData. Is there a way to do this using a HTTP Response code on the request without needing to pass this data through with TempData or a similar mechanism?
another route would be to set up a global actionfilter that "injects" that flag for you...
public class RedirectDetect: ActionFilterAttribute{
public override void OnActionExecuted(ActionExecutedContext filterContext){
if (filterContext.Result is RedirectToRouteResult ||
filterContext.Result is RedirectResult)
{
TempData["Redirected"] = true;
//or what ever other indicator you want to set
}
}
}
And then you can just call redirectToAction("Index") and then check in your receiving handler
sidenote: I challenge you to say RedirectDetect aloud and not smirk.
I use TempData in a similar fashion - for instance, to show a status message (after redirecting to) my view when a record has been added / updated / deleted. This is the kind of simple, throw-away stuff that TempData is used for, so I say what you have is appropriate.
Personally I wouldn't mess with HTTP status codes unless I had an absolute need for it. And you could probably do something with the referrer http header, but again, that would be much messier and more complicated than just using TempData. You have a clean, simple solution that works, I say go with what you have.
I am not aware of any simpler mechanism and have been using TempData for quite some time to implement Post-Redirect-Get features. As far as I know, this is specifically one of the reasons for TempData's existence. I would continue using it.
There is no way to tell the difference between requests as a result of a 3xx redirection or a straightforward user-initiated GET. The best way is to provide a querystring argument that is only appended by the redirection for the initial POST request, but there is nothing stopping the user from reloading the page with the same querystring.
Hmmm, or you could send a cookie with the redirection from the POST, then remove the cookie in the response of the subsequent GET, like so:
public ActionResult PostHandler(ViewModel model) {
SetCookie("redirected", "true"); // psuedocode
return Redirect("GetHandler2");
}
public ActionResult GetHandler2() {
if( GetCookie("redirected") == "true" ) {
// do something
}
DeleteCookie("redirected");
}
Building off of George's answer:
public class MarkRedirects : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Result is RedirectToActionResult ||
context.Result is RedirectResult)
{
// Obtain and verify the underlying IController
var controller = context.Controller as Controller;
if (controller != null)
controller.TempData["Redirected"] = true; // or set other dictionary data here
}
}
}
The conditional checks of context.Result can vary based on what method you used to redirect, for instance if you redirected the user via the RedirectToAction() method, context.Result is RedirectToActionResult will return true but context.Result is RedirectToRouteResult will not.
Because of this, you will want to change up that conditional based on your personal taste of how you redirect users. The current code would work for OP's situation.
If you're going to be using this everywhere, it may be wise to modify a base controller.
All the users on my site have public-facing profile pages. I am using URL rewriting to change urls from the form http://mysite.com/profile.aspx?id=sdsdfsdsdfsdfdsdffsdfsdf into http://mysite.com/Username like this (in my global.asax file):
static Regex _handleRegex1 = new Regex("/(?<hndl>[\\w]+)/?$", RegexOptions.Compiled);
void Application_BeginRequest(object sender, EventArgs e)
{
System.Text.RegularExpressions.Match handleMatch = _handleRegex1.Match(Request.Url.LocalPath);
if(handleMatch.Success){
String handle = handleMatch.Groups[1].Value;
using (SqlQuery query = new SqlQuery("[dbo].[sp_getUserIdByHandle]"))
{
try
{
query.AddParameter("#handle", handle, System.Data.SqlDbType.NVarChar, false);
query.AddParameter("#userId", new Guid(), System.Data.SqlDbType.UniqueIdentifier, true);
query.ExecuteNonQuery();
Object userId = query.GetOutParameter("#userId");
if (userId == DBNull.Value)
{
Response.Redirect("~/default.aspx");
}
else
{
Context.RewritePath(string.Format("~/profile.aspx?id={0}&{1}", userId, Request.QueryString));
}
}
catch (Exception ex)
{
}
}
}
}
This works fine. However, if I do a postback to the server, the URL changes from something like /username to the form /profile?id=5ab47aa3-3b4d-4de6-85df-67527c9cdb52&, which I want to hide from the user.
I thought about doing something like Response.Redirect(Request.RawUrl); to sent the user back to the right page. However, Request doesn't seem to contain any information about the desired URL.
Is there any way to find the pre-rewritten URL?
What platform are you on? If IIS 7 you would be best off using IIS URL Rewrite 2.0. You can find some suggestions on dealing with postback using this.
I suggest you use Routing, that way you can write your code the ASP.NET way but still have the Urls you want:
Routing with ASP.NET Web Forms
i am trying to remove default.aspx from any request that might have it.
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
string url = context.Request.Url.ToString();
// remove default.aspx
if (url.EndsWith("/default.aspx", StringComparison.OrdinalIgnoreCase))
{
url = url.Substring(0, url.Length - 12);
context.Response.Redirect(url);
}
}
gives an error:
**too many redirects occurred trying to open...**
what can i change to make it work?
thnx
k got it.
instead of using:
string url = context.Request.Url.ToString();
i tried:
string url = context.Request.RawUrl.ToString();
and that WORKS! together with what you guys said :)
I think that if you put the redirect inside the if you don't have to deal with infinite redirects.
You are endlessly redirecting.
Each time the following line executes the Application_BeginRequest event is fired again.
context.Response.Redirect(url);
Put the redirect inside the if statement like this.
if (url.EndsWith("/default.aspx", StringComparison.OrdinalIgnoreCase))
{
url = url.Substring(0, url.Length - 12);
context.Response.Redirect(url);
}