编程开发 > ASP > 文章内容

ASP.NETMVC的全球化方案(二)

2010-11-5编辑:dan

 在Controller的Action执行前跳转

所有的Controller都应该具有一个相同的行为:能够针对没有ci参数的url实施跳转。因此自然想到实现一个基类Controller,这里我命名为BaseController,代码如下:

以下为引用的内容:

public class BaseController : Controller
{
    protected string redirectUrl;

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);
        object cultureValue;
        //检测ci参数
        if (requestContext.RouteData.Values.TryGetValue("ci", out cultureValue))
        {
            //设置当前线程的culture
            try
            {
                Thread.CurrentThread.CurrentUICulture = CultureProvider.GetCultureInfo(cultureValue.ToString());
                Thread.CurrentThread.CurrentCulture = CultureProvider.GetCultureInfo(cultureValue.ToString());

以下为引用的内容:

                Response.Cookies.Add(new HttpCookie(CultureProvider.culturecookiekey,cultureValue.ToString()));
            }
            catch { throw new Exception("Culture Error!"); }
        }
        else //如果没有ci参数
        {
            //check cookie
            HttpCookie cLang = requestContext.HttpContext.Request.Cookies[CultureProvider.culturecookiekey];
            if (cLang != null)
            {
                cultureValue = cLang.Value;
            }
            else //check brower setting
            {
                string[] langs = requestContext.HttpContext.Request.UserLanguages;
                if (langs != null && langs.Length > 0)
                {
                    cultureValue = langs[0].Split(';').First();
                }
            }

            if (cultureValue == null)
            {
                cultureValue = CultureProvider.culturedefault;
            }
            //设置redirectUrl,如果不需要重定向到化redirectUrl 为null
            redirectUrl = string.Format(@"/{0}{1}",
                cultureValue.ToString(),
                requestContext.HttpContext.Request.RawUrl);

        }
    }

    protected override IActionInvoker CreateActionInvoker()
    {
        return new CustomControllerActionInvoker(redirectUrl);
    }
}

//一个IActionInvoker 的实现,MVC默认使用ControllerActionInvoker,因为在
//redirectUrl != null 的时候需要在action执行之前执行重定向
internal class CustomControllerActionInvoker : ControllerActionInvoker
{
    string redirectUrl;
    public CustomControllerActionInvoker(string url)
        : base()
    {
        redirectUrl = url;
    }
    protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
    {
        object returnValue;
       //ChildAction内部不能重定向
        if (!string.IsNullOrEmpty(redirectUrl) && !controllerContext.IsChildAction)
            returnValue = new RedirectResult(redirectUrl);
        else
            returnValue = actionDescriptor.Execute(controllerContext, parameters);
        ActionResult result = CreateActionResult(controllerContext, actionDescriptor, returnValue);
        return result;
    }
}

public static class CultureProvider
{
    public const string culturecookiekey = "Lang";
    public const string culturedefault = "en-US";

    public static CultureInfo GetCultureInfo(string ci)
    {
        try
        {
            return new CultureInfo(ci);
        }
        catch
        {
            return null;
        }
    }
}

只要所有的Controller继承这个BaseController即可。

这里需要重点指出的是CustomControllerActionInvoker类,事实上发现从这个类入手解决重定向问题花了我不少时间,为此我不得不调试MVC的源码。当然最初的想法是在每个action执行时手动判断redirectUrl,从而指导重定向,但显然,没人愿意将自己已经写好的action都拿出来一个个改,所以也就有了这个小小的探索。

页面中的链接、跳转

最后令我感到即高兴又担心的问题是:当我使用这个框架后,页面中的所有链接和跳转因素几乎都能自动在url前面加上ci参数!虽然我知道类似Html.ActionLink之类的helper有从路由表中产生url的能力,但是能够自动添加上ci,还是让我感到有点始料未及。不过,链接的url是否正确,还是要注意,有一些特殊情况。

页面中使用资源

在页面中引用资源可以直接在C#脚本中引用Resource类。这里提供一个helper。这个Html的扩展方法。

 

以下为引用的内容:

public static class ResourceExtensions
{
    public static string Resource(this Controller controller, string expression, params object[] args)
    {
        ResourceExpressionFields fields = GetResourceFields(expression, "~/");
        return GetGlobalResource(fields, args);
    }

    public static string Resource(this HtmlHelper htmlHelper, string expression, params object[] args)
    {
        string path = "~/";
        ResourceExpressionFields fields = GetResourceFields(string.Format("Resource,{0}", expression), path);
        return GetGlobalResource(fields, args);
    }

    static string GetGlobalResource(ResourceExpressionFields fields, object[] args)
    {
        return string.Format((string)HttpContext.GetGlobalResourceObject(fields.ClassKey, fields.ResourceKey, CultureInfo.CurrentUICulture), args);
    }

    static ResourceExpressionFields GetResourceFields(string expression, string virtualPath)
    {
        var context = new ExpressionBuilderContext(virtualPath);
        var builder = new ResourceExpressionBuilder();
        return (ResourceExpressionFields)builder.ParseExpression(expression, typeof(string), context);
    }
}

需要注意的是这个方法默认认为Resource是资源的类名,所以必要的话需要修改

 

以下为引用的内容:

ResourceExpressionFields fields = GetResourceFields(string.Format("Resource,{0}", expression), path); 中的"Resource,{0}"

结语

初学MVC,甚至可以说是初学web开发。以上是我个人提出的一种方案,不知道有没有什么不足之处,还请各位看官提出见解,探讨一下。

ASP.NETMVC的全球化方案(一)

热点推荐

登录注册
触屏版电脑版网站地图