Setting Context.Response.StatusCode does not seem to work - c#

I have an HttpHandler with the following code:
using System;
using System.Web;
using Company.Cms;
using Company.Web.Handlers.Console;
namespace Company.Web.Handlers
{
/// <summary>
/// Summary description for AdminHandler
/// </summary>
public class AdminHandler : IHttpHandler
{
public bool IsReusable
{
get
{
return false;
}
}
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string action = request.QueryString["action"];
if (!HttpContext.Current.User.CanAdminister())
{
response.StatusCode = 403;
response.Status = "403 Access Denied";
response.End();
return;
}
if (String.IsNullOrEmpty(action))
{
response.StatusCode = 404;
response.Status = "404 Not Found";
response.End();
return;
}
IHttpHandler handler = null;
switch (action)
{
case "menu":
handler = new MenuHandler();
break;
case "tree":
handler = new TreeHandler();
break;
case "grid":
handler = new GridHandler();
break;
case "list":
handler = new ListHandler();
break;
case "drop":
handler = new DropHandler();
break;
case "edit":
handler = new EditHandler();
break;
case "new":
handler = new InsertHandler();
break;
}
if (handler == null)
{
response.StatusCode = 404;
response.Status = "404 Not Found";
response.End();
}
else
{
handler.ProcessRequest(context);
}
}
}
}
Unfortunately when I intentionally specify an invalid action, the browser just displays a blank page. Non of the browser error messages are displayed both in Firefox and IE.
What could I be doing wrong?
EDIT - IE shows the error message, but Firefox does not.

First Try this:
protected void Page_Load(object sender, EventArgs e)
{
Response.StatusCode = 404;
Response.SuppressContent = true;
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
:)~

Firebug shows the correct status. Does
this mean that if I want the browser
to display a message, I have to render
it myself? – deverop
Absolutely it does. What the browser does based on an error code received is up to the browser. But you can still provide HTML to go along with the 404. Case in point... take a look at Stack Overflow's 404 page. That error message is entirely hand crafted.
Typically, however, you want to limit the amount of data returned from an error status; the more data you return from an erroneous request, the larger the surface of attack for denial of service.

I had a similar problem, which occures in IIS 7.0 only. What you could also try is to set
Response.TrySkipIisCustomErrors = true;

For 301 redirects use Response.RedirectPermanent().
For 302 redirects use Response.Redirect()
if (isPermanentRedirect)
{
// 301 Redirect
args.HttpContext.Response.RedirectPermanent(targetUrl);
}
else
{
// 302 Redirect
args.HttpContext.Response.Redirect(targetUrl);
}

Related

Global Error Handling in ASP.NET Core MVC

I tried to implement a global error handler on my Asp.net core mvc web page. For that I created an error handler middleware like described on this blog post.
public class ErrorHandlerMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception error)
{
var response = context.Response;
response.ContentType = "application/json";
switch (error)
{
case KeyNotFoundException e:
// not found error
response.StatusCode = (int)HttpStatusCode.NotFound;
break;
default:
// unhandled error
response.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
var result = JsonSerializer.Serialize(new { message = error?.Message });
await response.WriteAsync(result);
context.Request.Path = $"/error/{response.StatusCode}"; // <----does not work!
}
}
}
The middleware works as expected and catches the errors. As a result i get a white page with the error message. But i am not able to display a custom error page. I tried it with the following line of code. But this does not work.
context.Request.Path = $"/error/{response.StatusCode}";
Any ideas how I can achive my goal?
Thanks in advance
It seems that you wish to redirect the browser to an error page.
To do this you'll need to replace:
context.Request.Path = $"/error/{response.StatusCode}";
With
context.Reponse.Redirect($"/error/{response.StatusCode}");
Also, since you're sending a redirect, the response content needs to be empty, so remove the response.WriteAsync bit too.
var result = JsonSerializer.Serialize(new { message = error?.Message });
await response.WriteAsync(result);

Do "if" in Application WebConfig if it is posible

I want to do like this -
but I cent rite razor by web config.
Is there a way to write razor or do it in a different way to my goal will only manager see the errors
Apologize in advance for my English
#using Or50Core.Controllers;
#if ((BaseController)this.ViewContext.Controller).IsAdministrator())
{
<system.web>
<customErrors mode="Off"></customErrors>
</system.web>
}else{
<system.web>
<customErrors mode="On"></customErrors>
</system.web>
}
"if" do the work in views
you would be far better off using logging. That way you catch all the errors (not just ones the administrator gets) in the log files/DB but the users only get a friendly error.
You can use this code:
#{
var configuration = WebConfigurationManager.OpenWebConfiguration("~");
var section = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");
if (section != null)
{
#if ((BaseController)this.ViewContext.Controller).IsAdministrator())
{
section.Mode = CustomErrorsMode.Off;
}
else
{
section.Mode = CustomErrorsMode.On;
}
}
configuration.Save();
}
this code needs to add #using System.Web.Configuration; to view.
Edit:
For manage users you can use ASP.NET Identity and for manage error page you can use Custom Error Page.
You have to write Application_Error method in your Global.ascx. In this method you can check if current user is in Admin role or not and based on that you can show the real error or just a simple error page.
protected void Application_Error()
{
if (!User.IsInRole("Administrator"))
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Errors";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new ErrorsController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
}
Here you determine what users see based on each error
public class ErrorsController : Controller
{
public ActionResult General(Exception exception)
{
return Content("General failure", "text/plain");
}
public ActionResult Http404()
{
return Content("Not found", "text/plain");
}
public ActionResult Http403()
{
return Content("Forbidden", "text/plain");
}
}
BTW I find the answer in Here

Displaying an error page MVC

I am catching unhandled errors using the Application_Error method within my Global.asax file, this is what I have so far:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
if(httpException != null)
{
string action;
switch(httpException.GetHttpCode())
{
case 404:
action = "404";
break;
case 500:
action = "500";
break;
default:
action = "Other";
break;
}
Server.ClearError();
Response.Redirect(String.Format("~/Error/?error=" + action + "&message=" + exception.Message));
}
}
However I really don't like the idea of redirecting the user to error page, infact I would like the URL to remain the same.
For example when a page doesn't exist it shouldn't redirect to the path in the URL, instead it should remain on the same page but still display an error.
Does anyone know how to do this?
My solution redirects much like yours, but depending on how you deploy I would do this by customising the error pages themselves in IIS.
Check Out this answered question

Redirect User to sub domain based on IP

I am trying to redirect the user to sub domain based on his IP address location. I have a page load observer which runs a function on each request and it gets the user Location and when I try to redirect to another domain it gives me "Too many redirects" error and I can't figure out a way to solve this issue.
Currently my code looks like as follows
string CountryName = "";
var Country = HttpContext.Current.Response.Cookies["Country"];
Country.Expires = DateTime.Now.AddDays(365);
var ip = HttpContext.Current.Request.UserHostAddress;
if (!string.IsNullOrEmpty(ip) && ip != null && ip != "127.0.0.1")
{
using (var client = new WebServiceClient(xxxxx, "xxxxxxxx"))
{
var IpCountry = client.Country(ip);
CountryName = IpCountry.Country.Name;
}
switch (CountryName)
{
case "Denmark":
if (Country.Value != CountryName)
{
Country.Value = CountryName;
HttpContext.Current.Response.Redirect("/");
}
break;
case "United Kingdom":
if (Country.Value != CountryName)
{
Country.Value = CountryName;
HttpContext.Current.Response.Redirect("/en");
}
break;
case "Germany":
if (Country.Value != CountryName)
{
Country.Value = CountryName;
HttpContext.Current.Response.Redirect("/de");
}
break;
case "Sweden":
if (Country.Value != CountryName)
{
Country.Value = CountryName;
HttpContext.Current.Response.Redirect("/se");
}
break;
case "Norway":
if (Country.Value != CountryName)
{
Country.Value = CountryName;
HttpContext.Current.Response.Redirect("/no");
}
break;
default:
if (Country.Value != CountryName)
{
Country.Value = CountryName;
//HttpContext.Current.Response.Redirect("http://www.google.com");
}
break;
}
}
else if (loadedArgs.pageview.Area.ID != 2)
{
HttpContext.Current.Response.Redirect("/choose-country");
}
Further more I also would like to know what could be other possible ways to handle this scenario in more better way so this code don't run on every page load once the cookies are set. Many thanks in advance.
I do not have access to your code, but, if I am reading your code right the fix for the redirect issue is to check for the cookies existence before any creation/ redirection logic. I made some changes, please give this a try and let me know of any issues.
var context = HttpContext.Current;
var cookieName = "Country";
var ip = context.Request.UserHostAddress;
if (!string.IsNullOrWhiteSpace(ip) && ip != "127.0.0.1")
{
//If the cookie is present (means cookie is set already) then return
if (context.Request.Cookies[cookieName] != null)
{
return;
}
string countryName;
using (var client = new WebServiceClient(xxxxx, "xxxxxxxx"))
{
var ipCountry = client.Country(ip);
countryName = ipCountry.Country.Name;
}
context.Response.Cookies.Add(new HttpCookie(cookieName)
{
Value = countryName,
Expires = DateTime.Now.AddDays(365)
});
switch (countryName)
{
case "Denmark":
context.Response.Redirect("/");
break;
case "United Kingdom":
context.Response.Redirect("/en");
break;
case "Germany":
context.Response.Redirect("/de");
break;
case "Sweden":
context.Response.Redirect("/se");
break;
case "Norway":
context.Response.Redirect("/no");
break;
default:
//context.Response.Redirect("http://www.google.com");
break;
}
}
else if (loadedArgs.pageview.Area.ID != 2)
{
context.Response.Redirect("/choose-country");
}
Thank you,
Soma.
you can use the below code to get the client IP address. i.e., the IP address of the machine which requested a page in your website.
String UserIP = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(UserIP))
{
UserIP = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
}
Below is the format we need to use for the API URL.
freegeoip.net/{format}/{IP_or_hostname}
format –> is the response output format. It could be CSV or XML or JSON.
For example, if we would like to get the response in JSON format then we could use the API URL as 'http://freegeoip.net/json/clientIPAddress_here'
string url = "http://freegeoip.net/json/" + UserIP.ToString();
WebClient client = new WebClient();
string jsonstring = client.DownloadString(url);
To get the sample response format, run this http://freegeoip.net/json/XX.XX.XX.XX (replace XX.XX.XX.XX with the required ip address) URL directly in the browser. You will see the below response format.
{
"ip":"xxx.xxx.xxx.xxx",
"country_code":"",
"country_name":"",
"region_code":"",
"region_name":"",
"city":"",
"zip_code":"",
"time_zone":"",
"latitude":0,
"longitude":0,
"metro_code":0
}
Use the below code to convert the response to JSON object and then read the values of JSON object and save to a session variable or some other variable.
dynamic dynObj = JsonConvert.DeserializeObject(jsonstring);
System.Web.HttpContext.Current.Session["LocId"] = dynObj.country_code;
You can also detect the country using the Location header too
On HttpWebRequest you can set AllowAutoRedirect to false to handle the redirect yourself.
// don't allow redirects, they are allowed by default so we're going to override
myRequest.AllowAutoRedirect = false;
// send the request
HttpWebResponse response = myRequest.GetResponse();
// check the header for a Location value
if( response.Headers["Location"] == null )
{
// null means no redirect
}
else
{
// anything non null means we got a redirect
}
Solving the "Too many redirects" issue:
Redirect loop is like a situation wherein > "A points to B and B points back to A"
. Such a redirection will keep browser in an infinite loop and the webpage will never be displayed. In old times, such redirect or infinite loops used to result in a hung browser.Thankfully, modern browsers are able to detect such redirect loops and they break the cycle by displaying an error message: “Error 310 (net::ERR_TOO_MANY_REDIRECTS): there were too many redirects”.
This problem may be caused either at the client end or the server end. If there is no redirection loop on the server side, the problem is likely to be solved just by deleting cookies from the browser.
So I suggest please check your routeconfig.cs for such route Or similar redirect operation that points back to itself after deleting the cookies from the browser
Hope this helps :)
I think the problem lies in the logic that does not identify if the request is before or after redirecting. The sequence seems to be
The code executes once when a URL xyz.com
The redirect to xyz.com/en happens
Again the code executes and tries to redirect to xyz.com/en/en
This can be confirmed with some more debugging.
I suggest your code should execute and redirect if the URL being requested doesn't end with "en" or "de" (the list can be maintained in the application)
You might need to change the way you handle your default country too, because if the logic is no country indicates default country, then what I mentioned above will not work.
In Asp.Net MVC, I have a class that handles invalid IP addresses and re-directs them based on the IP address. I use the following code:
protected override async void HandleUnauthorizedRequest(AuthorizationContext context)
{
var ipAddress = HttpContext.Current.Request.UserHostAddress;
if (await IpAddressValid(ipAddress)) return;
var urlHelper = new UrlHelper(context.RequestContext);
var address = urlHelper.Action("InvalidIpRange", "Account");
context.Result = new RedirectResult(address ?? "www.google.com");
}
private async Task<bool> IpAddressValid(string ipAddress)
{
if (ipAddress == "::1")
return true;
var longIp = Ip2Int(ipAddress);
var addr = await GeoIPCountry.ReturnGeoIpCountries(longIp, longIp); //dbContext.GeoIPCountries.Where(x => x.Start >= longIp && x.End <= longIp);
return addr.All(g => g.CountryCode == "US");
}
/// <summary>
/// Converts IP Address to Long Stack Space.
/// </summary>
/// <param name="ipAddress"></param>
/// <returns></returns>
public int Ip2Int(string ipAddress)
{
try
{
var addr = IPAddress.Parse(ipAddress);
uint ip =
(uint) IPAddress.NetworkToHostOrder((int) BitConverter.ToUInt32(addr.GetAddressBytes(), 0));
return (int)ip;
}
catch (Exception)
{
return 0;
}
}
At the top of each controller that requires it, all you have to do is add the [IpAddressAuthorize] flag and it will handle everything. This happens before any other action so if you should be able to modify it pretty easily.
You don't provide much information on the 'observer that runs on every request', but if it really does run on every request, it will simply run again when you redirect the user after checking their country.
To debug this, simply place breakpoints wherever you call a redirect, and check which one gets repeatedly called.
For example, let's say that the user is from Denmark, in which case you
context.Response.Redirect("/");
But this will cause your 'observer' to run again and redirect again! So you need to check if the redirection already occurred by placing another cookie, or by checking whether the requested page is already a language-specific page and therefore there is no need to redirect again.

HTTP Post using .Net C# in speedway connect software

I am using RFID Speedway connect software in the Speedway reader, I got a PHP sample for HTTP Post and after googled sometime I couldn't find the sample for .Net C#. So I tried in simple asp.net application[hosted in IIS] to receive the HTTP post response from the reader but I never get in to it.
Below is my sample code.
URL assigned in the reader is http://MY_IP/Default.aspx
My asp.net code sample is :
protected void Page_Load(object sender, EventArgs e)
{
System.Text.StringBuilder displayValues = new System.Text.StringBuilder();
System.Collections.Specialized.NameValueCollection postedValues = Request.Form;
Label1.Text = postedValues.AllKeys.Length.ToString();
}
my page never got hit. Can anyone tell me how to achieve the HTTP Post response in C#.
Thanks
Try using a generic handler
myHandler.ashx
public class myHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string requestStr= new StreamReader(context.Request.InputStream).ReadToEnd();
context.Response.ContentType = "application/text";
switch (context.Request.HttpMethod)
{
case "GET":
break;
case "POST":
context.Response.Write("ok");
break;
default:
break;
}
}
public bool IsReusable
{
get { return false; }
}
}

Categories

Resources