1

IIS 8 の Web サイトで実行されている ASP.NET MVC 5 WEB アプリケーションがあり、DB から読み取ってセッション変数に保存するユーザー設定によって実行時にプログラムで言語を変更する必要があり、この値は実行時に変更される可能性があります。ドロップダウン付き。

問題は、CurrentCulture が変更されているにもかかわらず、言語リソースが変更されないことがあり、さらに悪いことに、アプリケーション レベルでフリーズして、他のすべてのユーザー セッションもその言語にフリーズし、すべてのアプリケーション セッションで同じ言語のみが表示されることです。好みに関係なくスタックするか、実行時に言語を変更しようとしても、正常に動作しているときに CurrentThread.CurrentCulture が強制的に変更されます。

ビューで非表示のテキストを使用して、CurrentThread.CurrentCulture が何であったかを追跡し、期待どおりに変化しているため、問題は別の場所にあるはずです。

これは、CurrentCulture の検査に使用するカミソリ ブロックです。

<div style="display:none; visibility: hidden;">Thread  
@System.Threading.Thread.CurrentThread.CurrentCulture</div>

また、実行時に言語または resx がアプリケーション レベルでフリーズ/スタックしている場合、値は実際には正しく選択されていますが、ビューに表示されている言語と一致せず、たとえば変更を加えるまで正常に動作しません。 web.config またはアプリケーションを再起動すると、しばらくは正常に動作しますが、あまり長くは続きません。

<div style="display:none; visibility: hidden;">Thread en-US</div>

問題は、これがすべてのユーザー セッションのアプリケーション レベルで発生し、アプリケーションが正常に動作しているときに CurrentCulture が実際に期待どおりに変化し、再起動するたびにこれが発生しないことです。現在のすべてのセッション、さらには新しいセッションの言語

カミソリ ビュー、アクション フィルター、およびベース コントローラーにもカルチャ ロジックの変更を配置しようとしましたが、問題は解決しませんでした。以前は、すべてのコントローラーが継承したベース コントローラーと、変更する Global.asax.cs のロジックがありました。そして文化を決定します。

私の現在のアプローチは、ベースコントローラーを削除し、Global.asax.cs Application_AcquireRequestState (私も Application_BeginRequest を使用してみましたが、どういうわけかライフサイクルが早すぎます) とアクションフィルターの両方で使用することでした。

これは Global.asax.cs にあります

    protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        if (Context.Session != null && Context.Session["CultureName"] != null)
        {
             string cultureName = Context.Session["CultureName"].ToString();

             CultureInfo cultureInfo = new System.Globalization.CultureInfo(cultureName);

            Thread.CurrentThread.CurrentCulture = cultureInfo;
            Thread.CurrentThread.CurrentUICulture = cultureInfo;

        }
    }

そして、このような私のアクションフィルター

public class CultureActionAttribute : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        string cultureName = null;

        string tenant = filterContext.RouteData.Values["Tenant"] as string;
        if (!String.IsNullOrWhiteSpace(tenant)) 
        {
            TenantService tenantService = new TenantService(tenant);

            cultureName = CultureHelper.GetImplementedCulture(tenantService.Tenant.LanguageCulture);

            tenantService.Unit.Dispose();

        }
        //Logic to override cultureName value by getting the user preference language

        CultureInfo cultureInfo = new System.Globalization.CultureInfo(cultureName);

        Thread.CurrentThread.CurrentCulture = cultureInfo;
        Thread.CurrentThread.CurrentUICulture = cultureInfo;
    }
}

そして、それを FilterConfig に追加しました

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new CultureActionAttribute());
        //
    }

ユーザーがカルチャを変更したときに ClearCachedData を使用しようとさえしました。

Thread.CurrentThread.CurrentCulture.ClearCachedData();

これはキャッシングまたはプールのリサイクルに関連している可能性があると思いますが、次に何を試すべきかわかりません。

web.config でグローバリゼーション タグを使用していません。

CurrentThread.CurrentCulture のビューでトレースされた値は常に正しいですが、問題はリソースの使用によるフリーズです。

リソースは、それらを別の専用の標準フォルダーに配置し、PublicResXFileCodeGenerator を使用してそれらを公開してコンパイルし、コントローラー、ビューなどにアクセスできるようにするという慣行と一致しています。

リソース フォルダー

ここに画像の説明を入力

誰かが私に別の選択肢を提供してくれませんか?

4

2 に答える 2

1

正しいリソースを確実に取得できる唯一の方法 は、CultureFilter の最後にあるすべてのリソース ルックアップの CurrentThreadUICulture プロパティをリソースを直接オーバーライドすることでした。

Resources.Resource.Culture = cultureInfo;

そして、これはうまくいきました!グローバル リソースとして 1 つのファイルのみを持つことを利用して、すべてが期待どおりに機能するようになりましたが、これは複数のリソース ファイルと名前空間にとって不便であることは理解しています。それにもかかわらず、言語の変更が確実に機能し、ベース コントローラーと Iauthorization actionfilter 属性を使用しようとした後、または Global.asax.cs で Application_AcquireRequestState を使用して 3 つの方法のいずれも使用しようとした後にフリーズしないようにする方法は他にありませんでした。 Thread.CurrentThread.CurrentUICulture は常に 3 つのアプローチで正しく変更されていましたが、フリーズのために UI 言語を常に正しく変更できました。

于 2016-07-12T03:55:17.210 に答える