Setting up redirect in web.config file - asp.net

I'm trying to redirect some unfriendly URLs with more descriptive ones. These URLs end in .aspx?cid=3916 with the last digits being different for each category name page. I want it to instead redirect to Category/CategoryName/3916. I tried this in the web.config file:
<location path="Category.aspx?cid=3916">
<system.webServer>
<httpRedirect enabled="true" destination="http://www.example.com/Category/CategoryName/3916" httpResponseStatus="Permanent" />
</system.webServer>
</location>
but since it didn't end with just the extension, it didn't work. Is there an easy way to get this to work? I'm using IIS 7.5.

Open web.config in the directory where the old pages reside
Then add code for the old location path and new destination as follows:
<configuration>
<location path="services.htm">
<system.webServer>
<httpRedirect enabled="true" destination="http://example.com/services" httpResponseStatus="Permanent" />
</system.webServer>
</location>
<location path="products.htm">
<system.webServer>
<httpRedirect enabled="true" destination="http://example.com/products" httpResponseStatus="Permanent" />
</system.webServer>
</location>
</configuration>
You may add as many location paths as necessary.

You probably want to look at something like URL Rewrite to rewrite URLs to more user friendly ones rather than using a simple httpRedirect. You could then make a rule like this:
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite to Category">
<match url="^Category/([_0-9a-z-]+)/([_0-9a-z-]+)" />
<action type="Rewrite" url="category.aspx?cid={R:2}" />
</rule>
</rules>
</rewrite>
</system.webServer>

In case that you need to add the http redirect in many sites, you could use it as a c# console program:
class Program
{
static int Main(string[] args)
{
if (args.Length < 3)
{
Console.WriteLine("Please enter an argument: for example insert-redirect ./web.config http://stackoverflow.com");
return 1;
}
if (args.Length == 3)
{
if (args[0].ToLower() == "-insert-redirect")
{
var path = args[1];
var value = args[2];
if (InsertRedirect(path, value))
Console.WriteLine("Redirect added.");
return 0;
}
}
Console.WriteLine("Wrong parameters.");
return 1;
}
static bool InsertRedirect(string path, string value)
{
try
{
XmlDocument doc = new XmlDocument();
doc.Load(path);
// This should find the appSettings node (should be only one):
XmlNode nodeAppSettings = doc.SelectSingleNode("//system.webServer");
var existNode = nodeAppSettings.SelectSingleNode("httpRedirect");
if (existNode != null)
return false;
// Create new <add> node
XmlNode nodeNewKey = doc.CreateElement("httpRedirect");
XmlAttribute attributeEnable = doc.CreateAttribute("enabled");
XmlAttribute attributeDestination = doc.CreateAttribute("destination");
//XmlAttribute attributeResponseStatus = doc.CreateAttribute("httpResponseStatus");
// Assign values to both - the key and the value attributes:
attributeEnable.Value = "true";
attributeDestination.Value = value;
//attributeResponseStatus.Value = "Permanent";
// Add both attributes to the newly created node:
nodeNewKey.Attributes.Append(attributeEnable);
nodeNewKey.Attributes.Append(attributeDestination);
//nodeNewKey.Attributes.Append(attributeResponseStatus);
// Add the node under the
nodeAppSettings.AppendChild(nodeNewKey);
doc.Save(path);
return true;
}
catch (Exception e)
{
Console.WriteLine($"Exception adding redirect: {e.Message}");
return false;
}
}
}

Related

C# read customHeaders value from web.config

I have requirement where I need to read customHeaders value in WCF. Below is sample config file of my application. I need to find programmatically value of "Access-Control-Allow-Origin" key. Please help in achieving the same.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff"/>
<add name="Access-Control-Allow-Origin" value="http://localhost:4200"/>
<add name="Access-Control-Request-Method" value="POST,GET,PUT,DELETE,OPTIONS"/>
<add name="Access-Control-Allow-Headers" value="X-Requested-With,Content-Type"/>
<add name="Access-Control-Allow-Credentials" value="true"/>
</customHeaders>
</httpProtocol>
I tried below but it is not working.
Configuration config = serverManager.GetWebConfiguration("Web.Config");
ConfigurationSection httpProtocolSection = config.GetSection("system.webServer/httpProtocol");
ConfigurationElementCollection customHeadersCollection = httpProtocolSection.GetCollection("customHeaders");
foreach(var element in customHeadersCollection)
{
Response.Write(element.Attributes[0].Name);
}
I found this example from Microsoft to read these values.
https://learn.microsoft.com/en-us/iis/configuration/system.webserver/httpprotocol/customheaders/#sample-code
You need a reference to Microsoft.Web.Administration.dll to access these classes.
using (ServerManager serverManager = new ServerManager())
{
Configuration config = serverManager.GetWebConfiguration("Default Web Site");
ConfigurationSection httpProtocolSection = config.GetSection("system.webServer/httpProtocol");
ConfigurationElementCollection customHeadersCollection = httpProtocolSection.GetCollection("customHeaders");
// what you want is in customerHeadersCollection
}

Nuget Server - Private Repository - Change Package Path location Dynamically by routing Url

We are working in private repository for our own private nuget packages in ASP.NET Project . We are in a position to change the nuget feed for every customer. But nuget packages are located in a location which is specified in Web.Config.
Is there a possibility to change the location dynamically through routing(URL) ? i have refferd this blog http://blog.maartenballiauw.be/post/2011/05/09/Using-dynamic-WCF-service-routes.aspx even though the packages url refers the path given in the webconfig file
public static void MapNugetRoutes(RouteCollection routes)
{
var factory = new DataServiceHostFactory();
var serviceRoute = new ServiceRoute("nuget/packages/getpackages/{platform}", factory, typeof(Packages));
serviceRoute.Defaults = new RouteValueDictionary { { "serviceType", "odata" } };
serviceRoute.Constraints = new RouteValueDictionary { { "serviceType", "odata" } };
routes.Add("nuget", serviceRoute);
}
<appSettings>
<add key="requireApiKey" value="true" />
<add key="apiKey" value="" />
<add key="packagesPath" value="~/NugetPackages/" />
<add key="enableSimpleMembership" value="false" />
<add key="" />
</appSettings>
the "NugetPackages" is my local repositary address , i need to access the repositary privately , like there are several folders inside that above location, i need dynamically access that folders NugetPackages/folder1, NugetPackages/folder2 like this, Is it possible?
thanks in advance..

Block IP Addresses In HttpModule

I have taken over a domain that had was running an old version of Community Server. Needless to say the bots are spamming me trying to find holes.
I'd like to block entire IP blocks before System.Web.HttpRequest.ValidateInputIfRequiredByConfig() is fired. I have a IHttpModule that I have tried but I assume it's getting called after because HealthMonitoring is catching the Exceptions. Here is the module:
public class IpBlockerModule : IHttpModule
{
private static readonly string[] Hacks = new[]
{
"60.169.73.",
"60.169.75.",
"61.160.232.",
"61.160.207.",
"92.85.161."
};
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += (Application_BeginRequest);
}
private void Application_BeginRequest(object source, EventArgs e)
{
var context = ((HttpApplication) source).Context;
var ipAddress = context.Request.UserHostAddress;
if (!IsHackIpAddress(ipAddress))
{
context.Response.StatusCode = 403; // (Forbidden)
}
}
private static bool IsHackIpAddress(string ip)
{
if (ip == null) return true;
return Hacks.Any(x => x.StartsWith(ip));
}
}
And the relevent web.config sections:
<system.web>
<httpModules>
<add name="IpBlockerModule" type="MyNameSpace.IpBlockerModule" />
</httpModules>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" >
<add name="IpBlockerModule" type="MyNameSpace.IpBlockerModule" preCondition="" />
</modules>
</system.webServer>
The reasoning behind this is my inbox is getting spammed from all the
A potentially dangerous Request.Path value was detected from the
client
and
A potentially dangerous Request.Form value was detected from the client
notifications. Is something wrong with my Module, or am I correct in assuming modules don't get fired until after the fact?
As an alternative solution have you considered letting IIS do the work for you? This way the request never makes it to your application. You can do this via the web.config and there's an article detailing the process located here. The following example is copied directly from that article and would be placed inside the <system.webServer> section of your web.config:
<security>
<ipSecurity allowUnlisted="true"> <!-- this line allows everybody, except those listed below -->
<clear/> <!-- removes all upstream restrictions -->
<add ipAddress="83.116.19.53"/> <!-- blocks the specific IP of 83.116.19.53 -->
<add ipAddress="83.116.119.0" subnetMask="255.255.255.0"/> <!--blocks network 83.116.119.0 to 83.116.119.255-->
<add ipAddress="83.116.0.0" subnetMask="255.255.0.0"/> <!--blocks network 83.116.0.0 to 83.116.255.255-->
<add ipAddress="83.0.0.0" subnetMask="255.0.0.0"/> <!--blocks entire /8 network of 83.0.0.0 to 83.255.255.255-->
</ipSecurity>
</security>
You can also add the ability to get and log IP addresses so as to identify and block only the spammy ones.
Here's C# code to get IP addresses
string ipadd;
ipadd = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (ipadd == "" || ipaddress == null)
ipadd = Request.ServerVariables["REMOTE_ADDR"];
I noticed that the link in the answer above is dead, so use this well-detailed article here

conditional url routing with asp.net 4 webforms

I want to server mobile and web version of pages on my site without any redirection so that if visitor browse them with PC they would see web version and vice versa.
I can do some media queries and reduce stuff on the page but that is not ideal.
I know i can do it with asp.net mvc, but, project is already half finished and I don't have time to rewrite it.
I thought about using conditional routing but as routes register on application start it didn't look possible. Is there anyway using conditional roting?
I am open to suggestions too.
This isn't an MVC solution, but I know you can do this with the IIS7 rewrite module.
<rewrite>
<rules>
<rule name="Mobile" stopProcessing="true">
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAny">
<add input="{USER_AGENT}" pattern="iPhone" />
</conditions>
<action type="Rewrite" url="Mobile/{R:1}" />
</rule>
</rules>
</rewrite>
You could certainly also do this with a custom conditional route in MVC.
public class MobileConstraint : IRouteConstraint
{
public MobileConstraint() { }
public bool Match(HttpContextBase httpContext, Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection)
{
// add null checking etc
return httpContext.Request.UserAgent.Contains("iPhone")
}
}
context.MapRoute(
"mobile",
"Mobile/{controller}/{action}/{id}",
new { action = "Index", controller = "Home", id = UrlParameter.Optional },
new { controller = new MobileConstraint() }
);

Using ASP.NET routing to serve static files

Can ASP.Net routing (not MVC) be used to serve static files?
Say I want to route
http://domain.tld/static/picture.jpg
to
http://domain.tld/a/b/c/picture.jpg
and I want to do it dynamically in the sense that the rewritten URL is computed on the fly. I cannot set up a static route once and for all.
Anyway, I can create a route like this:
routes.Add(
"StaticRoute", new Route("static/{file}", new FileRouteHandler())
);
In the FileRouteHandler.ProcessRequest method I can rewrite the path from /static/picture.jpg to /a/b/c/picture.jpg. I then want to create a handler for static files. ASP.NET uses the StaticFileHandler for this purpose. Unfortunately, this class is internal. I have tried to create the handler using reflection and it actually works:
Assembly assembly = Assembly.GetAssembly(typeof(IHttpHandler));
Type staticFileHandlerType = assembly.GetType("System.Web.StaticFileHandler");
ConstructorInfo constructorInfo = staticFileHandlerType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
return (IHttpHandler) constructorInfo.Invoke(null);
But using internal types doesn't seem to be the proper solution. Another option is to implement my own StaticFileHandler, but doing so properly (supporting HTTP stuff like ranges and etags) is non-trivial.
How should I approach routing of static files in ASP.NET?
Why not use IIS to do this? You could create a redirect rule to point any requests from the first route to the second one before it even gets to your application. Because of this, it would be a quicker method for redirecting requests.
Assuming you have IIS7+, you would do something like...
<rule name="Redirect Static Images" stopProcessing="true">
<match url="^static/?(.*)$" />
<action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
</rule>
Or, if you don't need to redirect, as suggested by #ni5ni6:
<rule name="Rewrite Static Images" stopProcessing="true">
<match url="^static/?(.*)$" />
<action type="Rewrite" url="/a/b/c/{R:1}" />
</rule>
Edit 2015-06-17 for #RyanDawkins:
And if you're wondering where the rewrite rule goes, here is a map of its location in the web.config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<!-- rules go below -->
<rule name="Redirect Static Images" stopProcessing="true">
<match url="^static/?(.*)$" />
<action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
After digging through this problem for a few hours, I found that simply adding ignore rules will get your static files served.
In RegisterRoutes(RouteCollection routes), add the following ignore rules:
routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");
I've had a similar problem. I ended up using HttpContext.RewritePath:
public class MyApplication : HttpApplication
{
private readonly Regex r = new Regex("^/static/(.*)$", RegexOptions.IgnoreCase);
public override void Init()
{
BeginRequest += OnBeginRequest;
}
protected void OnBeginRequest(object sender, EventArgs e)
{
var match = r.Match(Request.Url.AbsolutePath);
if (match.Success)
{
var fileName = match.Groups[1].Value;
Context.RewritePath(string.Format("/a/b/c/{0}", fileName));
}
}
}
I came up with an alternative to using the internal StaticFileHandler. In the IRouteHandler I call HttpServerUtility.Transfer:
public class FileRouteHandler : IRouteHandler {
public IHttpHandler GetHttpHandler(RequestContext requestContext) {
String fileName = (String) requestContext.RouteData.Values["file"];
// Contrived example of mapping.
String routedPath = String.Format("/a/b/c/{0}", fileName);
HttpContext.Current.Server.Transfer(routedPath);
return null; // Never reached.
}
}
This is a hack. The IRouteHandler is supposed to return an IHttpHandler and not abort and transfer the current request. However, it does actually achieve what I want.
Using the internal StaticFileHandler is also somewhat a hack since I need reflection to get access to it, but at least there is some documentation on StaticFileHandler on MSDN making it a slightly more "official" class. Unfortunately I don't think it is possible to reflect on internal classes in a partial trust environment.
I will stick to using StaticFileHandler as I don't think it will get removed from ASP.NET in the foreseeable future.
You need to add TransferRequestHandler for handling your static files.Please see following answer
https://stackoverflow.com/a/21724783/22858

Resources