Best way to handle URLs in a multilingual site in ASP.net - asp.net

I need to do a multilingual website, with urls like
www.domain.com/en/home.aspx for english
www.domain.com/es/home.aspx for spanish
In the past, I would set up two virtual directories in IIS, and then detect the URL in global.aspx and change the language according to the URL
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim lang As String
If HttpContext.Current.Request.Path.Contains("/en/") Then
lang = "en"
Else
lang = "es"
End If
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(lang)
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang)
End Sub
The solution is more like a hack. I'm thinking about using Routing for a new website.
Do you know a better or more elegant way to do it?
edit: The question is about the URL handling, not about resources, etc.

I decided to go with the new ASP.net Routing.
Why not urlRewriting? Because I don't want to change the clean URL that routing gives to you.
Here is the code:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs on application startup
RegisterRoutes(RouteTable.Routes)
End Sub
Public Sub RegisterRoutes(ByVal routes As RouteCollection)
Dim reportRoute As Route
Dim DefaultLang As String = "es"
reportRoute = New Route("{lang}/{page}", New LangRouteHandler)
'* if you want, you can contrain the values
'reportRoute.Constraints = New RouteValueDictionary(New With {.lang = "[a-z]{2}"})
reportRoute.Defaults = New RouteValueDictionary(New With {.lang = DefaultLang, .page = "home"})
routes.Add(reportRoute)
End Sub
Then LangRouteHandler.vb class:
Public Class LangRouteHandler
Implements IRouteHandler
Public Function GetHttpHandler(ByVal requestContext As System.Web.Routing.RequestContext) As System.Web.IHttpHandler _
Implements System.Web.Routing.IRouteHandler.GetHttpHandler
'Fill the context with the route data, just in case some page needs it
For Each value In requestContext.RouteData.Values
HttpContext.Current.Items(value.Key) = value.Value
Next
Dim VirtualPath As String
VirtualPath = "~/" + requestContext.RouteData.Values("page") + ".aspx"
Dim redirectPage As IHttpHandler
redirectPage = BuildManager.CreateInstanceFromVirtualPath(VirtualPath, GetType(Page))
Return redirectPage
End Function
End Class
Finally I use the default.aspx in the root to redirect to the default lang used in the browser list.
Maybe this can be done with the route.Defaults, but don't work inside Visual Studio (maybe it works in the server)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim DefaultLang As String = "es"
Dim SupportedLangs As String() = {"en", "es"}
Dim BrowserLang As String = Mid(Request.UserLanguages(0).ToString(), 1, 2).ToLower
If SupportedLangs.Contains(BrowserLang) Then DefaultLang = BrowserLang
Response.Redirect(DefaultLang + "/")
End Sub
Some sources:
* Mike Ormond's blog
* Chris Cavanagh’s Blog
* MSDN

Use urlrewriteing.net for asp.net webforms, or routing with mvc. Rewrite www.site.com/en/something.aspx to url: page.aspx?lang=en.
UrlRewriteing.net can be easily configured via regex in web.config. You can also use routing with webforms now, it's probably similar...
with webforms, let every aspx page inherits from BasePage class, which then inherits from Page class.
In BasePage class override "InitializeCulture()" and set culture info to thread, like you described in question.
It's good to do that in this order: 1. check url for Lang param, 2. check cookie, 3. set default lang
For static content (text, pics url) on pages use LocalResources,or Global if content is repeating across site. You can watch videocast on using global/local res. on www.asp.net
Prepare db for multiple languages. But that's another story.

I personnaly use the resources files.
Very efficient, very simple.

UrlRewriting is the way to go.
There is a good article on MSDN on the best ways to do it.
http://msdn.microsoft.com/en-us/library/ms972974.aspx

Kind of a tangent, but I'd actually avoid doing this with different paths unless the different languages are completely content separate from each other.
For Google rank, or for users sharing URLs (one of the big advantages of ‘clean’ URLs), you want the address to stay as constant as possible.
You can find users’ language preferences from their browser settings:
CultureInfo.CurrentUICulture
Then your URL for English or Spanish:
www.domain.com/products/newproduct
Same address for any language, but the user gets the page in their chosen language.
We use this in Canada to provide systems in English and French at the same time.

To do this with URL Routing, refer to this post:
Friendly URLS with URL Routing

Also, watch out new IIS 7.0 - URL Rewriting. Excellent article here http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/
I liked this part
Which Option Should You Use?
If you are developing a new ASP.NET Web application that uses either ASP.NET MVC or ASP.NET Dynamic Data technologies, use ASP.NET routing. Your application will benefit from native support for clean URLs, including generation of clean URLs for the links in your Web pages. Note that ASP.NET routing does not support standard Web Forms applications yet, although there are plans to support it in the future.
If you already have a legacy ASP.NET Web application and do not want to change it, use the URL-rewrite module. The URL-rewrite module allows you to translate search-engine-friendly URLs into a format that your application currently uses. Also, it allows you to create redirect rules that can be used to redirect search-engine crawlers to clean URLs.
http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/
Thanks,
Maulik.

Related

search folder through directory ASP VB.NET

Is there a way to search folder name(whether its root folder or subfolder and with files inside) through web vb.net? I searched all over the internet and haven't found single help. this is what i've done so far. but this is in windows forms.
I am looking for web forms. thank you
Protected Sub search_Click(sender As Object, e As EventArgs) Handles Search.Click
Dim MainFldr = "d:\shared\"
Dim SKfiles() As System.IO.FileInfo
Dim FldrInfo As New System.IO.DirectoryInfo(MainFldr)
Dim flpth As String
flpth = ""
ListBox2.Items.Clear()
SKfiles = FldrInfo.GetFiles("*" & txtfolder.Text & "*.*", IO.SearchOption.AllDirectories)
For Each MySearchfile In SKfiles
flpth = ""
flpth = MySearchfile.DirectoryName + "\" + MySearchfile.Name
ListBox2.Items.Add(flpth)
Application.DoEvents()
Next
End Sub
Well, it turns out you can do the same in web land.
However, one huge "issue" to remember?
For any web page url, web page link, web page document reference? You will use the web site URL for that file in question.
So, say you have the web site (root) and then a folder called Images.
images\cat.jpg
So, the path name for the WEB SITE MARK up will be:
"~/images/cat.jpg
however, WHEN you run code behind? (your vb.net code). Now, ALL AND EVERY file reference MUST be a full normal standard windows path name!!!
so, if say your vb.net code was to "test" if the above file existed?
Lets say we drop a button and a image control on a web page - we have this:
and lets just make this super simple - we want in vb code to set the above image control to a picture we have in our Content folder.
Well, you have to translate the web based url into a plane jane good old fashioned windows file path name!
So, you would do this:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim strF As String
strF = "~/Content/uncheck1.jpg"
Dim strFInternal = Server.MapPath(strF)
Debug.Print(strFInternal)
If File.Exists(strFInternal) Then
Image1.ImageUrl = strF
End If
End Sub
Note how our INTERNAL code MUST use a good old plane jane windows file path name.
but for things on the web page? They are ALWAYS referenced from the point of view of the web site. After I run the above code I get this:
But that debug.print of the file name? This is the output:
Output:
C:\Users\AlbertKallal\source\repos\WebFriendlyTest\Content\uncheck1.jpg
Note VERY careful the above? It was a plane jane INTERNAL file name. I can't tell you how many times I struggled with above simple concept:
Web page controls and markup: use correct URL path names
Code behind: use full windows path name!!!
So, your posted code? it WILL work near as it stands!!!!
The only issue here is what folder you looking to push out to that list box?
Say in above, I wanted to push out ALL files in that Content Folder.
I mean, I can type in this to display that check box if I wanted to:
So the web page now displays that one simple image on the page - since I typed in the FULL correct url!!!
So, how about we drop a list box on the web form, and when we click our button, we display ALL files in that Content folder. Now I could "guess" the location of the file folder, but for ANY WEB page to use that folder, it HAS to be part of the web site folders (or sub folders). The web site can NOT just out of the blue map to steal or grab ANY file on the computer - those URL's can ONLY point to say root of the site + any sub folder.
So that content folder on this site is this:
So, as you can see, then I can type in a url that is the base site, and then that folder, and then that picture (uncheck1.jpg) that exists in that folder.
So, lets drop in a listbox, and push out all the files from that folder to the listbox on the form:
Our markup will be this:
So, just a button, and a list box.
And the button code for the Content folder? Well, we would use this:
(I removed the search part - but that is standard code - JUST like you ALWAYS used in the past!!!
So:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim MainFldr = "~/Content"
Dim FldrInternal = Server.MapPath(MainFldr)
Dim SKfiles() As System.IO.FileInfo
Dim FldrInfo As New System.IO.DirectoryInfo(FldrInternal)
ListBox1.Items.Clear()
SKfiles = FldrInfo.GetFiles("*.*", IO.SearchOption.AllDirectories)
For Each MyFile In SKfiles
ListBox1.Items.Add(MyFile.Name)
Next
End Sub
I decided to NOT use the full path name - but I could have.
The output:
so just remember, that any web page? It can ONLY use files and things that are PART of the web site. And any url - even for a picture, file etc.? Then it MUST be a valid URL.
However, the code behind? It is NOT limited to JUST the folders and files from the root and sub folders. You can actually use your d: drive, or anything else that box on the network can get/grab/use/fetch. So the code behind is your plane jane windows code.
The web site URL and files from web pages thus can only use folders/files that are part of the web site. However, in some cases, say you had some other big server with folders for pictures and files - but your web site (and valid URL's) need to use that folder? Well, you then setup what is a called a virtual directory. This you quite much need to use IIS as opposed to using IIS express edition. (you can google for express edition + setup virutal folders).
Once that virtual folder is setup? It will look like any other sub folder in teh site - but they are not in the site anymore. (and this is also used for documents or PDF folders often too).
This is simply LOOKS like a sub folder, but it really is a folder that can point to any other folder on your computer network. of course this would only work if the final web server and published site location is running on a box on your server, and say not some hosting plan.
So one should code and NOT think in terms of full valid local server file names, but try to always think in terms of the URL, and the path name, and even path names in sub folders in that web site. But in all cases, the code behind operations are against plane jane valid full path names.
However, if you thought that debug.print of the simply .jpg file name was long or funny? Well, on a published server those file path names can be super crazy paths - but you NEVER care if you reference the folders as per above.
I solve the problem by creating search like below. searching folder name and subfolder.
Dim files As FileInfo() = Nothing
Dim dirInfo As DirectoryInfo = New DirectoryInfo(startFolder)
Dim dir As DirectoryInfo() = Nothing
dir = dirInfo.GetDirectories(folderName, SearchOption.AllDirectories)
For i = 0 To dir.Length - 1
If dir(i).Name = folderName Then
Dim path2 = Directory.GetDirectories(dir(i).FullName)
If path2.Length = 0 Then
files = dir(i).GetFiles()
For Each file In dir(i).GetFiles()
path = CStr(dir(0).FullName)
path = path.Remove(0, 11)
HiddenField1.Value = path & "\" & file.Name
HiddenField2.Value = file.Name
Dim tr As New TableRow
tr.Cells.Add(New TableCell With {.Text = file.Name})
grd.Rows.Add(tr)
Dim tdlnk As New TableCell
Dim lnk As New HtmlAnchor
tdlnk.Controls.Add(lnk)
tr.Cells.Add(tdlnk)
Next
Exit For
Else
Dim aaa As String = path2(0).Substring(path2(0).Length - 10)
startFolder = path2(0).ToString
folderName = aaa
Dim files1 As FileInfo() = Nothing
Dim dirInfo1 As DirectoryInfo = New DirectoryInfo(startFolder)
Dim dir1 As DirectoryInfo() = Nothing
dirInfo1.GetDirectories(folderName, SearchOption.AllDirectories)
files1 = dirInfo1.GetFiles
For Each file In dirInfo1.GetFiles
path = CStr(dirInfo1.FullName)
path = path.Remove(0, 11)
HiddenField1.Value = path & "\" & file.Name
HiddenField2.Value = file.Name
Dim tr As New TableRow
tr.Cells.Add(New TableCell With {.Text = file.Name})
grd.Rows.Add(tr)
Dim tdlnk As New TableCell
Dim lnk As New HtmlAnchor
tdlnk.Controls.Add(lnk)
tr.Cells.Add(tdlnk)
Next
Exit For
End If
End If
Next

Rewrite URLS using global.asax

I'm trying to make some friendlyurls in my vb.net (.net 4) project and I'm trying to do it using something I read about global.asax and Application_Beginrequest but I can't get it to compile.
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim httpContext As System.Web.HttpContext = httpContext.Current
Dim currentURL As String = currentURL.Request.Path.ToLower()
If currentURL.IndexOf("widgets") > 0 Then
objHttpContext.RewritePath("products.aspx?ID=123")
Else
objHttpContext.RewritePath(httpContext)
End If
End Sub
Above is what i'm trying but it's erroring on the objHttpContext. is there another method? Ideally once I get the above method working I'm going to be attempting to use a database call to work out the URLs. So any suggestions in that direction will also be very welcome. I'm trying to get away from having to install anything on IIS as it's a load balenced enviroment that I'd rather not install something on every server.
Thanks
Tom
You should access HttpApplication.Context. Here is how I do it (C#):
string reqPath = Request.Url.AbsolutePath;
if(reqPath=="/")
newPath="/Pages/PL/Main.aspx";
if (newPath != "")
HttpApplication.Context.RewritePath(newPath);
As I can see in documentation you should be able to use exactly the same syntax to access the context in VB.NET.
You could also use II7 url rewrite module if you really wanted.
Why do you want use rewriting, when you can do it really easy using asp.net routing?
Please, look at the following link for more info:
http://msdn.microsoft.com/en-us/library/cc668201.aspx

ASP.NET - Capture screen shot

I am thinking about using a WebBrowser object to create a screen shot of a page a user has visited (by capturing the URL). Part of the class will look something like tHE below. This is an internal application and the reason is to allow the user to see how the dynamic page looked several months ago when they last visited.
Public Function ConvertPage(ByVal PageUrl As String) As Bitmap
Me.PageUrl = PageUrl
Dim thrCurrent As New Thread(New ThreadStart(AddressOf CreateImage))
thrCurrent.SetApartmentState(ApartmentState.STA)
thrCurrent.Start()
thrCurrent.Join()
CreateImage()
Return ConvertedImage
End Function
Private Sub CreateImage()
Dim BrowsePage As New WebBrowser()
BrowsePage.ScrollBarsEnabled = False
BrowsePage.Navigate(PageUrl)
AddHandler BrowsePage.DocumentCompleted, AddressOf _
WebBrowser_DocumentCompleted
While BrowsePage.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
End While
BrowsePage.Dispose()
End Sub
Earlier today I was reading an entry (I think it was on here) and the answerer advised the questioner to avoid this approach. I do not have a link to this post. Is this a poor apprach bin your view i.e. using a WebBrowser object in an ASP.NET page?
I think this is the link you are after.
problem using winforms WebBrowser in asp.net
This code project page seems to have a solution and talks about the advantages of it
http://www.codeproject.com/Articles/50544/Using-the-WebBrowser-Control-in-ASP-NET
His solutions seems to require three threads to use the control;
perhaps a better options would be to take a via Javascript and then post the information back via an ajax call, have a look at this Javascript library that does it
http://html2canvas.hertzen.com/
if you are going with the webbrowser approach att the bottom of this question is c# code for capturing the image
Take a screenshot of a webpage with JavaScript?

Share Session between Page in Page to Page Request

My application is simple, I have 2 pages:
RSSProducer.aspx: A page that generates RSS (XML) feeds
RssConsumer.aspx: A page that retrieves the RSS feeds and displays it to the user in a repeater control. To do this I am using the System.Xml.XmlTextReader to fill a DataSet with tables based on the RSS-XML retrieved from the RSSProducePage. A table within the DataSet is bound to the repeater control.
For example, this is what I have in my RssConsumer.aspx page:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Session("permittedToViewSomeDetail") = True
Dim url = "http://localhost/DevSite/RSSProducer.aspx"
Dim reader As New System.Xml.XmlTextReader(url)
Dim ds As New DataSet()
ds.ReadXml(reader)
myRssRepeater.DataSource = ds.Tables(2)
myRssRepeater.DataBind()
End Sub
My problem is that user-authorization details are stored in Session in the RssConsumer page that need to be accessed in the RSSProducer page (in this example it would be Session("permittedToViewSomeDetail") that I need to access in the RSSProducer page); however, the Session identifier is not common between the two. This means that I cannot access the authorization details in the RSSProducer page.
The reason for why is fairly clear to me:
User's browser makes a request to
the RssConsumer page
Server generates a Session ID (which is stored in a cookie) if
there is no existing Session
Identifer
The RSSConsumer requests the RSSProducer page...which generates a
new Session ID every time because no
session identifier is ever going to
be found.
I tried using cookieless session so that I could pass the SessionID via the URL to the RSSProducer page as an experiment but for some reason the XmlTextReader doesn't work well with this method (but the desired shared session does work).
I've hit a brick wall here.
Does anyone know how to share session between pages when one page makes a request to the other?
Thanks,
-Frinny
I ended up taking a different approach to solving this problem. I moved the code out of the RssProducer.aspx page into the RssConsumer.aspx page. I am now able to apply the correct authorization to the feature and it's actually more efficient this way because I don't need to produce/consume RSS-XML any more.
Thanks to everyone who took the time to help me with this.
-Frinny

ASP.NET create a page dynamically

I am dynamically generating HTML which is stored in a string variable.
I would like to open a new window with a new page created from this HTML.
This seems too simple, but I just cannot find the solution.
I am using ASP.NET 3.5 and VS2008.
Thanks,
Paul.
Best idea would be to create an http handler, register it in your web.config file to handle the various request paths that you need to have dynamic content for, and then detect the content to display based on HttpContext.Current.Request.Path.
This way you don't have to save any files, and you write from your string variable to the output stream
You can try this in your new page:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.ClearHeaders()
HttpContext.Current.Response.ClearContent()
HttpContext.Current.Response.ContentType = "text/html
HttpContext.Current.Response.Write(YourString)
HttpContext.Current.Response.Flush()
HttpContext.Current.Response.End()
End Sub
Create an .ashx page that takes a query string, e.g. pagebuilder.ashx?pageid=12345
The purpose of this page is simply to lookup in a session id based on the pageid query string. e.g.
var page = Session["PAGE_" + QueryString["pageid"]].ToString();
Response.Write(page);
On the page that generates the html in a variable, store the variable in Session at Page_Init
` ["PAGE_12345"] = generatedHtml;
Then on Page_Load, generate a javascript that opens to the url pagebuilder.ashx?pageid=12345.
That's it. You will be able to open your newly generated html in another window.

Resources