从MVC下载文件

时间:2015-03-16 22:41:36

标签: javascript c# jquery .net angularjs

当用户点击angular / script中的图标并将其发送到.NET中的MVC控制器时,我需要一种方法来传递字符串列表。此列表执行它应该在我的浏览器中下载文件所需的内容。我了解到我不能通过AJAX这样做和/或它变得相当混乱。

编辑:字符串列表是指我正在检索的文件ID列表,然后压缩到一个要下载的文件中。我不想永久存储这个压缩文件。

我愿意接受想法!

        $http.post('document/downloadfiles', data).success(function ()         {/*success callback*/ });

    [HttpPost]
    public ActionResult DownloadFiles(List<string> fileUniqueIdentifiers)
    {
           var file =    _service.ArchiveAndDownloadDocuments(fileUniqueIdentifiers);

        file.Position = 0;

        return new FileStreamResult(file, "application/force-download");


    }

3 个答案:

答案 0 :(得分:1)

我通常不会花费这么长的时间来帮忙,但是我在家里生病了,并且想要编写一些代码,所以这里是我认为你所做的事情的实现&#39;要求。在这里,我使用令牌交换来跟踪在单例实例中存储数据的特定用户的文件交换,如果您愿意,可以使用其他方法(例如数据库令牌存储)...

查看部分(我将我的数据添加到index.cshtml):

<script type="text/javascript">
    function sendStringandGetFiles() {

        var strings = ['One String', 'Two String', 'Three String'];

        $.ajax({
            type: "POST",
            url: "/Home/GetFile",
            contentType: 'application/json',
            data: JSON.stringify(strings),
            success: function (result) {
                //alert("Yes This worked! - " + result);
                window.location = "/Home/GetFile?token=" + result;
            }
        });
    }
</script>

<h5>Just something to click</h5>
<button onclick="sendStringandGetFiles()">Send String and Get Files</button>

然后,控制器部分(我使用HomeController.cs):

[AcceptVerbs(HttpVerbs.Post)]
public string GetFile(string[] strings)
{
    for (int i = 0; i < strings.Length; i++)
    {
        // Do some stuff with string array here.
    }
    Guid token = Guid.NewGuid();
    InMemoryInstances instance = InMemoryInstances.Instance;
    instance.addToken(token.ToString());

    return token.ToString();
}

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetFile(string token)
{
    string filename = @"c:\temp\afile.txt";

    InMemoryInstances instance = InMemoryInstances.Instance;

    if (instance.checkToken(token))
    {
        instance.removeToken(token);
        FileStreamResult resultStream = new FileStreamResult(new FileStream(filename, FileMode.Open, FileAccess.Read), "txt/plain");

        resultStream.FileDownloadName = Path.GetFileName(filename);

        return resultStream;
    }
    else
    {
        return View("Index");
    }

}

InMemoryInstances类:

public class InMemoryInstances
{
    private static volatile InMemoryInstances instance;
    private static object syncRoot = new Object();

    private List<Guid> activeTokens;

    private InMemoryInstances() 
    {
        activeTokens = new List<Guid>();
    }

    public static InMemoryInstances Instance
    {
        get 
        {
            if (instance == null) 
            {
                lock (syncRoot)                  
                {
                    if (instance == null) 
                        instance = new InMemoryInstances();
                }
            }

            return instance;
        }
    }

    public bool checkToken(string token)
    {
        return activeTokens.Contains(new Guid(token));
    }

    public bool addToken(string token)
    {
        activeTokens.Add(new Guid(token));
        return true;
    }

    public bool removeToken(string token)
    {
        return activeTokens.Remove(new Guid(token));
    }
}

希望这有帮助!

答案 1 :(得分:1)

我还写了另一个使用cookie来执行相同操作的实现(如果你想存储信息客户端而不是使用查询字符串,是的,我有点无聊)...

查看部分(我将我的数据添加到index.cshtml):

<script type="text/javascript">
    function sendStringandGetFiles() {

        var strings = ['One String', 'Two String', 'Three String'];

        $.ajax({
            type: "POST",
            url: "/Home/GetFile",
            contentType: 'application/json',
            data: JSON.stringify(strings),
            success: function (result) {
                //alert("Yes This worked! - " + result);
                window.location = "/Home/GetFile?token=" + result;
            }
        });
    }
</script>

<h5>Just something to click</h5>
<button onclick="sendStringandGetFiles()">Send String and Get Files</button>

然后控制器部分(我使用HomeController.cs)

[AcceptVerbs(HttpVerbs.Post)]
public string GetFile(string[] strings)
{
    for (int i = 0; i < strings.Length; i++)
    {
        // Do some stuff with string array here.
    }
    Guid token = Guid.NewGuid();
    InMemoryInstances instance = InMemoryInstances.Instance;

    instance.addToken(token.ToString());

    HttpCookie cookie = new HttpCookie("CookieToken");

    cookie.Value = token.ToString();

    this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);

    return token.ToString();
}

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetFile()
{
    string filename = @"c:\temp\afile.txt";

    InMemoryInstances instance = InMemoryInstances.Instance;

    if (this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains("CookieToken"))
    {
        HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["CookieToken"];

        if (instance.checkToken(cookie.Value)) 
        {                                
            cookie.Expires = DateTime.Now.AddDays(-1);            
              this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);

            FileStreamResult resultStream = new FileStreamResult(new FileStream(filename, FileMode.Open, FileAccess.Read), "txt/plain");

            resultStream.FileDownloadName = Path.GetFileName(filename);

            return resultStream;
        } else 
        {
            return View("Index");
        }
    }            
    else
    {
        return View("Index");
    }

}

InMemoryInstances类:

public class InMemoryInstances
{
    private static volatile InMemoryInstances instance;
    private static object syncRoot = new Object();

    private List<Guid> activeTokens;

    private InMemoryInstances() 
    {
        activeTokens = new List<Guid>();
    }

    public static InMemoryInstances Instance
    {
        get 
        {
            if (instance == null) 
            {
                lock (syncRoot)                  
                {
                    if (instance == null) 
                        instance = new InMemoryInstances();
                }
            }

            return instance;
        }
    }

    public bool checkToken(string token)
    {
        return activeTokens.Contains(new Guid(token));
    }

    public bool addToken(string token)
    {
        activeTokens.Add(new Guid(token));
        return true;
    }

    public bool removeToken(string token)
    {
        return activeTokens.Remove(new Guid(token));
    }
}

如果你想从浏览器地址栏中隐藏令牌交换,那可能会更好吗?

答案 2 :(得分:1)

好的,我猜第三次幸运吗? (我认为这将是我最后一次实施对不起吉姆 - 你必须为自己完成剩下的工作,我想我现在已经给你足够的免费指针......如果你想要更多,你可以联系我,我会指示你写它!:P)。

此版本使用基于cookie的交换,从javascript接受输入字符串(假设它们是文件名),将这些字符串作为键存储在实例类中,然后将ZipFile组装在内存中(无需写入磁盘),然后将zipfile作为内容结果返回。为了提高效率,您可以针对GUID列表删除实际的令牌检查,只需检查文件列表中的键。很显然,你可能不希望我在javascript中对文件名进行硬编码,但是你可以为自己完成这部分工作。 提示:创建一个带有标识符/文件路径对的数据库表,并在请求发送到服务器后使用标识符查找各个文件路径...

查看部分(我将我的数据添加到index.cshtml):

<script type="text/javascript">
    function sendStringandGetFiles() {

        var files = ['c:\\temp\\afile.txt', 'c:\\temp\\afile2.txt', 'c:\\temp\\afile3.txt'];

        $.ajax({
            type: "POST",
            url: "/Home/GetFile",
            contentType: 'application/json',
            data: JSON.stringify(files),
            success: function (result) {
                //alert("Yes This worked! - " + result);
                window.location = "/Home/GetFile";
            }
        });
    }
</script>

<h5>Just something to click</h5>
<button onclick="sendStringandGetFiles()">Send String and Get Files</button>

然后控制器部分(我使用HomeController.cs)

    [AcceptVerbs(HttpVerbs.Post)]
    public string GetFile(string[] strings)
    {
        Guid token = Guid.NewGuid();

        InMemoryInstances instance = InMemoryInstances.Instance;

        instance.addToken(token.ToString());

        instance.addFiles(token.ToString(), strings);

        HttpCookie cookie = new HttpCookie("CookieToken");

        cookie.Value = token.ToString();

        this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);

        return token.ToString();
    }

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult GetFile()
    {
        InMemoryInstances instance = InMemoryInstances.Instance;

        if (this.ControllerContext.HttpContext.Request.Cookies.AllKeys.Contains("CookieToken"))
        {
            HttpCookie cookie = this.ControllerContext.HttpContext.Request.Cookies["CookieToken"];

            if (instance.checkToken(cookie.Value)) 
            {                                
                cookie.Expires = DateTime.Now.AddDays(-1);

                this.ControllerContext.HttpContext.Response.Cookies.Add(cookie);

                MemoryStream ms = new MemoryStream();

                string[] filenames = instance.getFiles(cookie.Value);

                using (ZipArchive zs = new ZipArchive(ms,ZipArchiveMode.Create, true))
                {
                    for (int i=0;i < filenames.Length; i++)
                        zs.CreateEntryFromFile(filenames[i], Path.GetFileName(filenames[i]));                        
                }

                FileContentResult resultContent = new FileContentResult(ms.ToArray(),"application/zip");

                instance.removeFiles(cookie.Value);

                resultContent.FileDownloadName = "ARandomlyGeneratedFileNameHere.zip";

                return resultContent;
            } else 
            {
                return View("Index");
            }
        }            
        else
        {
            return View("Index");
        }

    }

InMemoryInstances类:

public class InMemoryInstances
{
    private static volatile InMemoryInstances instance;
    private static object syncRoot = new Object();

    private List<Guid> activeTokens;
    private NameValueCollection filesByKeyCollection;

    private InMemoryInstances() 
    {
        activeTokens = new List<Guid>();
        filesByKeyCollection = new NameValueCollection();
    }

    public static InMemoryInstances Instance
    {
        get 
        {
            if (instance == null) 
            {
                lock (syncRoot)                  
                {
                    if (instance == null) 
                        instance = new InMemoryInstances();
                }
            }

            return instance;
        }
    }

    public bool checkToken(string token)
    {
        return activeTokens.Contains(new Guid(token));
    }

    public string[] getFiles(string token)
    {
        return filesByKeyCollection.GetValues(token);
    }

    public bool addFiles(string token, string[] files)
    {
        for (int i = 0; i < files.Length; i++)
            filesByKeyCollection.Add(token, files[i]);

        return true;
    }

    public bool addToken(string token)
    {
        activeTokens.Add(new Guid(token));
        return true;
    }

    public bool removeFiles(string token)
    {
        filesByKeyCollection.Remove(token);
        return true;
    }

    public bool removeToken(string token)
    {
        return activeTokens.Remove(new Guid(token));
    }
}

希望这有帮助!