问题
I have inherited from a very small ASP.NET WebForms project, and my customer would like to add a second language to it.
For every "somepage.aspx", I'd like to support a "second language path" version of it, like "fr/somepage.aspx". I'd like to handle this using normal globalization (CurrentCulture + resource files in both languages) and avoid having to duplicate each page. I must keep the original paths valid, thus I have excluded ASP.NET MVC for now (for lack of knowing if I could continue to support ".aspx" paths).
Is this possible?
回答1:
URL Routing is avalaible in for ASP.NET.
You could create two routes, the first being the route that catches your language:
{language}/{page}
The second route would be just
{page}
In MVC we can create route constraints that would enforce the Language to be of a specific value (so like en, en-us, etc) I'm not positive if the same can be done in regular ASP.NET WebForms routing.
Here are two articles that describe the topic of routing in WebForms (non-MVC)
http://msdn.microsoft.com/en-us/magazine/dd347546.aspx
and
http://weblogs.asp.net/scottgu/archive/2009/10/13/url-routing-with-asp-net-4-web-forms-vs-2010-and-net-4-0-series.aspx
EDITED TO ADD CODE SAMPLE
In my Global.asax I registered the following:
void RegisterRoutes(RouteCollection routes)
{
routes.Ignore("{resource}.asxd/{*pathInfo}");
routes.Add(
new Route(
"{locale}/{*url}", //Route Path
null, //Default Route Values
new RouteValueDictionary{{"locale", "[a-z]{2}"}}, //constraint to say the locale must be 2 letters. You could also use something like "en-us|en-gn|ru" to specify a full list of languages
new Utility.Handlers.DefaultRouteHandeler() //Instance of a class to handle the routing
));
}
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
RegisterRoutes(RouteTable.Routes);
}
I also created a seperate Class (see asp.net 4.0 web forms routing - default/wildcard route as a guide.)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Compilation;
using System.Web.Routing;
using System.Web.UI;
namespace SampleWeb.Utility.Handlers
{
public class DefaultRouteHandeler:IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
//Url mapping however you want here:
string routeURL = requestContext.RouteData.Values["url"] as string ;
string pageUrl = "~/" + (!String.IsNullOrEmpty(routeURL)? routeURL:"");
var page = BuildManager.CreateInstanceFromVirtualPath(pageUrl, typeof(Page))
as IHttpHandler;
if (page != null)
{
//Set the <form>'s postback url to the route
var webForm = page as Page;
if (webForm != null)
webForm.Load += delegate
{
webForm.Form.Action =
requestContext.HttpContext.Request.RawUrl;
};
}
return page;
}
}
}
This works because when no locale is specified in the URL the default view engine for Web Forms takes over. It also works when a 2 letter locale (en? us? etc) is used. In MVC we can use an IRouteConstraint and do all kinds of checking, like making sure the locale is in a list, checking to see if the path exists, etc but in WebForms the only option for a constraint is using a RouteValueDictonary.
Now, I know there is an issue with the code as-is, default documents don't load. So http://localhost:25436/en/ does not load the default document of default.aspx, but http://localhost:25436/en/default.aspx does work. I'll leave that to you to resolve.
I tested this with sub directories and it works.
回答2:
You can create an ASP.NET HTTP module that calls HttpContext.RewritePath
to map requests from "fr/somepage.aspx" to "somepage.aspx". This technique works best with IIS 7.0 in Integrated mode because relative URLs to scripts and stylesheets will resolve to actual paths like "/fr/jquery.js", and these should be mapped to "/jquery.js" as well.
namespace SampleApp
{
public class LocalizationModule : IHttpModule
{
private HashSet<string> _supportedCultures =
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "de", "es", "fr" };
private string _appPath = HttpRuntime.AppDomainAppVirtualPath;
public void Dispose()
{
}
public void Init(HttpApplication application)
{
application.BeginRequest += this.BeginRequest;
_appPath = HttpRuntime.AppDomainAppVirtualPath;
if (!_appPath.EndsWith("/"))
_appPath += "/";
}
private void BeginRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
string path = context.Request.Path;
string cultureName = this.GetCultureFromPath(ref path);
if (cultureName != null)
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(cultureName);
context.RewritePath(path);
}
}
private string GetCultureFromPath(ref string path)
{
if (path.StartsWith(_appPath, StringComparison.OrdinalIgnoreCase))
{
int startIndex = _appPath.Length;
int index = path.IndexOf('/', startIndex);
if (index > startIndex)
{
string cultureName = path.Substring(startIndex, index - startIndex);
if (_supportedCultures.Contains(cultureName))
{
path = _appPath + path.Substring(index + 1);
return cultureName;
}
}
}
return null;
}
}
}
Web.config:
<!-- IIS 7.0 Integrated mode -->
<system.webServer>
<modules>
<add name="LocalizationModule" type="SampleApp.LocalizationModule, SampleApp" />
</modules>
</system.webServer>
<!-- Otherwise -->
<system.web>
<httpModules>
<add name="LocalizationModule" type="SampleApp.LocalizationModule, SampleApp" />
</httpModules>
</system.web>
回答3:
You can update Application_BeginRequest in Global.Asax with this codes. If global.asax does not exists, create it.
Visual Studio Project Virtual Path must be /
protected void Application_BeginRequest(object sender, EventArgs e)
{
string file_path = Request.RawUrl.ToLower();
char[] separator = new char[] { '/' };
string[] parts = file_path.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length > 0 && parts[0] == "fr")
{
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("fr-FR");
Context.RewritePath("~/" + file_path.Substring(4), true);
}
else
{
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
}
}
回答4:
One option is to put the texts of the aspx within <%$ Resources: My translated text %>
tags. Resources tags will be resolved using a ResourceProviderFactory to get the translated value. This ResourceProviderFactory you can create yourself, doing the work of getting the translation from a resource file or database for example (Just implement IResourceProvider.GetObject()
). You configure this in the web.config:
<system.web>
<globalization resourceProviderFactoryType="CustomResourceProviderFactory" uiCulture="fr" culture="en-GB"/>
</system.web>
See: http://msdn.microsoft.com/en-us/library/fw69ke6f(v=vs.80).aspx
来源:https://stackoverflow.com/questions/9072088/add-second-language-support-with-root-path-in-an-existing-asp-net-webforms-site