【问题标题】:What is the best way to create multiple xml files and export it as one zip file创建多个 xml 文件并将其导出为一个 zip 文件的最佳方法是什么
【发布时间】:2020-08-12 18:14:52
【问题描述】:

我的项目在 ASP.NET MVC 中,现在我正在使用 Razor 引擎服务 (RazorEngineService.RunCompile) 创建多个 XML 文件并将其作为单个 Zip 文件并导出。

但问题是,当我们每次传递模型对象来处理模板并将其作为单独的 XML 文件返回并完成整个操作时,完成整个内容需要更多时间(10 个对象大约需要 40 秒)导出。

我目前的方法有什么问题,还是我现在做得正确?如果我在这种方法中犯了任何错误,请指导我。

private FileInfo Export(List<Model> modelList)
  {
        string timeStr = Datetime.Now.ToString();
        string archiveFileName = "Main.zip";
        string archivePath = Path.Combine(_reportFolderPath, archiveFileName);

        using (ZipArchive archive = ZipFile.Open(archivePath, ZipArchiveMode.Create))
    {
        foreach (var list in modelList)
        {
            string fileName = model.name + model.Id;
            string filePath = GetModelExport(list, fileName, timeStr);
            archive.CreateEntryFromFile(filePath, fileName + ".xml");
        }
        archive.Dispose();
    }
    return new FileInfo(archivePath);
}

private string GetModelExport(Model model, string fileName, string timeStr)
{
    var processedTemplate = ProcessTemplate(model, TemplateName, TemplateKey);
    string reportFilelName = fileName + "_" + timeStr + ".xml";
    string filePath = Path.Combine(_reportFolderPath, reportFilelName);

    using (var file = new StreamWriter(filePath))
    {
        file.Write(processedTemplate);
    }
    return filePath;
}

private string ProcessTemplate(Model model, string templateName, string templateKey)
    {
        var templateFilePath = Path.Combine(_reportTemplateFolder, templateName);
        return ReportUtils.ProcessTemplate(templateFilePath, templateKey, model);
    }
public static string ProcessTemplate(string templatePath, string templateKey, object model = null)
{
    var templateService = RazorEngineService.Create();
    var result = templateService.RunCompile(File.ReadAllText(templatePath), templateKey, null, model);

    return result;
}

【问题讨论】:

  • 那是真实代码吗?因为它不仅仅使用string timeStr = Datetime.Now; 编译。有多种方法可以加快速度:并行处理、将模板保存在内存中、重用 RazorEngineService 实例...
  • @CamiloTerevinto 是的,这是真正的代码。基本上在实际情况下,我们有单独的代码将时间转换为字符串。可能只是例如 DateTime.Now.ToString();.
  • 假设每次您在单个操作中从不同的文件中读取,并行化应该是相当简单的。查看Parallel.ForEach,您可能需要ConcurrentBag&lt;string&gt;,具体取决于您的处理方式
  • @CamiloTerevinto,感谢您的评论,我将尝试使用 Parellel.ForEach 并通过重用 RazorEngineService 实例的方式更新您,但是将模板保存在内存中怎么样,我是没有明白这一点。您是说加载模板路径并将其保存在内存中,而不是每次都读取完整路径?
  • @CamiloTerevinto 在构建报告层时加载了报告模板,现在只创建了一次报告模板,并且在生成模板的步骤之间删除了现在它可以正常工作,没有任何问题,谢谢很多。

标签: c# asp.net-mvc razorengine


【解决方案1】:

你的一些代码丢失了,所以我看不到整个画面,这就是我要开始的...... gdluck.


public class HolderTempName 
{
    private TemplateService _templateService;
    private Dictionary<string, string> _templateContainer;
    
    public HolderTempName()
    {
        //this will save creating this everytime
        _templateService = RazorEngineService.Create();
        
        //this will hold the template so it does not have to fetch on each loop,
        //if the same template is used.
        _templateContainer = new Dictionary<string, string>();
    }


    //you will need to tweeek this to get the type out 
    private string GetTemplate(string templateName, templatePath)
    {
        if(!_templateContainer.Conatains(templateName))
        {
            var text = File.ReadAllText(templatePath);
            _templateContainer[templateName]  = text;
        }
        return _templateContainer[templateName];
    }


    private FileInfo Export(List<Model> modelList)
    {
        string timeStr = Datetime.Now;
        string archiveFileName = "Main.zip";
        string archivePath = Path.Combine(_reportFolderPath, archiveFileName);


        using (ZipArchive archive = ZipFile.Open(archivePath, ZipArchiveMode.Create))
        {
            foreach (var item in modelList)
            {
                var templateFilePath = Path.Combine(_reportTemplateFolder, TemplateName); //<--TemplateName seems like a local private
                //these should come from where cant see where...
                var template = GetTemplate( TemplateName, templateFilePath)
                
                string modelResponse  = ProcessModel(item,template,TemplateKey ); //<-- why is not passing in the template
                //step 2; 
                //making this above done in parrell and then add aync, but before all that measure what is taking time
                
                string pathname = MakeFileName(_reportFolderPath, reportFilelName, timeStr);
                SaveToDisk(pathname, modelResponse);
                
                string fileName = model.name + model.Id;
                archive.CreateEntryFromFile(filePath, fileName + ".xml");
            }
            archive.Dispose();
        }
        return new FileInfo(archivePath);
    }

    private string MakeFileName(string path ,string filename, string tStamp)
    {
        string reportFilelName = fileName + "_" + timeStr + ".xml";
        string filePath = Path.Combine(_reportFolderPath, reportFilelName);
        return filePath;
    }

    private void SaveToDisk(string filePath, string content)
    {
        using (var file = new StreamWriter(filePath))
        {
            file.Write(processedTemplate);
        }
    }
    
    public static string ProcessTemplate(object model, string template, templateKey)
    {
        var result = templateService.RunCompile(template, templateKey, null, model);
        return result;
    }
}

【讨论】:

  • 感谢您的回答,我已经修改了一些与您的回答类似的内容,并且有效。
猜你喜欢
  • 2010-11-02
  • 1970-01-01
  • 2021-01-21
  • 2014-03-28
  • 2018-10-09
  • 2013-09-20
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
相关资源
最近更新 更多