You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core Web API如何导出与导入外部REST API的JSON数据?

ASP.NET Core WebAPI实现JSON数据的导出与导入

需求背景

我正在构建ASP.NET Core WebAPI,用于从外部REST API获取JSON格式的天气数据,现在需要实现这些数据的本地保存(导出)和重新加载(导入)功能。

当前获取外部API数据的代码如下:

public async Task<List<Weather>> Get(string cities)
{
    List<Weather> weathers = new List<Weather>(); 
    var options = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    };

    foreach (var city in cities.Split(";"))
    {
        string APIURL = $"?key={this.apiKey}&q={city}";
        var response = await _httpClient.GetAsync(APIURL);

        if (response.IsSuccessStatusCode)
        {
            var responses = await response.Content.ReadAsStreamAsync();
            var weather = await JsonSerializer.DeserializeAsync<Weather>(responses, options);

            weathers.Add(weather);
        }

    }

    return weathers;
}

返回的JSON格式示例:

[
   {
      "location":{
         "name":"Chennai",
         "region":"Tamil Nadu",
         ...
      },
      "current":{
         "last_updated_epoch":1663601400,
         "last_updated":"2022-09-19 21:00",
         ...
      }
   },
   {
      "location":{
         "name":"Mumbai",
         "region":"Maharashtra",
         ..
      },
      "current":{
         "last_updated_epoch":1663602300,
         "last_updated":"2022-09-19 21:15",
         ..
      }
   }
]

已实现的代码更新

我已经编写了文件操作工具类和导入导出的相关代码,具体如下:

JSON文件操作工具类

public static class JsonFileUtils
{
    private static readonly JsonSerializerSettings _options
        = new() { NullValueHandling = NullValueHandling.Ignore };

    public static void StreamWrite(object obj, string fileName)
    {
        using var streamWriter = File.CreateText(fileName);
        using var jsonWriter = new JsonTextWriter(streamWriter);

        JsonSerializer.CreateDefault(_options).Serialize(jsonWriter, obj);
    }

    public static async Task StreamWriteAsync(object obj, string fileName)
    {
        await Task.Run(() => StreamWrite(obj, fileName));
    }
}

数据导出(保存到本地文件)

在获取数据的接口中添加保存逻辑:

public async Task<List<Weather>> Get(string cities)
{
    List<Weather> weathers = new List<Weather>(); 
    var options = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    };

    foreach (var city in cities.Split(";"))
    {
        string APIURL = $"?key={this.apiKey}&q={city}";
        var response = await _httpClient.GetAsync(APIURL);

        if (response.IsSuccessStatusCode)
        {
            var responses = await response.Content.ReadAsStreamAsync();
            var weather = await JsonSerializer.DeserializeAsync<Weather>(responses, options);

            weathers.Add(weather);
        }

    }

    var fileName = "weathers.json";
    await JsonFileUtils.StreamWriteAsync(weathers, fileName);

    return weathers;
}

数据导入(上传JSON文件并解析)

添加文件上传接口:

[HttpPost("upload", Name = "upload")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<Weather>))]
[ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UploadFile(
        IFormFile file,
        CancellationToken cancellationToken)
{
    string fileContent = null;

    using (var reader = new StreamReader(file.OpenReadStream()))
    {
        fileContent = reader.ReadToEnd();
    }
    var result = JsonConvert.DeserializeObject<List<Weather>>(fileContent);
    return Ok(result);
}

代码优化建议

  • 统一JSON序列化库:当前代码混合使用了System.Text.Json(获取数据时的反序列化)和Newtonsoft.Json(文件操作和上传解析),建议统一使用其中一种,避免配置不一致。比如统一用System.Text.Json重构工具类和上传接口:

    // 重构后的JsonFileUtils
    public static class JsonFileUtils
    {
        private static readonly JsonSerializerOptions _options = new() 
        { 
            NullValueHandling = JsonIgnoreCondition.WhenWritingNull,
            WriteIndented = true,
            PropertyNameCaseInsensitive = true
        };
    
        public static void StreamWrite<T>(T obj, string fileName)
        {
            using var stream = File.Create(fileName);
            JsonSerializer.Serialize(stream, obj, _options);
        }
    
        public static async Task StreamWriteAsync<T>(T obj, string fileName)
        {
            using var stream = File.Create(fileName);
            await JsonSerializer.SerializeAsync(stream, obj, _options);
        }
    
        public static T StreamRead<T>(string fileName)
        {
            using var stream = File.OpenRead(fileName);
            return JsonSerializer.Deserialize<T>(stream, _options);
        }
    
        public static async Task<T> StreamReadAsync<T>(string fileName)
        {
            using var stream = File.OpenRead(fileName);
            return await JsonSerializer.DeserializeAsync<T>(stream, _options);
        }
    }
    
    // 重构后的上传接口
    [HttpPost("upload", Name = "upload")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<Weather>))]
    [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> UploadFile(
            IFormFile file,
            CancellationToken cancellationToken)
    {
        if (file == null || file.Length == 0)
        {
            return BadRequest("上传的文件不能为空");
        }
    
        var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
        if (fileExtension != ".json")
        {
            return BadRequest("仅支持上传JSON格式文件");
        }
    
        try
        {
            using var stream = file.OpenReadStream();
            var result = await JsonSerializer.DeserializeAsync<List<Weather>>(stream, _options);
            return Ok(result);
        }
        catch (JsonException ex)
        {
            return BadRequest($"JSON格式错误:{ex.Message}");
        }
    }
    
  • 规范文件存储路径:直接使用文件名会保存到程序运行目录,建议配置固定存储目录(如wwwroot/weather-data),并确保目录存在:

    private static string GetStoragePath(string fileName)
    {
        var basePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "weather-data");
        Directory.CreateDirectory(basePath);
        return Path.Combine(basePath, fileName);
    }
    
  • 增强错误处理:导出时添加异常捕获,避免保存失败影响接口返回;导入时增加文件校验和格式错误提示,提升接口健壮性。

内容的提问来源于stack exchange,提问作者One Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:50:28