Redirect in MVC does not work as expected - c#

I have the following code:
var redirectIp = string.Format("{0}{1}", Session["CurrentHost"], ip.PathAndQuery);
return new RedirectResult(redirectIp);
When I check the value of redirectIP it gives me:
redirectIp "127.0.0.1:84/Administration/Accounts/ShowSummary?ds=0001" string
However when I step through the code the browser opens and gives me the following:
http://127.0.0.1:84/Administration/Accounts/127.0.0.1:84/Administration/Accounts/ShowSummary?ds=0001
I am totally confused. Anyone have any idea what's happening?

That is how urls, http and browsers work. You forgot the protocol part, so the redirect actually does work as expected, given the url that you are redirecting to.
var redirectIp = string.Format("http://{0}{1}", Session["CurrentHost"], ip.PathAndQuery);
return new RedirectResult(redirectIp);
This will work better for now, but to be able to also cover https, you're better off storing the protocol part in a session variable along with the hostname.

Related

"The page you requested was removed" with 410 and redirect

I have following requirement:
the user comes to a job page in our customer's website, but the job is already taken, so the page does not exist anymore
the user should NOT get a 404 but a 410(Gone) and then be redirected to a job-overview-page where he gets the information that this job is not available anymore and a list of available jobs
but instead of a 302(temp. moved) or a 404(current behavior) google should get a 410(gone) status to indicate that this page is permanently unavailable
so the old url should be removed from the index and the new not be treated as a replacement
So how i can redirect the user with a 410 status? If i try something like this:
string overviewUrl = _urlContentResolver.GetAbsoluteUrl(overviewPage.ContentLink);
HttpContext context = _httpContextResolver.GetCurrent();
context.Response.Clear();
context.Response.Redirect(overviewUrl, false);
context.Response.StatusCode = 410;
context.Response.TrySkipIisCustomErrors = true;
context.Response.End();
I get a static error page in chrome with nothing but:
The page you requested was removed
But the status-code is correct(410) and also the Location is set correctly, just no redirect.
If i use Redirect and set the status before:
context.Response.StatusCode = 410;
context.Response.Redirect(overviewUrl, true); // true => endReponse
the redirect happens but i get a 302 instead of the desired 410.
Is this possible at all, if yes, how?
I think you're trying to bend the rules of http. The documentation states
The HyperText Transfer Protocol (HTTP) 410 Gone client error response code indicates that access to the target resource is no longer available at the origin server and that this condition is likely to be permanent.
If you don't know whether this condition is temporary or permanent, a 404 status code should be used instead.
In your situation either 404 or 410 seems to be the right status code, but 410 does not have any statement about redirection as a correct behavior that browsers should implement, so you have to assume a redirect is not going to work.
Now, to the philosophically right way to implement your way out of this...
With your stated requirements, "taken" does not mean the resource is gone. It means it exists for the client that claimed it. So, do you 302 Redirect a different client to something else that might be considered correct? You implemented that, and it seems like the right way to do it.
That said, I don't know if you "own" the behavior across the client and server to change the requirements to this approach. Looking at it from the "not found" angle, a 404 also seems reasonable. It's not found because "someone" already has the resource.
In short if your requirements are set in stone, they may be in opposition to the HTTP spec. If you still must have a 410 then you would need to change the behavior on the client-side somehow. If that's JavaScript, you'd need to expect a 410 from the server that returns a helpful payload that the client interprets to do something else (e.g. like a simulated redirect).
If you don't "own" the client code... well that's a different problem.
There's a short blog post by Tommy Griffth that backs up what I am saying. Take a read. It says in part,
The “Gone” error response code means that the page is truly gone—it’s no longer available on the origin server and no redirect was set up.
Sometimes, webmasters want to be very explicit to Google and other search engines that a page is gone. This is a much more direct signal to Google that a page is truly gone and never coming back. It's slightly more direct than a 404.
So, is it possible? Yes, but you're going to need to "fake" it by changing both client and server code.
I will accept Kit's answer since he's right in general, but maybe i have overcomplicated my requirement a bit, so i want to share my solution:
What i wanted actually?
provide crawlers a 410 so that the taken job page is delisted from search engine indexes
provide the user a better exeprience than getting a 404, so redirect him to a job-overview where he can find similar jobs and gets a message
These are two separate requirements and two separate users, so i could simply provide a solution for a crawler and one for a "normal" user.
In case someone needs something similar i can provide more details, just a snippet:
if (HttpContext.Current.IsInSearchBotMode())
{
Deliver410ForSearchBots(HttpContext.Current);
}
else
{
// redirect(301) to job-overview, omitting details
}
private void Deliver410ForSearchBots(HttpContext context)
{
context.Response.Clear();
context.Response.StatusCode = 410;
context.Response.StatusDescription = "410 job taken";
context.Response.TrySkipIisCustomErrors = true;
context.Response.End();
}
public static bool IsInSearchBotMode(this HttpContext context)
{
ISearchBotConfiguration configuration = ServiceLocator.Current.GetInstance<ISearchBotConfiguration>();
string userAgent = context.Request?.UserAgent;
return !(string.IsNullOrEmpty(userAgent) || configuration.UserAgents == null)
&& configuration.UserAgents.Any(bot => userAgent!.IndexOf(bot, StringComparison.InvariantCultureIgnoreCase) >= 0);
}
These user-agents i have used for the crawler detection:
<add key="SearchBot.UserAgents" value="Googlebot;Googlebot-Image;Googlebot-News;APIs-Google;AdsBot-Google;AdsBot-Google-Mobile;AdsBot-Google-Mobile-Apps;DuplexWeb-Google;Google-Site-Verification;Googlebot-Video;Google-Read-Aloud;googleweblight;Mediapartners-Google;Storebot-Google;LinkedInBot;bitlybot;SiteAuditBot;FacebookBot;YandexBot;DataForSeoBot;SiteCheck-sitecrawl;MJ12bot;PetalBot;Yeti;SemrushBot;Roboter;Bingbot;AltaVista;Yahoobot;YahooCrawler;Slurp;MSNbot;Lycos;AskJeaves;IBMResearchWebCrawler;BaiduSpider;facebookexternalhit;XING-contenttabreceiver;Twitterbot;TweetmemeBot" />

Query String Parameter Being Lost on Request

i'm developing an MVC 4 web application.
I'm trying to make an url that changes in an authorized/unauthorized context.
I'm generating the following url for unauthorized user:
http://localhost/vendas-web/Login?ReturnUrl=%2Fvendas-web%2FClienteNovo%2FIndex%299999
The first time I've tested, it worked just fine.
But.. the second time I've tried, the query string got lost.. and the url turned into:
http://localhost/vendas-web/Login
When i test it against chrome on anonymous tab, it works FINE.
When i change the value of the last parameter, it works FINE.
There's some sort of cache related to this ?
What i'm doing wrong ?
Soo, my question is:
How do i keep my full url in any scenario ??
Ty
There's really not enough information here, but what you're likely talking about is that the first time a user needs to be authorized, they are automatically redirected to the first URL, which includes the ReturnUrl bit. That's built into the framework to allow the user to be redirected back to that URL after logging in. However, if you need to persist this past that initial first redirect to the login page, that's on you. Any links must manually add the query string param:
#Url.Action("SomeAction", new { ReturnUrl = Request["ReturnUrl"] })
And any forms must include it as a hidden input:
#Html.Hidden("ReturnUrl", Request["ReturnUrl"])
Otherwise, yes, it will be lost, because the literal URL you're now requesting doesn't include it. It's not just magically appended.
My problem was cache...
I've used this annotation to avoid using cache by application.
[OutputCache(NoStore = true, Duration = 0)]

asp.net not saving my cookies

I know it's probably something simple, but I just can't figure it out. Note that I'm doing this on my own PC, not through a server (localhost) and I've considered that might be the issue, but I see nothing online about it being the case so maybe it's just a thought.
So I am trying to simply get a string and store it into a cookie and then read it later. Here's the lines of code that "saves" the cookie and its information:
HttpCookie cookie = new HttpCookie("userName", someInfo);
Response.Cookies.Add(cookie);
lblProof.Text = "Value: " + Request.Cookies["userName"].Value;
If I try this method, it fails. No information is shown on the lblProof. At first, I thought maybe someInfo didn't have anything in it (note it's a string). However, when I set the lblProof.Text to someInfo, it DOES show it. I've tried simply doing
Response.Cookies["userName"].Value = someInfo;
But that didn't work either. So what's causing this thing to not work at all? And yes, I've tried HttpContext.Current.Response and Request.

How do I redirect to my parent action in MVC site?

I have been looking at several pages on here already such as:
How do I redirect to the previous action in ASP.NET MVC?
How can I redirect my action to the root of the web site?
Along with several hours of searching google.
No where seems to have an answer to my problem and I am sure it should be possible within MVC somehow hence the reason I am now here to ask the question.
So the problem I am facing is that I want to allow the user to change the language of the page by choosing a new language from a drop down menu which is in its own partial view hence the problem, I need to redirect to the parent action and not the child. This all works fine as long as i send the user back to the root of the site. Using the following code:
[HttpPost]
public ActionResult RegionSelect(RegionSelectionModel model)
{
var currentUser = Session.GetCurrentUser();
var currentDbUser = Session.GetUserEntity(_dataAccessLayer);
if (!ModelState.IsValid)
{
model.AvailableRegions = CacheHelpers.GetAvailableRegions<RegionView>(_dataAccessLayer, _cache).ToList();
return PartialView("_RegionSelect", model);
}
var selectedRegion = UsersControllerHelpers.SetSelectedRegion(model, _dataAccessLayer, _cache, _website.Client);
var uri = model.OriginalUrl;
var routeInfo = new RouteHelpers(uri, HttpContext.Request.ApplicationPath);
// Route Data
var routeData = routeInfo.RouteData;
routeData.Values.Remove("language");
var defaultClientLanguageCode = _website.Client.LanguagesSupported.FirstOrDefault().Code;
if (currentDbUser.Language.CountryCode != selectedRegion.PrimaryLanguage.CountryCode)
{
//TODO: Decide where to redirect or whether to refresh the whole page...
if ((defaultClientLanguageCode == selectedRegion.PrimaryLanguage.CountryCode) || (model.SelectedRegionId == 0))
{
UsersControllerHelpers.UpdateUsersRegions(currentUser, selectedRegion, _website.Client, _cache, _dataAccessLayer,
Session);
return RedirectToRoute(routeData.Values);
}
routeData.Values.Add("language",selectedRegion.PrimaryLanguage.CountryCode);
return RedirectToRoute(routeData.Values);
}
return RedirectToRoute(routeData.Values);
}
Two of my return statements return to the root page and one returns to the root but with a language so it would be "http://mysite/en-En/" but what if the user is on a page other than the root site? I want to somehow redirect them back to this same action but with the correct language string at the start.
How can i do this?
I have thought of several "hacky" ways of doing this, such as splitting the URL and swapping the language codes over. But ideally I am looking to do this as clean as possible.
Can anyone give me any idea's? Or is it just not possible?
It seems like it should be really simple but apparently not.
Thanks in advance for any help that you can provide.
EDITED
Added new code that is using code from suggested answer below.
I am now having two new problems.
I am getting this error message, if there are any things in the URL such as ?page=1:
A potentially dangerous Request.Path value was detected from the client (?)
If i try and remove the language completely using .Remove(). It removes it fine but when i try and redirect to the page in the default language it adds language?=language to the end of the URI.
Any ideas how i can resolve these two issues?
This option is definitely my answer. Leave me a comment if you need me to drop some code, and I can do that, but the examples on the linked website should get you started.
Use this method to change Request.UrlReferrer into Route data, then merge your language into that, then do a RedirectToRoute with the modified Route data.
Just use RouteData.Values.Add, RouteData.Values.Remove, and RouteData.values["whatever"], then pass that modified RouteData.Values object to RedirectToRoute()

How to encode the redirect_uri for facebook login

I'm trying to build a login link for facebook and I'm I'm getting errors only in some cases. I'm trying to specify a a querystring parameter in redirect_uri token so that I can redirect them back to a specific area of my site after logging in. Here's what works and what doesn't work.
&redirect_uri=http://mydomain.com/login?returnUrl=returnUrl - works
&redirect_uri=http://mydomain.com/login?returnurl=/return/url -doesn't work
&redirect_uri=http%3a%2f%2fmyagentcheckin.com%2flogin%3freturnUrl%3d%2freturn%2furl -doesn't work
It seems that the / in the querystring are causing it to fail. Facebook returns an error when I try it. Anyone know of a way around this?
Instead of including the returnUrl parameter as part of your redirect_uri value, use the state parameter to store this data.
For instance,
https://graph.facebook.com/oauth/authorize?type=web_server&client_id={appid}&redirect_uri=http://www.yoursite.com/oauth/handshake&state=/requested/page
I have experienced something similar, especially with multiple redirects as above.
My solution is to put the returnUrl into the user's session (or perhaps a cookie), so I don't have to wrestle with double-encoding. For the redirect_url, just omit the querystring.
Try using this API that put together. It will remove the hassle of this for you.
No url encoding necessary.
Sample Authentication
Imports Branches.FBAPI
...
Dim SI As New SessionInfo("[application_id]","applicaiton_secret")
SI.AuthenticateUser("http://[my url]", New SessionInfo.PermissionsEnum(){SessionInfo.PermissionsEnum.email, SessionInfo.PermissionsEnum.read_stream}))
Read the response from the URL you provided above from that page.
Dim FSR = FS.ReadFacebooAuthResponse
When I tried what you do, I got a redirect callback something like this.
http://mydomain.com/login?returnurl=%2Freturn%2Furl&code=...
And I decode the "returnurl" value.
Then it worked fine for me.

Categories