1

ASP.NET MVC 2 アプリケーションでは、次のようなルートがあります。

            routes.MapRoute(
            "Default",                                       // Route name
            "{lang}/{controller}/{action}/{id}",             // URL with parameters
            new                                              // Parameter defaults 
            {                                             
                controller = "Home",
                action = "Index",
                lang = "de",
                id = UrlParameter.Optional
            },
            new 
            { 
                lang = new AllowedValuesRouteConstraint(new string[] { "de", "en", "fr", "it" },
                                                        StringComparison.InvariantCultureIgnoreCase) 
            }

ここで、基本的には、渡された言語に従ってスレッドのカルチャを設定したいと思います。ただし、例外が 1 つあります。「 http://www.mysite.com」を呼び出すように、ユーザーが初めてページを要求した場合は、次のようにします。可能であれば、最初の言語を「ブラウザが優先する」言語に設定します。

初期の処理段階 (global.asax など) で、既定値が原因で既定のパラメーターが設定されているか、URL を介して明示的に言及されているかをどのように区別できますか? (リクエスト URL が解析されないソリューションを希望します)。

パラメータのデフォルト値を動的に提供する方法はありますか? フックみたいなもの?または、どこでデフォルト値をオーバーライドできますか (良いアプリケーション イベントですか?)。

これは私が実際に実験しているコードです:

        protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        string activeLanguage;
        string[] validLanguages;
        string defaultLanguage;
        string browsersPreferredLanguage;

        try
        {
            HttpContextBase contextBase = new HttpContextWrapper(Context);
            RouteData activeRoute = RouteTable.Routes.GetRouteData(new HttpContextWrapper(Context));                

            if (activeRoute == null)
            {
                return;
            }

            activeLanguage = activeRoute.GetRequiredString("lang");
            Route route = (Route)activeRoute.Route;
            validLanguages = ((AllowedValuesRouteConstraint)route.Constraints["lang"]).AllowedValues;
            defaultLanguage = route.Defaults["lang"].ToString();
            browsersPreferredLanguage = GetBrowsersPreferredLanguage();

            //TODO: Better way than parsing the url
            bool defaultInitialized = contextBase.Request.Url.ToString().IndexOf(string.Format("/{0}/", defaultLanguage), StringComparison.InvariantCultureIgnoreCase) > -1;
            string languageToActivate = defaultLanguage;
            if (!defaultInitialized)
            {
                if (validLanguages.Contains(browsersPreferredLanguage, StringComparer.InvariantCultureIgnoreCase))
                {
                    languageToActivate = browsersPreferredLanguage;
                }
            }

            //TODO: Where and how to overwrtie the default value that it gets passed to the controller? 
            contextBase.RewritePath(contextBase.Request.Path.Replace("/de/", "/en/"));

            SetLanguage(languageToActivate);
        }
        catch (Exception ex)
        {
            //TODO: Log
            Console.WriteLine(ex.Message);
        }

    }
    protected string GetBrowsersPreferredLanguage()
    {
        string acceptedLang = string.Empty;

        if (HttpContext.Current.Request.UserLanguages != null && HttpContext.Current.Request.UserLanguages.Length > 0)
        {
            acceptedLang = HttpContext.Current.Request.UserLanguages[0].Substring(0, 2);
        }

        return acceptedLang;
    }

    protected void SetLanguage(string languageToActivate)
    {
        CultureInfo cultureInfo = new CultureInfo(languageToActivate);

        if (!Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.Equals(languageToActivate, StringComparison.InvariantCultureIgnoreCase))
        {
            Thread.CurrentThread.CurrentUICulture = cultureInfo;
        }

        if (!Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Equals(languageToActivate, StringComparison.InvariantCultureIgnoreCase))
        {
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
        }
    }

サンプルを再現する RouteConstraint:

    public class AllowedValuesRouteConstraint : IRouteConstraint
{

    private string[] _allowedValues;
    private StringComparison _stringComparism;

    public string[] AllowedValues
    {
        get { return _allowedValues;  }
    }

    public AllowedValuesRouteConstraint(string[] allowedValues, StringComparison stringComparism)
    {
        _allowedValues = allowedValues;
        _stringComparism = stringComparism;
    }

    public AllowedValuesRouteConstraint(string[] allowedValues)
    {
        _allowedValues = allowedValues;
        _stringComparism = StringComparison.InvariantCultureIgnoreCase;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (_allowedValues != null)
        {
            return _allowedValues.Any(a => a.Equals(values[parameterName].ToString(), _stringComparism));
        }
        else
        {
            return false;
        }
    }
}

誰かがその問題で私を助けることができますか?

ありがとう、マーティン

4

3 に答える 3

0

アクションフィルターを使ってみませんか?

これは次のようなものである可能性があります。

public class LocalizationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.RouteData.Values["lang"] != null)
        {
            var lang = filterContext.RouteData.Values["lang"].ToString();
            //TODO: Validate the obtained value.
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(lang);
        }
        else
        {
            var langHeader = filterContext.HttpContext.Request.UserLanguages[0];
            //TODO: Validate the obtained value.
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(langHeader);
        }
    }
}

これは単なるアイデアです。もちろん、それを改善する必要があります。次に、この属性をコントローラーに追加するか、ベースコントローラーを作成して属性を設定します(すべてのコントローラーをこのベースコントローラーのサブクラスにします)。

よろしく。

于 2010-03-09T02:14:01.817 に答える
0

これを試して:

        RouteData data=RouteTable.Routes.GetRouteData(httpContext);
        if (data != null)
        {
            Route route = data.Route as Route;
            if (route != null && route.Defaults != null)
                route.Defaults["lang"] = lang.Name;
        }
于 2010-06-22T13:58:36.023 に答える
0

一貫性がなくなるのを防ぐために、ルートでブラウザの言語にリダイレクトし、ユーザーが必要に応じて言語を変更できるようにすることを好みます。

この行を default.aspx に入れるだけで準備完了です。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Select Case Mid(Request.UserLanguages(0).ToString(), 1, 2).ToLower
        Case "en"
            Response.Redirect("/en/")
        Case "pt"
            Response.Redirect("/pt/")
        Case Else
            Response.Redirect("/es/")
    End Select

End Sub
于 2010-03-09T00:01:43.423 に答える