声明: 本文算是半原创,idea是公司另一个同事想出来的,但他的方案比较高阶,我细化了,也把遇到的问题都解决了, 基于VS.NET2008和Reporting Services2008
目的: 实现reporting services 2008的报表(多语言)使用Resource file中的多语言信息
方案: 用web service读取resource file, 再用一个DLL的类来调用这个web service, 把DLL复制到reporting service和vs.net2008的相应安装目录, 在报表中引用这个DLL,并用vbscript调用DLL里封装的获取多语言的方法
步骤:
1. 建立一个WebApplication1, 在里边加资源文件和一个web service
2. 在web service类中加入方法, 此方法就是从resx中按id和lang code读取, 在初次load resx这个xml文件时,就放到缓存中
[WebMethod]
public string GetLabel(string msgID, string langCode)
{
string returnVal = "";
//string localResrouceFile = "../App_LocalResources/Default.aspx.resx";
string localResrouceFile = System.Web.Hosting.HostingEnvironment.MapPath(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath + @"/App_LocalResources/" + "Default.aspx.resx");
XElement doc = (XElement)HttpRuntime.Cache.Get("ResourceCacheKey");
if (doc == null)
{
doc = XElement.Load(localResrouceFile);
//System.Web.Caching.Cache c = new System.Web.Caching.Cache();
HttpRuntime.Cache.Add("ResourceCacheKey", doc, null,
DateTime.Now.AddDays(1), System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Default, null);
}
var resource = from pn in doc.Descendants("data")
where (string)pn.Attribute("name") == msgID
select pn; //.Descendants("value");
if (resource.Count() < 1)
{
//doc = XElement.Load(globalResrouceFile);
//resource = from pn in doc.Descendants("data")
// where (string)pn.Attribute("name") == msgID
// select pn; //.Descendants("value");
returnVal = "没有找到id是:" + msgID + "的资源";
}
else
{
returnVal = resource.First().Value;
}
return returnVal;
}
3. 建立类库并命名为GetResourceLib, 并”Add Web Reference”, 加入步骤1中所建的web service
在类Class1中加入方法
public static string GetMessage(string msgID, string langCode)
{
using (WebReference.WebService1 w = new GetResourceLib.WebReference.WebService1())
{
string path = "";
try
{
//string serviceUrl = ConfigurationManager.AppSettings["WebServiceKey "].ToString()
//Assembly myAssembly = Assembly.GetExecutingAssembly();
path = AppDomain.CurrentDomain.RelativeSearchPath;
//D:/Program Files/Microsoft SQL Server/MSRS10.MSSQLSERVER/Reporting Services/ReportServer/bin/GetResourceLib.dll.config
//path = @"D:/Program Files/Microsoft SQL Server/MSRS10.MSSQLSERVER/Reporting Services/ReportServer/bin";
path += @"/GetResourceLib.dll.config";
string[] pathList = path.Split(new char[]{';'});
if (pathList.Length > 1)
{
path = pathList[1];
}
XElement doc = XElement.Load(path);
var filePaths = from setting in doc.Descendants("setting")
where (string)setting.Attribute("name") == "GetResourceLib_WebReference_WebService1"
select setting; //.Descendants("value");
//string serviceUrl = filePaths.First().Value;
string serviceUrl = filePaths.First().Element(XName.Get("value")).Value;
string userName = filePaths.First().Element(XName.Get("UserName")).Value;
string password = filePaths.First().Element(XName.Get("Password")).Value;
string domain = filePaths.First().Element(XName.Get("Domain")).Value;
//System.Windows.Forms.Application.CommonAppDataPath
w.Url = serviceUrl;
//在reporting service里调用这个web service的方法,会出现"无法连接到远程服务器"的问题, 是防火墙的问题,开放Web Server(HTTP)就可以了
//下边两用,一种是指定web application的impersonate用户,一种是用default的credentials 都可以
//20100527: 在把web service部署到别的电脑后,发现用default的credentials是不可以的,所以只能用指定用户名,密码和域的做法(也从config取)
//System.Net.NetworkCredential n = new System.Net.NetworkCredential("apjuser", "apj", "APJ");
System.Net.NetworkCredential n = new System.Net.NetworkCredential(userName, password, domain);
w.Credentials = n;
//w.Credentials = System.Net.CredentialCache.DefaultCredentials; //
}
catch(Exception ex)
{
return ex.Message + "--1---" + path;
}
return w.GetLabel(msgID, langCode);
}
}
同时修改app.config文件, 在<setting 节点下加多UserName, Password, Domain 三个值,用于动态配置credentials时用
<setting name="GetResourceLib_WebReference_WebService1" serializeAs="String">
<value>http://10.199.130.7/GetResourceLibWebApp/WebService1.asmx</value>
<UserName>apjuser</UserName>
<Password>apj</Password>
<Domain>APJ</Domain>
</setting>
把这个类库编译后,把DLL和生成的config文件GetResourceLib.dll.config复制到reporting service的安装目录D:/Program Files/Microsoft SQL Server/MSRS10.MSSQLSERVER/Reporting Services/ReportServer/bin下, 也同时把它复制到vs.net 2008的安装目录D:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE/PrivateAssemblies下.
同时,为了能在vs.net2008的报表设计画面中也能成功的preview一个报表, 还需要在D:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE/PrivateAssemblies下修改文件RSPreviewPolicy.config, 和上边文件rssrvpolicy.config同样改法, 但Url值就要改成本目录路径下的值了.
5. 建立报表项目” 报表项目1”, 在下边新建一个报表Report1.rdl, 拖一个textbox到报表体中
点击vs.net的菜单”报表”à”报表属性”
在”References”中加入刚才复制到D:/Program Files/Microsoft SQL Server/MSRS10.MSSQLSERVER/Reporting Services/ReportServer/bin下的GetResourceLib.dll的引用, 并在Class Name中输入GetResourceLib.Class1和在Instance Name中输入c
在”Code”中输入vbscript:
Public Function GetLabel(labelID as String, langCode as String) as String
Try
Return c.GetMessage(LabelID,langCode)
Catch ex as Exception
Return ex.Message
End Try
End Function
6. 以上五步完成后,部署到报表服务器可以成功实现目的
7. 以上所有的操作都在同一台电脑上进行, 为了模似真实环境, webapplication(web service)和报表都放到不同的电脑上.
a) 报表放到其它电脑上, 由于报表和web service不在同一电脑,会出现一些问题
"无法连接到远程服务器"
上图的问题是由于web service所在的电脑的防火墙没有开放Web Server(HTTP)导致
b) 由于步骤3中有一句代码path = AppDomain.CurrentDomain.RelativeSearchPath; , 在vs.net2008的报表设计界面中preview时,有时会提示找不到D:/ GetResourceLib.dll.config或E:/ GetResourceLib.dll.config等等, 只要把这个config文件复制到相应盘符下就可以解决
---------------------------------------------------------------------------------------------------------------------------end------------
“OK”后, 在报表的textbox的expression中输入
=Code.GetLabel("Label2.Text", "1")
4. 回到目录D:/Program Files/Microsoft SQL Server/MSRS10.MSSQLSERVER/Reporting Services/ReportServer, 打开文件rssrvpolicy.config, 在该文件中查找文本Name="Report_Expressions_Default_Permissions"将其上面一行内容修改为PermissionSetName="FullTrust", 其次还需在该文件(rssrvpolicy.config)的倒数第2个</CodeGroup>前增加一段引用自定义程序集的内容:
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="FullTrust" Description="This special code group grants RSCustomLib.dll FUllTrust permission. ">
<IMembershipCondition class="UrlMembershipCondition" version="1" Url="D:/Program Files/Microsoft SQL Server/MSRS10.MSSQLSERVER/Reporting Services/ReportServer/bin/GetResourceLib.dll" />
</CodeGroup>