另一位开发人员维护着大量水晶报表。我需要在我的 ASP.NET MVC3 页面上提供这些报表,而不需要完整的 Crystal Reports Server 产品。
当前的报告站点是一个经典的 ASP 页面,所有参数都通过了,例如 Prompt0&Prompt1...等
为此,我创建了一个位于我的 MVC 应用程序中的 aspx 页面,并从我的应用程序的目录中提供这些报告,如下所示:
公共部分类报告:System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e)
{
iLogger logger = LoggingFactory.CreateLogger();
ReportDocument rd = new ReportDocument();
string fileName = Request.QueryString["reportfile"];
if(!Regex.IsMatch(fileName,@"^[ 0-9a-zA-Z-_\\]+.rpt$"))
{
//log and throw
}
if(Path.IsPathRooted(fileName))
{
//log and throw
}
string rootPath = Server.MapPath("~/Reports/");
string path = Path.Combine(rootPath, fileName);
if (File.Exists(path))
{
rd.Load(path);
}
//get all keys starting with Prompt
var prompts = Request.QueryString.AllKeys.Where(q => q.StartsWith("Prompt"));
foreach (string promptKey in prompts)
{
//try to convert the rest of the string to an int
//yes, this should probably not just be a replace here...
string withoutPrompt = promptKey.Replace("Prompt", "");
int promptVal;
if (int.TryParse(withoutPrompt, out promptVal))
{
rd.SetParameterValue(promptVal, Request.QueryString[promptKey]);
}
//rd.SetParameterValue(promptKey, Request.QueryString[promptKey]);
}
CrystalReportViewer1.ReportSource = rd;
}
}
这对于工作量来说非常有效(报表设计者只需将报表/查询页面中的链接从例如 mywebserver.foo/Report1.rpt?Prompt....etc.etc 更改为 mywebserver.foo/mymvcreport/ report.aspx?Filename=report1.rpt&Prompt...等
太好了,我们可以快速转移到我们的 MVC 应用程序,而不必让 10 个站点出去购买 Crystal Server。
我明显担心的是,在文件名 arg 中,有人可以在其中放置任何内容,例如:“C:\foo\bar”或“../bla/blah”等。是否有一个最佳实践来转义这些文件名并确保它是我的应用程序的本地路径?
我希望能够采用例如以下参数:/Sales/Quarterly/Quarterly.rpt
我的第一个想法是只使用例如 [0-9a-zA-z-_\]+ 的正则表达式,以确保不能使用冒号或点字符。有关处理此问题的最完整方法的任何建议?
谢谢!
编辑:
更新了我放入的初步检查...