Determine the URL hostname without using HttpContext.Current? - c#

Using the current request I can get the URL hostname with:
HttpContext.Current.Request.Url.Host
But - I need to determine the URL hostname without using the current request (HttpContext.Current). The reason for this is that my code is called from a SqlDependency in the onChange callback for when a SQL Dependency is found. Althougth the code resides in my web app, there is no request, and HttpContext.Current is null.
I was hoping I could grab it from HttpRuntime, but there doesn't seem to be anything of use there. is there a way I can get this information?

If you are running this from a web application, and it is all managed code then HttpContext must exist. Does your child library (assuming your managed code is in a library) have a reference to System.Web? If not, consider adding this reference. From that point you should be able to access the HttpContext directly by using the fully qualified namespace:
System.Web.HttpContext.Current.Request.Url.Host
In any case, unless your code is unmanaged or your context truly does not originate with a web application, HttpContext should be available at every point while the thread is alive.
Edit:
Based on reading your comment below, it sounds like the SqlDependency is being fired independently. While it's on the same thread, it's not being fired directly by the request. Since all you're looking for is the host url, it's not inconceivable that you can create an application variable or a static variable to hold this information in the event that it is needed for a dependency.
Also something I have seen is that while HttpContext.Current may not be available, HttpContext.Request might be. These should be the same object, but they may not necessarily be. It's possible that the Host may be found there.

How about
Environment.MachineName

If you know the host at the moment you're setting up the event handler then you should be able to do something like (code not actually tested):
string host = HttpContext.Current.Request.Url.Host;
var dep = new SqlDependency(cmd);
dep.OnChange += ((sender, args) =>
{
DoStuff(host);
});

You should use the IIS api to query the information from the website you're looking for. Because depending on the IIS configuration your URL or Hostname could be differing. (Think about hostheaders, ports, protocols and stuff like this.
A introduction for IIS API could be found at http://learn.iis.net/page.aspx/165/how-to-use-microsoftwebadministration/

Related

Get remote IP address in DotVVM

I'm building an app using DotVVM framework (ver 1.1.9) using AspNet.Core and .NET Framework 4.7.1.
At some point I need to log remote user's IP address. Is there a way to get it inside the ViewModel? I've seen many tutorials
There is a property Context in ViewModelBase that has property HttpContext but it's some build-in IHttpContext interface, not the proper HttpContext.
However I found out that I can cast existing IHttpContext to DotvvmHttpContext which contains property OriginalContext that indeed seems to be the one I was looking for.
var remoteAddr = ((DotvvmHttpContext)Context.HttpContext).OriginalContext.Connection.RemoteIpAddress;
So the question is, if this is "safe" approach or is there any other "proper" way to either access original AspNet HttpContext or the remote IP Address directly?
Yes, this is safe approach as long as you are only going to run the application on Asp.Net Core. If you'd switch to OWIN hosting for some reason, it would throw an invalid cast exception.
Also note that there is a helper method for getting the Asp.Net Core http context, Context.GetAspNetCoreContext().Connection... might be a bit more comfortable. As you can see from the source code, it's basically the same as your code: https://github.com/riganti/dotvvm/blob/d623ae5ddf57ecf3617eb68454d546f675b64496/src/DotVVM.Framework.Hosting.AspNetCore/Hosting/AspNetCoreDotvvmRequestContextExtensions.cs#L13
Looking at the source for IHttpContext that is exposed in the DotvvmViewModelBase, there does not seem to be a good way to access the connection information. I was hoping that the IHttpRequest might expose the remote IP address but that also isn’t the case.
You have to rely on accessing the original HttpContext from ASP.NET Core here to access that information. If you run on ASP.NET Core (instead of OWIN), then it should be totally save to cast the context to DotvvmHttpContext so that you can access the underlying HttpContext.
So yeah, your solution seems just fine here:
var originalHttpContext = ((DotvvmHttpContext)Context.HttpContext).OriginalContext;

Is it possible to get the hostname(sitename) at the time of registering middleware in Owin startup?

I have a middleware that needs options object to start. One of the properties is hostname.(I mean its to be set up like http://mywebsite.com and not the physical machine name). The middleware is configured to do some business logic at startup and so app.Run() and app.Use() isn't an option.
I also cannot hardcode hostname(as I run multiple instances with different site names), or get it from the config file, because:
1. its duplication of information which I could otherwise get from database, if only I knew the hostname
2. I wouldn't still be sure which one out of the many site instances I have, was invoked
var options = new MyMiddlewareOptions{
hostname = <hostname of the server hosting this app>,
.
..
...
//other properties
};
app.UseMyMiddleware(options);
How can I get the hostname at the time of Owin Startup since there is no request or Environment data available?
I have tried using inline middleware, and I get the hostname but by then its too late.
something on the lines of:
app.Use((ctx,next) =>
{
host = ctx.Request.Uri.Host;
var options = new MyMiddlewareOptions
{
hostname = host
};
app.UseMyMiddleware(options);
return next.Invoke();
}
The above does give me the Hostname, but it is too late to register a new middleware when a request is already in progress and therefore it doesn't really do things it should.
Is there a way to get the hostname at the time of startup when middlewares are getting registered?
There is no absolute way of getting the host name until the first request has been received. It depends on what you're hosting the site on. When it's self hosting, you can do app.Properties["host.Addresses"]. IIS Express however is a different story - that key for a start doesn't exist (I don't if there is a way at all).
Use the app.map('pathYouWant', methodYouNeed);
I have a example in Portuguese using this method.
Access here, you can learn more about this.

how to send a request to one of the IIS handlers programatically?

i have a legacy 3rd party application which submits data to our internal sales system. It exposes ASP page with a form to the internet as follows:
<form id="ServiceRequest" enctype="multipart/form-data" method="post" action="AddToServiceRequest.csp">
where AddToServiceRequest.csp is a proprietary IIS handler:
Right now we embed this form into our ASP.Net 4 website using iframe - and that is really inconvenient. What I want to do is to replace this form with a native form, do all validation etc - and then call AddToServiceRequest.csp handler from code-behind logic. What's the right way to do it? I can think only about something like this:
var r = (HttpWebRequest)WebRequest.Create("http://localhost/AddToServiceRequest.csp");
r.Method = "POST";
r.KeepAlive = false;
// fill in form data
var res = r.GetResponse();
res.Close();
but it just does not look "right" to me. Are there any other ways?
If handler serving request is for some other site (from IIS point of view) than code for it will run in separate process or separate AppDomain and you will have no reasonable way to call it directly.
If handler is registered for the same site as yours you may be able to invoke it directly - i.e. if it is APS.Net class that handles request than it just an interface with couple methods - you may be able to instantiate and execute it directly. Note that many handlers depend on HttpContext.Current and you may not be able to set request reasonably for such calls.
It is also unlikely to register same handler to your site as most handlers/controllers/forms are designed to work for particularly configured site (i.e. Web.Config will have DB connection info).
So making direct web request is most straightforward solution. I would not try any other way as most web code will not handle unusual ways of invocation correctly.
You may consider HttpClient instead of WebRequest to get easier async supoprt (assuming .Net 4.5+), but any way of setting up request is ok.
Note that if site uses Windows Authentication you may not be able to pass user information via Web request .

Access current domain name on Application_Start

Normally to access the current domain name e.g where the site is hosted I do something like
string rURL = HttpContext.Current.Request.Url.ToString().ToLower();
But HttpContext is not avaible on Application_Start only from Application_BeginRequest.
Any ideas?
A single IIS application can be bound to many different URLs. Application_Start fires before any request has been received, so the only way to find the domain name to which the site is bound is to query IIS.
Even then you may not be able to get an answer - consider the situation where an application is bound to a wildcard / default hostname.
A better approach may be to look at Application_AuthenticateRequest. This fires before Application_BeginRequest and does give you a full HttpContext.Current.Request object.
Try Dns.GetHostName().
You can use this in Gloabl.asax.cs, no matter within Application_Start() or not.
var hostName = Dns.GetHostName();
tested in Asp.net 4.5 MVC.
The IIS application does not know what domain its accessed from (see bindings) at application start.
One way of achieving this is a little bit of a cheat and comes with caveats, and that's to use System.Web.Hosting.HostingEnvironment.SiteName.
So this would look like:
string rURL = System.Web.Hosting.HostingEnvironment.SiteName;
And now for those caveats:
This is the name of the site in IIS.
That means your site name can be a non-URI (eg My Awesome Site).
If you have multiple domains sharing the same site, it'll be the same for each one.
For my purposes - setting up logging on servers where I had multiple sites in IIS pointing to the same physical folder - the above solution was probably the simplest and easiest. I'm not saying it's necessarily the 'right' answer, but it should be considered as an alternative.

How to get the physical location of an ASP.NET web application without using HttpContext.Current?

I've found myself having a requirement to configure log4net based on a file relative to the physical location of the running ASP.NET web application. We like to start the logger as early as possible, so Application_Start seems a proper place. In IIS6, this works fine and has been running for ages, but now we moved to IIS7 and this won't work anymore:
string absolutePath = HttpContext.Current.Request.PhysicalApplicationPath;
because the HttpContext.Current is not available in many global.asax (Application, Session) events. This is old news, we all know it raises the now infamous Request is not available in this context error. We don't want to move back to Classic Mode.
Now, the question is simple: without using HttpContext, is it possible to find the physical location of the currently running web application instance?
Try HttpRuntime.AppDomainAppPath. For more info, read IIS7 Integrated mode: Request is not available in this context exception in Application_Start posted by Mike Volodarsky.
As an alternative answer to my own question, I'd like to add that Server.MapPath() works during the Application_Start event as well. The application domain path would then be equal to Server.MapPath("~"), but it's handier for mapping relative paths, removing the burden of concatenation (what MapPath was meant for to begin with).

Categories