如何将模型作为JSON文件下载?

发布于 2025-02-12 16:24:27 字数 3032 浏览 1 评论 0 原文

我的模型保存在客户端的JavaScript对象中,用户可以在其中通过UI控件编辑其属性。我想为用户提供一个选择,以下载代表他们编辑的模型的JSON文件。 是.NET

使用的

public IActionResult Download([FromForm]SomeModel someModel)
{
    var json = JsonConvert.SerializeObject(someModel);
    var characters = json.ToCharArray();
    var bytes = new byte[characters.Length];
    for (var i = 0; i < characters.Length; i++)
    {
        bytes[i] = (byte)characters[i];
    }

    var stream = new MemoryStream();
    stream.Write(bytes);
    stream.Position = 0;
    return this.File(stream, "APPLICATION/octet-stream", "someFile.json");
}

<button class="btn btn-primary" onclick="download()">Download</button>

6 Ajax Magic):

function download() {
    $.ajax({
        url: 'https://hostname/ControllerName/Download',
        method: 'POST',
        data: { someModel: someModel },
        success: function (data) {
            console.log('downloading', data);
        },
    });
}

发生了什么事,

浏览器控制台显示我的模型已发布到服务器上,序列化为JSON,JSON已返回到浏览器。但是,没有下载文件。

我尝试过的其他方法

我也尝试了这样的链接来调用操作方法:

@Html.ActionLink("Download", "Download", "ControllerName")

但是

,下载了文件,因为 ActionLink 只能提出没有请求正文,用户的模型未传递给服务器,而下载的文件表示 somemodel 的默认实例。

问问

我知道我可以将模型发布到服务器,将其序列化给JSON并将JSON返回给客户端,我知道我可以让浏览器下载模型的JSON-Serialialized版本,但是我该怎么做在同一请求中都可以吗?

编辑:我已经接受的答案所做的是

xinran shen的答案,因为它起作用,但是因为我相信仅从堆栈溢出中复制代码而不了解它的作用或为什么不练习,所以我做了一些挖掘和我的版本 savedata 函数现在看起来像:

function saveData(data, fileName) {
    // Convert the data to a JSON string and store it in a blob, a file-like
    // object which can be downloaded without it existing on the server.
    // See https://developer.mozilla.org/en-US/docs/Web/API/Blob
    var json = JSON.stringify(data);
    var blob = new Blob([json], { type: "octet/stream" });

    // Create a URL from which the blob can be downloaded - see
    // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
    var url = window.URL.createObjectURL(blob);

    // Add a hidden hyperlink to the page, which will download the file when clicked
    var a = document.createElement("a");
    a.style = "display: none";
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);

    // Trigger the click event on the hyperlink to download the file
    a.click();

    // Release the blob's URL.
    // Browsers do this when the page is unloaded, but it's good practice to
    // do so as soon as it's no longer needed.
    window.URL.revokeObjectURL(url);

    // Remove the hidden hyperlink from the page
    a.remove();
}

希望有人能找到这个有用的

My model is held in a JavaScript object on the client side, where the user can edit its properties via the UI controls. I want to offer the user an option to download a JSON file representing the model they're editing. I'm using MVC core with .net 6.

What I've tried

Action method (using Newtonsoft.Json to serialize the model to JSON):

public IActionResult Download([FromForm]SomeModel someModel)
{
    var json = JsonConvert.SerializeObject(someModel);
    var characters = json.ToCharArray();
    var bytes = new byte[characters.Length];
    for (var i = 0; i < characters.Length; i++)
    {
        bytes[i] = (byte)characters[i];
    }

    var stream = new MemoryStream();
    stream.Write(bytes);
    stream.Position = 0;
    return this.File(stream, "APPLICATION/octet-stream", "someFile.json");
}

Code in the view to call this method:

<button class="btn btn-primary" onclick="download()">Download</button>

And the event handler for this button (using jQuery's ajax magic):

function download() {
    $.ajax({
        url: 'https://hostname/ControllerName/Download',
        method: 'POST',
        data: { someModel: someModel },
        success: function (data) {
            console.log('downloading', data);
        },
    });
}

What happened

The browser console shows that my model has been posted to the server, serialized to JSON and the JSON has been returned to the browser. However no file is downloaded.

Something else I tried

I also tried a link like this to call the action method:

@Html.ActionLink("Download", "Download", "ControllerName")

What happened

This time a file was downloaded, however, because ActionLink can only make GET requests, which have no request body, the user's model isn't passed to the server and instead the file which is downloaded represents a default instance of SomeModel.

The ask

So I know I can post my model to the server, serialize it to JSON and return that JSON to the client, and I know I can get the browser to download a JSON-serialized version of a model, but how can I do both in the same request?

Edit: What I've done with the answer

I've accepted Xinran Shen's answer, because it works as-is, but because I believe that just copying code from Stack Overflow without understanding what it does or why isn't good practice, I did a bit of digging and my version of the saveData function now looks like this:

function saveData(data, fileName) {
    // Convert the data to a JSON string and store it in a blob, a file-like
    // object which can be downloaded without it existing on the server.
    // See https://developer.mozilla.org/en-US/docs/Web/API/Blob
    var json = JSON.stringify(data);
    var blob = new Blob([json], { type: "octet/stream" });

    // Create a URL from which the blob can be downloaded - see
    // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
    var url = window.URL.createObjectURL(blob);

    // Add a hidden hyperlink to the page, which will download the file when clicked
    var a = document.createElement("a");
    a.style = "display: none";
    a.href = url;
    a.download = fileName;
    document.body.appendChild(a);

    // Trigger the click event on the hyperlink to download the file
    a.click();

    // Release the blob's URL.
    // Browsers do this when the page is unloaded, but it's good practice to
    // do so as soon as it's no longer needed.
    window.URL.revokeObjectURL(url);

    // Remove the hidden hyperlink from the page
    a.remove();
}

Hope someone finds this useful

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

何以心动 2025-02-19 16:24:27

首先,您的代码是正确的,您可以尝试在没有AJAX的情况下访问此方法,您会发现它可以成功下载文件,但是您无法使用Ajax来实现此目的,因为JavaScript无法与磁盘进行交互,您需要使用Blob来保存文件。这样更改您的JavaScript:

function download() {
            
            $.ajax({
                url: 'https://hostname/ControllerName/Download',
                method: 'Post',
                data: { someModel: someModel },,
                
                success: function (data) {
                            fileName = "my-download.json";
                            saveData(data,fileName)
                        },
                        
            });
        }
        
        var saveData = (function () {
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            return function (data, fileName) {
                var json = JSON.stringify(data),
                    blob = new Blob([json], {type: "octet/stream"}),
                    url = window.URL.createObjectURL(blob);
                a.href = url;
                a.download = fileName;
                a.click();
                window.URL.revokeObjectURL(url);
            };
        }());

First, Your code is right, You can try to access this method without ajax, You will find it can download file successfully,But You can't use ajax to achieve this, because JavaScript cannot interact with disk, you need to use Blob to save the file. change your javascript like this:

function download() {
            
            $.ajax({
                url: 'https://hostname/ControllerName/Download',
                method: 'Post',
                data: { someModel: someModel },,
                
                success: function (data) {
                            fileName = "my-download.json";
                            saveData(data,fileName)
                        },
                        
            });
        }
        
        var saveData = (function () {
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            return function (data, fileName) {
                var json = JSON.stringify(data),
                    blob = new Blob([json], {type: "octet/stream"}),
                    url = window.URL.createObjectURL(blob);
                a.href = url;
                a.download = fileName;
                a.click();
                window.URL.revokeObjectURL(url);
            };
        }());
时常饿 2025-02-19 16:24:27

我认为您可能需要 fileStreamResult ,也需要将MIME类型设置为文本文件或JSON文件。

// instead of this
return this.File(stream, "APPLICATION/octet-stream", "someFile.json");

// try this
return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))  
{  
    FileDownloadName = "someFile.txt"  
};

// or   
return new FileStreamResult(stream, new MediaTypeHeaderValue("application/json"))  
{  
    FileDownloadName = "someFile.json"  
};

参考:

I think you may need FileStreamResult, also you need to set the MIME type to text file or json file.

// instead of this
return this.File(stream, "APPLICATION/octet-stream", "someFile.json");

// try this
return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))  
{  
    FileDownloadName = "someFile.txt"  
};

// or   
return new FileStreamResult(stream, new MediaTypeHeaderValue("application/json"))  
{  
    FileDownloadName = "someFile.json"  
};

Reference: https://www.c-sharpcorner.com/article/fileresult-in-asp-net-core-mvc2/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文