半年多没有写博了。今天稍微写点。今天写的这些东西还是在今年四到六月的时候在美国工作时获得的一点东西。公司派过去的拿工作签证在那里工作。客户是美国运通。项目是他们的一个叫Serve的电子钱包服务平台。当时主要是设计并实现MVC 3的多语言方案。这些技术方案都有现成的。比如msdn上就有链接。那篇英文博文用了不同的视图来实现多语言。在客户这里他们的需求和那篇博文的情况不一样。客户这里的需求是希望controller和view都有本地化版本,model就在多语言之间共享。他们希望在同一套编译出的程序,只需要改一下web.config,就能切换语言,其界面,和商务逻辑也跟着变了。同时技术上的要求也和那篇博文不一样,还需要利用Unity 2来实现对不同的商务逻辑和controller,view的访问;另外他们这里的系统挺庞大,旧的webform页面也很多,这次只把一部分页面转换成MVC技术,所以我们也得为webform准备解决方案。最开始的时候是先熟悉一下环境,做一些技术预研制。我是工作快20年的人了,很快进入了角色。
开始做了一个webform的多语言,这是成熟技术了。没啥好说的。我们用的都是全局资源。类似这样的代码就会有很多:<title><asp:Literal Text='<% $ Resources: Glossary, DefaultPageTitle %>' runat="server"></asp:Literal></title>,还试着实时换界面。这次在那里学到了一个以前没有了解的技术,就是ExpressionBuilder,这个技术可以让Page请求处理过程中动态地解析所需要的资源。如过不用ExpressionBuilder,就只能继承所有的常用的webform服务器端控件,在新的子类里面加上一个资源名属性,只要这个属性的值被设置上,就可以去相关全局资源里取得相应资源。客户这里本来就是已经把所有webform的服务器端控件全都继承了,写了新类。所以用第二种方法也是可行的。实际也是这么做的。
至于MVC。我们想出来了一个解决方案。即在Global.asax.cs里面应用启动的时候,创建Unity 容器,Unity配置是只需要将那些controller所在的名称空间写在Unity配置文件里面即可。另外需要继承DefaultControllerFactory类。这是默认的controller创建的类。我们需要改写该类。当我们需要将某个controller实例化的时候,Unity容器会自动去这些名称空间找到符合该名字的controller类并返回一个该类的实例。这里有一个问题,就是多个语言的controller是同样的名字的,这会让Unity报错的。所以我们得覆盖掉DefaultControllerFactory类的GetControllerType方法。当判断到当前线程的culture是什么的时候,就知道应该取哪个controller了。只需要取得相应controller的Type, 然后返回就可以了。剩下的事情就都交给Unity来实现就可以了。
尽管实现了根据culture来选择controller, 该controller对应的view还需要进行设置。如果没有进行设置,其默认的view还是英语的。需要设置其对应语言的view的path.如中文的view, 动态地取得viewengine, 将viewengine的viewpath改成中文的viewpath.这样的话,就可以有若干个区分开的view, 每一个对应一种语言,它们可以有不同的布局,不同的字段。
View所绑定的model是一个多个语言组合起来的。它有美国特有的字段,也有中国特有的字段。当用于美国时,中国特有的字段就空着。用于中国时,美国的那些特殊字段就空着。model每个字段的显示label是用自定义的attribute实现的,这些attribute可以从全局资源文件里取出字串。还有做数据验证的正则attribute,美国的数据验证和中国的几不一样,例如邮编,美国可以是5位或者9位,而中国是6位。其对应的正则也是不同的。这个正则attribute里可以根据当前线程的culture来取得正确的正则表达式。从而实现对美国和中国的不同数据验证。
以上都只是一些思想。代码就不贴了。其实我手头也没有。全都在客户那里。这是商业代码。不可能拿出来的。