In the regular ASP.NET you could do this in a view to determine if the current request was from localhost:
HttpContext.Current.Request.IsLocal
But I can't find something similar in ASP.NET 6/Core/whatever it is meant to be called.
UPDATE: ASP.NET Core 2.0 has a method called Url.IsLocalUrl (see this Microsoft Docs).
I think this code will work, but I haven't been able to test it completely
var callingUrl = Request.Headers["Referer"].ToString();
var isLocal = Url.IsLocalUrl(callingUrl);
But see Will Dean's comment below about this approach:
Anyone thinking about using the 'updated' version which checks the Referrer header should bear in mind that headers are extremely easy to spoof, to a degree that doesn't apply to loopback IP addresses.
Original solution
I came across this looking for a solution to knowing if a request is local. Unfortunately ASP.NET version 1.1.0 does not have a IsLocal method on a connection. I found one solution on a web site called Strathweb but that is out of date too.
I have created my own IsLocal extension, and it seems to work, but I can't say I have tested it in all circumstances, but you are welcome to try it.
public static class IsLocalExtension
{
private const string NullIpAddress = "::1";
public static bool IsLocal(this HttpRequest req)
{
var connection = req.HttpContext.Connection;
if (connection.RemoteIpAddress.IsSet())
{
//We have a remote address set up
return connection.LocalIpAddress.IsSet()
//Is local is same as remote, then we are local
? connection.RemoteIpAddress.Equals(connection.LocalIpAddress)
//else we are remote if the remote IP address is not a loopback address
: IPAddress.IsLoopback(connection.RemoteIpAddress);
}
return true;
}
private static bool IsSet(this IPAddress address)
{
return address != null && address.ToString() != NullIpAddress;
}
}
You call it in a controller action from using the Request property, i.e.
public IActionResult YourAction()
{
var isLocal = Request.IsLocal();
//... your code here
}
I hope that helps someone.
At the time of writing HttpContext.Connection.IsLocal is now missing from .NET Core.
Other working solution checks only for a first loopback address (::1 or 127.0.0.1) which might not be adequate.
I find the solution below useful:
using Microsoft.AspNetCore.Http;
using System.Net;
namespace ApiHelpers.Filters
{
public static class HttpContextFilters
{
public static bool IsLocalRequest(HttpContext context)
{
if (context.Connection.RemoteIpAddress.Equals(context.Connection.LocalIpAddress))
{
return true;
}
if (IPAddress.IsLoopback(context.Connection.RemoteIpAddress))
{
return true;
}
return false;
}
}
}
And the example use case:
app.UseWhen(HttpContextFilters.IsLocalRequest, configuration => configuration.UseElmPage());
None of the above worked for me.
Url.IsLocalUrl works very different and I find it a bit useless:
For example, the following URLs are considered local:
/Views/Default/Index.html
~/Index.html
The following URLs are non-local:
../Index.html
http://www.contoso.com/
http://localhost/Index.html
HttpContext.Connection.IsLocal doesn't exist in .Net Core 2.2
Comparing ControllerContext.HttpContext.Connection.RemoteIpAddress and ControllerContext.HttpContext.Connection.LocalIpAddress also doesn't work in my test because I get "::1" for remote ip and "127.0.0.1" for local ip.
Finally, I used this piece:
IPAddress addr = System.Net.IPAddress.Parse( HttpContext.Connection.RemoteIpAddress.ToString() );
if (System.Net.IPAddress.IsLoopback(addr) )
{
//do something
}
Late to the party, but if I want to check IsLocal in razor views in .Net core 2.2+, I just do this:
#if (Context.Request.Host.Value.StartsWith("localhost"))
{
//do local stuff
}
UPDATE for ASP.NET Core 3.1
You can use this:
if (Request.Host.Host == "localhost") {// do something }
I would also mention that it may be useful to add the below clause to the end of your custom IsLocal() check
if (connection.RemoteIpAddress == null && connection.LocalIpAddress == null)
{
return true;
}
This would account for the scenario where the site is being ran using the Microsoft.AspNetCore.TestHost and the site is being ran entirely locally in memory without an actual TCP/IP connection.
now its
HttpContext.Connection.IsLocal
and if you need to check that outside of a controller then you take a dependency on IHttpContextAccessor to get access to it.
Update based on comment:
HttpContext is intrinsically available in Views
#if (Context.Connection.IsLocal)
{
}
Related
I'm trying to create API integration tests for legacy code I've inherited.
Currently I have a piece of testing code that:
recreate database (using Fluent Migrations)
starts a web app (Owin.Hosting)
makes api call to get auth token
makes api call to authorized endpoint
It works perfectly if I skip first step and do only 2) 3) 4).
It's a bit weird that I'm also able to do steps 1) 2) 3) (so the auth API call works with database recreation included).
I thought my web api isn't working properly, but I'm able to do basic path when I don't recreate database. Then I thought maybe it's not working at all when I recreate database, but I'm able to authorize an user. I have no clues what could I try now.
[Collection("Database Create collection")]
public class RoleControllerTests : IDisposable
{
private readonly IDisposable _server;
private readonly string _url = new Configuration().ServerUrl;
public RoleControllerTests()
{
_server = WebApp.Start<Startup>(_url);
}
public void Dispose()
{
_server.Dispose();
}
[Fact]
public async Task basic_roles_should_exist_in_the_database()
{
// Arrange
var roleApi = RestClient.For<IRoleController>(_url);
IAuthorize auth = new Authorize();
roleApi.AuthenticationHeader = await auth.GetAuthenticationHeaderAsync();
// Act
var rolesData = await roleApi.List();
// Assert
rolesData.ShouldContain(x => x.Name == "User");
rolesData.ShouldContain(x => x.Name == "Displayer");
}
}
So I've changed testing framework to NUnit and it's working.
I have no idea why, does XUnit have some issues with changing things in runtime?
I'm trying to detect if the website is running in local to display the stack trace instead of a nice server error page. I've been happily using Request.IsLocal in the Global.asax.cs file locally and on internal environments, but when it gets deployed to an Azure app it behaves as if the request was indeed local.
According to the documentation this actually checks if the originating IP was 127.0.0.1 but I don't understand how can that be. Is this just some weird Azure underlying problem?
I didn't see same problem. But, I think, you can try doing IsLocal with the following code.
public static class HttpRequestExtensions
{
public static bool IsLocal(this HttpRequest req)
{
var connection = req.HttpContext.Connection;
if (connection.RemoteIpAddress != null)
{
if (connection.LocalIpAddress != null)
{
return connection.RemoteIpAddress.Equals(connection.LocalIpAddress);
}
return IPAddress.IsLoopback(connection.RemoteIpAddress);
}
if (connection.RemoteIpAddress == null && connection.LocalIpAddress == null)
{
return true;
}
return false;
}
}
I am writing a c# console client to connect to SignalR service of a server. Using a bit of Wiresharking, Firebugging and examining the .../signalr/hubs document on the server, I was able to connect on the default "/signalr" URL:
var connection = new HubConnection("https://www.website.com");
var defaultHub = connection.CreateHubProxy("liveOfferHub");
connection.Start().ContinueWith(task =>
{
if (task.IsFaulted)
{
Console.WriteLine("Error opening the connection:" + task.Exception.GetBaseException());
}
else
{
Console.WriteLine("SignalR Connected");
}
}).Wait();
Now I need to find out
What hubs are there available on the server to connect to? (ask for a list of them)
What methods can I invoke on the hub? (ask for a list of them)
What services can I subscribe to? And what will be the names of the events I will be handling, and the classes of the objects I will be receiving?
The IHubManager interface or HubManagerExtensions class look promising, but I was not even able to find out, what classes implement it and how to use it. Asp.net/signalr offers only basic documentation and tutorials.
Thanks in advance for pointing me in the right direction!
I think what you are looking for is something like a WSDL for SignalR.
No, SignalR doesn't have something that complex. What you can get, manually, is from the SignalR proxy: ./signalr/hubs.
If you look at this code from the proxy
proxies.chatHub = this.createHubProxy('chatHub'); //hub name
proxies.chatHub.client = { };
proxies.chatHub.server = {
serverMethod: function (firstParameter, secondParameter, thridParameter) { //hub method and number of parameters
return proxies.chatHub.invoke.apply(proxies.chatHub, $.merge(["ServerMethod"], $.makeArray(arguments)));
}
};
you get only:
- hub names (chatHub)
- server methods and number of parameters (serverMethod, 3 parameters)
So, the only info is that your hub looks something like this:
[HubName("chatHub")]
public class ?? : Hub
{
public ?? ServerMethod(?? firstParameter, ?? secondParameter, ?? thridParameter)
{
??
}
}
The client methods are not really in any list and are used on the fly. You can catch them with Fiddler.
I have a code that I want to run in global.asax in ASP.NET. I want this code to run only on localhost and when the code on an EC2 instance, I want it to run another code (the second code should run when I deploy my project on Amazon Web Service EC2 server), how can I do that without using the DEBUG functionality?
To check for whether or not the request is from the local machine, do this:
bool isLocal = HttpContext.Current.Request.IsLocal;
if(isLocal)
{
// Do things that should only be done when request is local here
}
Note: Read HttpRequest.IsLocal documentation for more information.
I guess uyou can pick few environment variables frm these:
Environment Variables (type ENV)
EC2_AMI_ID
EC2_AKI_ID
EC2_ARI_ID
EC2_AMI_MANIFEST_PATH
EC2_PLACEMENT_AVAILABILITY_ZONE
EC2_HOSTNAME
EC2_INSTANCE_ID
EC2_INSTANCE_TYPE
EC2_LOCAL_HOSTNAME
EC2_PUBLIC_HOSTNAME
EC2_PUBLIC_IPV4
EC2_RESERVATION_ID
EC2_SECURITY_GROUPS
RS_EIP
RS_SERVER
RS_SKETCHY
RS_SYSLOG
RS_TOKEN
RS_SERVER_NAME
List taken from here: https://support.rightscale.com/09-Clouds/AWS/FAQs/FAQ_0013_-_What_EC2_environment_variables_are_available_in_RightScripts%3F
I think, that checking for availability of EC2_AMI_ID and EC2_INSTANCE_ID would be enough to answer your questions.
If you are using ASP.NET dev server (VS 2012 and earlier) use this method:
public static bool IsDebugWebServer()
{
if (HttpContext.Current != null && HttpContext.Current.Request != null)
{
return HttpContext.Current.Request.ServerVariables["SERVER_SOFTWARE"] == null || HttpContext.Current.Request.ServerVariables["SERVER_SOFTWARE"] == string.Empty;
}
else
{
return false;
}
}
And if you are using local IIS Express use this:
public static bool IsDebugWebServer()
{
return String.Compare(Process.GetCurrentProcess().ProcessName, "iisexpress") == 0;
}
I picked up the following code from Stackoverflow->a blog re handling custom 404 in Sitecore (which acutally does a 302 redirect to 404 page with status 200 which gets picked up by google as soft 404).
While this works totally fine in our local test servers, the moment we drop it in production the site goes haywire and takes AGES e.g. 8-9 minutes to load and stuff.
public class ExecuteRequest : Sitecore.Pipelines.HttpRequest.ExecuteRequest
{
protected override void RedirectOnItemNotFound(string url)
{
var context = System.Web.HttpContext.Current;
try
{
// Request the NotFound page
var domain = context.Request.Url.GetComponents(
UriComponents.Scheme | UriComponents.Host,
UriFormat.Unescaped);
var content = WebUtil.ExecuteWebPage(
string.Concat(domain, url));
// The line below is required for IIS 7.5 hosted
// sites or else IIS is gonna display default 404 page
context.Response.TrySkipIisCustomErrors = true;
context.Response.StatusCode = 404;
context.Response.Write(content);
}
catch (Exception ex)
{
Log.Error(string.Format("Falling back to default redirection behavior. Reason for error {0}", ex), ex);
// Fall back to default behavior on exceptions
base.RedirectOnItemNotFound(url);
}
context.Response.End();
}
}
P.S: I then replaced ExecuteRequest with my custom one in web.config.
If you have experienced similar thing or know of any issue re this please do shed some light.
Thanks in advance
There is a setting in Sitecore, with which you can get rid of the 302 redirect:
<setting name="RequestErrors.UseServerSideRedirect" value="true" />
With this settings, the url stays the same and the status code is 404. If you want to have some additional logic (like showing a Sitecore item as error page), there is a Shared Source module called Error Manager on the Sitecore Market Place.
Hope that helps.
Check if the server is able to access the hostname of your website.
Servers often do not have access to a DNS and therefore are unable to resolve hostnames. In order for your 404 handler to work, the application needs to be able to access its own hostname to request the 404 page.
To be sure this works, edit the hosts file of the server and add an entry for your hostname there, pointing it to 127.0.0.1
You can resolve it with creating new resolver. It is good solution when you want to give to an user error page in right language. But there some differences in IIS 7.0 and 7.5.
Add processor to your sitecore configuration:
<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel"/>
<processor type="Project.Error404Resolver, Project" />
Processor resolving it:
For IIS 7.0:
public class Error404Resolver : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
if(Sitecore.Context.Item == null && !args.Context.Request.Url.AbsolutePath.StartsWith("/sitecore")
{
args.Context.Response.Clear();
SiteContext site = Sitecore.Context.Site;
if(site != null)
{
Item item404Page = Sitecore.Context.Database.GetItem(site.RootPath + "website/error/404");
if(item404Page != null)
{
Sitecore.Context.Item = item404Page;
args.Context.Response.StatusCode = (int) System.Net.HttpStatusCode.NotFound;
}
}
}
}
}
For IIS 7.5:
public class Error404Resolver : Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
{
public override void Process(Sitecore.Pipelines.HttpRequest.HttpRequestArgs args)
{
if(Sitecore.Context.Item == null && !args.Context.Request.Url.AbsolutePath.StartsWith("/sitecore")
{
args.Context.Response.Clear();
SiteContext site = Sitecore.Context.Site;
if(site != null)
{
Item item404Page = Sitecore.Context.Database.GetItem(site.RootPath + "website/error/404");
if(item404Page != null)
{
WebClient webClient = new WebClient();
webClient.Encoding = args.Context.Request.ContentEncoding;
webClient.Headers.Add("User-Agent", args.Context.Request.UserAgent);
string page = webClient.DownloadString(LinkManager.GetItemUrl(item404Page));
args.Context.Response.StatusCode = (int) System.Net.HttpStatusCode.NotFound;
args.Context.Response.Write(page);
args.Context.Response.TrySkipIisCustomErrors = true;
args.Context.Response.End();
}
}
}
}
}
Whit this you will render error page in current page without redirect and returns to a browser code 404.
I have the same issue at a customer I currently work at (looks like the code was pasted) and actually the reason is pretty obvious: If you execute this call with a url that is not registered in the Sitecore sites config (but accessible via IIS), you will also run through this code. Unfortunately, the WebUtil.ExecuteWebPage call is executed with the wrong url as well, hence you end up stuck in a loop.
Actually you should see a lot of these messages in your log: Falling back to default redirection behavior. Reason for error {0}, probably with timeouts.
If you really want to use your custom handler, you should check if you are in the right site context before calling WebUtil.ExecuteWebPage.