Add language name in URL by using Routing in Asp.net - asp.net

How we can add language name in URL by using Routing?
my site runs on http://localhost:41213/default.aspx URL successfully but this site in multilingual and my client wants run this site according to language like he wants http://localhost:41213/en/default.aspx instead of http://localhost:41213/default.aspx URL.
So my problem is that how to add en,es,hi,etc in URL and how to read this? default.aspx page is on root directory and it is home page.

Use this code in global.asax
public static void RegisterRoutes(System.Web.Routing.RouteCollection routes)
{
routes.Add(new System.Web.Routing.Route("{language}/{*page}", new CustomRouteHandler()));
}
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(System.Web.Routing.RouteTable.Routes);
}
void Application_BeginRequest(object sender, EventArgs e)
{
string URL = HttpContext.Current.Request.Url.PathAndQuery;
string language = TemplateControlExtension.Language;
if (URL.ToLower() == "/default.aspx")
{
HttpContext.Current.Response.Redirect("/" + language + URL);
}
}
make a router handler class like this...
public class CustomRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string language = TemplateControlExtension.GetString(null, requestContext.RouteData.Values["language"]).ToLower();
string page = TemplateControlExtension.GetString(null, requestContext.RouteData.Values["page"]).ToLower();
if (string.IsNullOrEmpty(page))
{
HttpContext.Current.Response.Redirect("/" + language + "/default.aspx");
}
string VirtualPath = "~/" + page;
if (language != null)
{
if (!VIPCultureInfo.CheckExistCulture(language))
{
HttpContext.Current.Response.Redirect("/" + SiteSettingManager.DefaultCultureLaunguage + "/default.aspx");
}
TemplateControlExtension.Language = language;
}
try
{
if (VirtualPath.Contains(".ashx"))
{
return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(IHttpHandler));
}
return BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page)) as IHttpHandler;
}
catch
{
return null;
}
}
}
By using this i hope your requirement has fulfill.....

Probably the best way to do this is to have an initial page where he chooses the language he wants. Then the site loads a cookie to his browser indicating his language preference. In subsequent visits, your site reads the cookie and automatically takes him to his language preference.

Related

Custom HTTP handler for URL rewriting + session and application variable

Currently my product page URL is like
http://www.localhost:80/products/default.aspx?code=productCode
I want to access product page with
http://www.localhost:80/productCode
I have used HTTP module for this.
public class UrlRewritingModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);
}
void context_AuthorizeRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
if (some condition)
{
context.RewritePath(url);
}
}
void context_PreRequestHandlerExecute(object sender, EventArgs e)
{
//We set back the original url on browser
HttpContext context = ((HttpApplication)sender).Context;
if (context.Items["originalUrl"] != null)
{
context.RewritePath((string)context.Items["originalUrl"]);
}
}
}
I have register it in web.config and it is working fine. But when I deploy it in IIS that session and application variables are not throwing null referent Exceptions.
Can anyone help me?
Edit: Do it require extra code to access session/ Application variable for rewritten URLs
?
Have you tried using HTTPContext.Current?
I was able to solve issue (accessing session and application variables in subsequent pages rewritten by custom handler) by adding runAllManagedModulesForAllRequests="true" attribute in modules in web.config.

Partial caching of custom WebControls

I need to cache the generated content of custom WebControls. Since build up of control collection hierarchy is very expensive, simple caching of database results is not sufficient. Caching the whole page is not feasible, because there are other dynamic parts inside the page.
My Question: Is there a best practice approach for this problem? I found a lot of solutions caching whole pages or static UserControls, but nothing appropriate for me. I ended up with my own solution, but im quite doubtful if this is a feasible approach.
A custom WebControl which should be cached could look like this:
public class ReportControl : WebControl
{
public string ReportViewModel { get; set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Fake expensive control hierarchy build up
System.Threading.Thread.Sleep(10000);
this.Controls.Add(new LiteralControl(ReportViewModel));
}
}
The aspx page which includes the content control(s) could look as follows:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Fake authenticated UserID
int userID = 1;
// Parse ReportID
int reportID = int.Parse(Request.QueryString["ReportID"]);
// Validate if current user is allowed to view report
if (!UserCanAccessReport(userID, reportID))
{
form1.Controls.Add(new LiteralControl("You're not allowed to view this report."));
return;
}
// Get ReportContent from Repository
string reportContent = GetReport(reportID);
// This controls needs to be cached
form1.Controls.Add(new ReportControl() { ReportViewModel = reportContent });
}
private bool UserCanAccessReport(int userID, int reportID)
{
return true;
}
protected string GetReport(int reportID)
{
return "This is Report #" + reportID;
}
}
I ended up writing two wrapper controls, one for capturing generated html and a second one for caching the content - Quite a lot of code for simple caching functionality (see below).
The wrapper control for capturing the output overwrites the function Render and looks like this:
public class CaptureOutputControlWrapper : Control
{
public event EventHandler OutputGenerated = (sender, e) => { };
public string CapturedOutput { get; set; }
public Control ControlToWrap { get; set; }
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Controls.Add(ControlToWrap);
}
protected override void Render(HtmlTextWriter writer)
{
StringWriter stringWriter = new StringWriter();
HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter);
base.RenderChildren(htmlTextWriter);
CapturedOutput = stringWriter.ToString();
OutputGenerated(this, EventArgs.Empty);
writer.Write(CapturedOutput);
}
}
The wrapper control to cache this generated output looks as follows:
public class CachingControlWrapper : WebControl
{
public CreateControlDelegate CreateControl;
public string CachingKey { get; set; }
public delegate Control CreateControlDelegate();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string content = HttpRuntime.Cache.Get(CachingKey) as string;
if (content != null)
{
// Content is cached, display
this.Controls.Add(new LiteralControl(content));
}
else
{
// Content is not cached, create specified content control and store output in cache
CaptureOutputControlWrapper wrapper = new CaptureOutputControlWrapper();
wrapper.ControlToWrap = CreateControl();
wrapper.OutputGenerated += new EventHandler(WrapperOutputGenerated);
this.Controls.Add(wrapper);
}
}
protected void WrapperOutputGenerated(object sender, EventArgs e)
{
CaptureOutputControlWrapper wrapper = (CaptureOutputControlWrapper)sender;
HttpRuntime.Cache.Insert(CachingKey, wrapper.CapturedOutput);
}
}
In my aspx page i replaced
// This controls needs to be cached
form1.Controls.Add(new ReportControl() { ReportViewModel = reportContent });
with
CachingControlWrapper cachingControlWrapper = new CachingControlWrapper();
// CachingKey - Each Report must be cached independently
cachingControlWrapper.CachingKey = "ReportControl_" + reportID;
// Create Control Delegate - Control to cache, generated only if control does not exist in cache
cachingControlWrapper.CreateControl = () => { return new ReportControl() { ReportViewModel = reportContent }; };
form1.Controls.Add(cachingControlWrapper);
Seems like a good idea, maybe you should pay attention to :
the ClientIdMode of the child controls of your custom control to prevent conflicts if these controls are to be displayed in another context
the LiteralMode of your Literal : it should be PassThrough
the expiration mode of your cached item (absoluteExpiration/slidingExpiration)
disable ViewState of your CustomControl
Recently, I tend to have another approach : my wrapper controls only holds some javascript that performs an AJAX GET request on a page containing only my custom control.
Caching is performed client side through http headers and serverside through OutputCache directive (unless HTTPS, content has to be public though)

IIS 6, html file/extension, urlrewriting

I use url rewriting on my site (ASP.NET 4.0 / IIS6), instead of aspx I use html. Everything like described here: IIS 6 executing html as aspx . Problem is that when I have any real .html file (html file exists in the site folder) on the site it doesn't open in web-browser. Is it way to resolve this? Thanks!
You can use a custom httpmodule like this:
public class CheckRealHtmlFile : System.Web.IHttpModule
{
public void Dispose()
{
}
public void Init(System.Web.HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
System.Web.HttpApplication app = sender as System.Web.HttpApplication;
if (app != null)
{
System.Text.RegularExpressions.Regex rHtml = new System.Text.RegularExpressions.Regex(#"\.html$", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
if (rHtml.IsMatch(app.Context.Request.Url.AbsolutePath) && !System.IO.File.Exists(app.Context.Server.MapPath(app.Context.Request.Url.AbsolutePath)))
{
//Execute your html -> aspx logic
}
else
return;
}
else
return;
}
}

How to intercept and pre-process QueryStrings in Asp.Net

We send out registration urls to clients via email. Some of the email clients are turning the url into
url <url>
I think it may be happening when users forward the email onto themselves at which point the email client re-formats the original email (maybe)
E.g.
https://my.app.com/login.aspx?param=var
Becomes
https://my.app.com/login.aspx?param=var%20%3Chttps://my.app.com/login.aspx?param=var%3E
Which rightly produces System.Web.HttpRequestValidationException: A potentially dangerous Request.QueryString value was detected
Where in the code should I intercept these instances and santize the url so that the user is re-directed onto the original form of the url?
global.asax?
Page_Init?
HttpHandler?
Pipeline?
You can catch it in Global Application_BeginRequest or in the same event in an HttpModule.
Global
using System;
using System.Web;
namespace MassageIncomingRequestUrl
{
public class Global : HttpApplication
{
protected void Application_BeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication) sender;
string path = app.Context.Request.Url.PathAndQuery;
int pos = path.IndexOf("%20%3C");
if (pos > -1)
{
path = path.Substring(0, pos);
app.Context.RewritePath(path);
}
}
}
}
Module
using System;
using System.Web;
namespace MassageIncomingRequestUrl
{
public class UrlMungeModule : IHttpModule
{
#region IHttpModule Members
public void Init(HttpApplication context)
{
context.BeginRequest += BeginRequest;
}
public void Dispose()
{
//nop
}
#endregion
private static void BeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
string path = app.Context.Request.Url.PathAndQuery;
int pos = path.IndexOf("%20%3C");
if (pos>-1)
{
path = path.Substring(0,pos);
app.Context.RewritePath(path);
}
}
}
}
This will get your request processed with the correct query string in the Request, regardless of what you see in the browser address. You may be able to take extra steps to remove the garbage from the reported url but that is mainly just aesthetics.

ASP.NET SSL - issue is the postback, so OnInit etc won't work

When should I enforce SSL for secure pages in an ASP.NET page life-cycle?
I mean should I do it inside page_load? or OnInit? or some other function?
I am using the following code to enforce SSL for certain pages, but where should I put this code? Earlier I placed it inside OnInit function, but that did not work well with ASP.NET wizards. Do I need to check whether it's postback or not first?
If postback drops https, shouldn't my code enforce it? If postback does not drop https, shouldn't my code stop redirecting and move to the next step of the wizard? It seems like it keeps redirecting.
if (!HttpContext.Current.Request.IsSecureConnection) {
HttpContext.Current.Response.Redirect(SiteNavigation.ResolveAbsoluteUrl(true, HttpContext.Current.Request.Url.PathAndQuery));
}
You have basically two options.
If you want all authenticated pages to run under SSL, you can set the requireSSL="true" attribute on forms authentication. Just make sure your login page is also running on HTTPS.
You can also set this on a page-by-page basis. I found this works well in a "page base" class that inherits from System.Web.UI.Page, and that all your pages inherit from (instead of System.Web.UI.Page).
public class PageBase : System.Web.UI.Page
{
public bool RequiresSSL {get; set;}
string currentPage = Request.Url.ToString();
public PageBase()
{
Init += new EventHandler(PageBase_Init);
}
void PageBase_Init(object sender, EventArgs e)
{
if ((RequiresSSL) && (WebConfigurationManager.AppSettings["SSLavailable"] == "true"))
{
if (currentPage.ToLower().StartsWith("http://"))
{
redirectTo = "https://" + currentPage.Substring(7);
Response.Redirect(redirectTo);
}
}
else
{
if (currentPage.ToLower().StartsWith("https://"))
{
redirectTo = "http://" + currentPage.Substring(8);
Response.Redirect(redirectTo);
}
}
}
}
The AppSettings value of SSLavailable allows you to switch the whole mechanism off when you're running in test mode without SSL.
For pages that need to run in SSL mode, all they need to do is set RequiresSSL:
public partial class ChangePassword : PageBase
{
public ChangePassword()
{
PreInit += new EventHandler(ChangePassword_PreInit);
}
void ChangePassword_PreInit(object sender, EventArgs e)
{
RequiresSSL = true;
}
}
It works, very smoothly, and any other pages they go to after the secure page will automatically switch back to HTTP protocol.
I usually do this in the OnPreLoad event to force SSL:
protected override void OnPreLoad(EventArgs e)
{
base.OnPreLoad(e);
String qs;
qs = Request.QueryString;
//// Force the page to be opened under SSL
if (!Request.IsSecureConnection)
{
if (qs != "")
{
qs = "?" + qs;
}
Response.Redirect("https://" +
Request.ServerVariables["SERVER_NAME"].ToString() +
Request.ServerVariables["PATH_INFO"].ToString() + qs);
}
}
If you want to force SSL for all pages, it may be a good fit for an HttpModule. I have come up with the following:
using System;
using System.Web;
namespace CustomHttpModules
{
public class EnforceSSLModule : IHttpModule
{
public void Init(HttpApplication httpApp)
{
httpApp.PreRequestHandlerExecute += this.OnPreRequestHandlerExecute;
}
public void Dispose()
{
}
public void OnPreRequestHandlerExecute(object o, EventArgs e)
{
using (HttpApplication httpApp = (HttpApplication)o)
{
if (HttpContext.Current != null)
{
HttpContext ctx = HttpContext.Current;
String qs;
qs = ctx.Request.QueryString;
//// Force the page to be opened under SSL
if (ctx.Request.IsSecureConnection)
{
if (qs != "")
qs = "?" + qs;
ctx.Response.Redirect("https://" +
ctx.Request.ServerVariables["SERVER_NAME"].ToString() +
ctx.Request.ServerVariables["PATH_INFO"].ToString() + qs);
}
}
}
}
}
}
To use the HttpModule in IIS5.1 or IIS6, drop the compiled assembly for the HttpModule in your site's bin folder and add the following to your web.config's HttpModules section:
<add type="CustomHttpModules.EnforceSSLModule, dllname" name="EnforceSSLModule" />
(where dllname is the name of your assembly file without the extension)

Resources