.NET - Dynamically get Web Root URL of another project - c#

I have 4 WebForms projects in my solution. I want to be able to do URL redirects to a page in another WebForms project.
Currently I have to set a URL/port number in my project web settings, set that URL in my web config as an app setting, then read it and handle redirecting.
This is a real pain and makes deployments to various environments obnoxious. Is there a way to dynamically handle this via code?
To make the above even more complication I may have all projects mapped in IIS as such:
www.mydomain.com/project1
www.mydomain.com/test/project2
www.mydomain.com/test/project3
But, that shouldn't matter because you can do this to get the Web Root Url for the server that I want to redirect to:
HttpContext.Current.Request.ApplicationPath;
I am not sure if just handling the web config route is my best option or if I can do this dynamically?
Thanks for any assistance.

This is a pretty standard pattern here and believe it or not, convention and configuration are the ways to handle this -- IIS can lie, or IIS might not know what you want it to do and can easily give you the wrong answer. So, as I was saying:
Convention: got some sort of standard relationship for urls within your app? Especially with regards to dev, CI and QA which are typically the frequent deployments? If so, setup a default convention there so that your app always thinks the right way. Typically the best or at least easiest to handle is to have all the different apps under IIS applications off a shared root.
Configuration: usually for production use where you might have url/ssl/other things at play. Make all the folders configurable.
Trick to mining the stuff out of IIS, besides the fact it often doesnt give you the answer you want, is that you've got alot of environmental stuff to work through. Presuming your app can get the permissions to query the metabase, you still need to know the idea of the virtual site, etc. It is actually easier to explicitly specify the URL than to figure it out.

http://www.gotknowhow.com/articles/how-to-get-base-url-in-aspnet
public static string BaseSiteUrl
{
get
{
HttpContext context = HttpContext.Current;
string baseUrl = context.Request.Url.Scheme + "://" + context.Request.Url.Authority + context.Request.ApplicationPath.TrimEnd('/') + '/';
return baseUrl;
}
}

Related

Generating links to self when running behind reverse proxy

How can I generate absolute links to other resources in my RESTful API app when the app is meant to be accessed via a reverse proxy that publishes just the paths under /api?
My app is an API with a common layout of routes like /api, /swagger and /health. It is published on my employer's API management under a path of the form /business-area/api-name/v1. Calling the API both directly and through the API gateway overall works: calling https://api-gateway.company.com/business-area/api-name/v1/some-resource results in internal call to https://my-app.company.com/api/some-resource.
The issue is that the links in my app's responses point directly to the backend app (https://my-app.company.com/api/another-resource), not the the API gateway (https://api-gateway.company.com/business-area/api-name/v1/another-resource). They are generated using IUrlHelper.
I solved the domain by the ForwardedHeadersMiddleware and adding the X-Forwarded-Host by a policy on the API management. Sadly, we are allowed to use just extremely simple policies, so if we published the API using multiple gateways, the current solution would generate link to just a single one. But that is an issue to be solved somewhen later; now it works OK.
I could not get the path to work well. I tried changing the paths using a middleware as hinted in the ASP.NET Core behind proxy docs:
app.Use((context, next) =>
{
context.Request.PathBase = "/business-area/api-name/v1";
if (context.Request.Path.StartsWithSegments("/api", out var remainder))
{
context.Request.Path = remainder;
}
return next();
});
When I insert this middleware high in the pipeline, it breaks the routing, but if I insert it low enough, the routing works OK and only link generation is affected. But it seems that only PathBase change really affects link generation as the /api is still in the generated URI. I can see that the Path of the request object is really changed, though, so it is probably just that link generation uses the routing info directly, without passing through my middleware, which makes sense, but it rules out the middleware solution.
Is wrapping the standard IUrlHelper in my own implementation and postprocessing the URLs it returns a good way to go? I don't know how to go about that. I use the IUrlHelper from the ControllerBase.Url property and debugger tells it is actually an instance of Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper. Doing the wrapping in every action seems wrong (repetitive, error-prone).
Changing the routing so that /api moves to the root is my last resort option as it mixes up the namespaces: technical endpoints like /health and /swagger would live among the actual resources of the API. Is there a reasonable way to avoid that while keeping the links working? This all seems like a pretty standard problem and I am surprised I cannot find how to solve it.
We use .NET 5 and we will migrate to .NET 6 as soon as it is out, if that makes any difference.

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.

URL Rewriting in asp.net c#

I'm working on a real estate website. It would be ideal to have my client's featured properties have their own unique URL like:
www.realestatewebsite.com/featured/123-fake-st/
I'm constructing a CMS for my client so that they can add/delete featured properties in an admin backend, meaning that I need to write a program to automatically add the new URL for them based on the address they input in the database through the CMS.
I'm new to URL Rewrite. What would be the best way to go about this? I've considered using RewriterConfig in the web.config, but then I'm worried I would encounter problems writing a program that adds new rules to the web.config file. I thought about using a regex expression in the RewriterRule to find anything after /featured/ in the URL, but then if I'm just using the address in the LookFor then how would it know which property ID to use in the SendTo?
It would be ideal if I could just have a file put the address after "/featured/" into a string, look in the database for the address and retrieve the Property ID and then redirect the users that way.
As I said, I'm new to URL Rewriting and it would be great if someone could point me in the right direction.
Thanks!
-Aaron
There are different ways of doing this. Common to all solutions are the following:
Set up a algorithm to create the URIs and store them in the database (changing space to - is a simple way to achieve this.
Route the URI by making the address string into a parameter
Routing can be done a variety of ways.
If you have control of the server, or they have control of the server, you have the ability to set up IIS rewriting on the IIS instance on their server (good starter URI).
If this is hosted on an ISP, you may not have this option and have to use IIS rewriting and will have to use ASP.NET routing. Here is a good article to start with to undestand this. If you are using MVC, the routing is "built in".
I would suggest using URL Rewrite Module for IIS7, look here:
http://learn.iis.net/page.aspx/460/using-the-url-rewrite-module/

Parse Subdomain on localhost

The Setup
I am building an app using ASP.NET MVC3, the application makes use of sub domains, i added the following in my hosts file : 127.0.0.1 students.localhost.
This all seems fine, when i debug, the browser opens up localhost:{PORT}, i can browse the site, i can also open up: students.localhost:{PORT}, and the site works perfectly.
In case you were wondering, i made use of: Maarten Balliauw's code to achieve the routing requirements in MVC and subdomains
The Problem
I need to somehow find out what subdomain the user is accessing the site from. If i debug, my and go to my subdomain:http://students.localhost:{PORT} Request.Url is : http://localhost:{PORT}, for some reason the deubugger (or ASP.NET Development Server) is not picking up students.
Please do not go into the TLD descussion trying to explain what a subdomain really is, all i need is the first string after http://. in local and production this WILL be my subdomain.
Thanx in advance
UPDATED:
I managed to get the desired result by making use of:Request.Headers["host"], it would be interesting to find out why Request.Url does not contain the students substring.
The easy way to do this is to put a fully qualified domain name in hosts. If the production site is subdomain.domain.com, I like to use subdomain.domain.local and just map this to 127.0.0.1.
new System.Uri(Request.RawUrl).Host
I think this will be the real hostname.

How do I find the root site URL in a Share Point 2010 project?

Is there a way to get the root url of the current server the Share Point application is hosted on? For example, if I want to load information from a site I'm currently typing:
SPSite site = new SPSite(http://dev3);
But when I move the development code onto the production server I have to manually replace the site URLs with the new server URLs:
SPSite site = new SPSite(http://sp2010);
I'm using C# in Visual Studio 2010.
I am not sure if I understood your context correctly, but you should be able to use SPContext property.
SPContext.Current.Site.Url;
If you want to get the hostname of the current machine, it's this:
System.Net.Dns.GetHostName()
If you're looking for something using the SharePoint Object Model, try this:
new SPSite(SPServer.Local.Address.ToString())
So the problem that you are facing is that the code has to adjust to the different urls in different environments?
There are two ways to handle this
Ensure that the Urls are the same in all the environments by using a host header in IIS This would result in the urls being the same in both the DEV machine and the PROD machine. (On the DEV machine you would also need to set up the BackConnectionHostNames in registry for it to work well, because you would be logging in to the DEV box and working locally from there).
[1] http://www.it-notebook.org/iis/article/understanding_host_headers.htm
[2] http://support.microsoft.com/kb/896861
But a more standard (and realistic) way of solving this would be to keep the root site name in a config file and let the code pick it up from there. For different environments, you just need to go and update the config file. You can also automate this by seting up your installer to replace the strings based on the environment to which it is getting installed to. The advantage that you get is that you are not hard-coding the Url, and the logic is not dependent on the hostname of the server (There would definitely be scenarios where a host header is used, or an alternate access mapping resulting in the url being different from the host name of your sever). So this way you get better de-coupling.
Just my two cents.
For me, these hints didn't work out. I have several site collections and instead of using DNS information I found it safer to get the url of the topmost site collection of the web application like this:
[current SPWeb].Site.WebApplication.AlternateUrls[0].IncomingUrl
or (longer and resulting in an URL with trailing slash):
[current SPWeb].Site.WebApplication.AlternateUrls[0].Uri.AbsoluteUri
If you want to get all of the web applications on a machine you can get this collection:
Microsoft.SharePoint.Administration.SPWebService.ContentService.WebApplications
For good measure, here is how you get the administrative web application(s):
Microsoft.SharePoint.Administration.SPWebService.AdministrationService.WebApplications
By using these approaches you can go a long way towards hard coding site collection urls into your code base.
Careful!
Although the first item in the WebApplication.Sites collection is usually the root site collection, it is not guaranteed to be item zero [0] if you happen to delete and recreate the root site collection after other site collections have been created. A more reliable way is to reference the site collection using the root URL like this.
WebApplication.Sites["/"]
Also, SharePoint timer jobs execute within the context of the web application. So, for a timer job:
using (SPSite site = this.WebApplication.Sites["/"])
{
}
This will take you to the home page in whatever site or subsite you are in. Rather than the root site home page.
SPContext.Current.Web.Url;

Categories