Как отдать Json из файла?

я хочу научиться обрабатывать данные, которые мне будет выдавать еще не написанный сервис.

То есть, у меня есть схема json-ответов.

Пускай это для определенности будет класс Person:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string Phone { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

я могу "руками" написать json-файл.

Теперь мне надо сделать сервис, который берет этот json, сохраненный в виде файла, и отдаёт его точно так же, как это сделал бы настоящий сервис.

И тут я столкнулся вот с какой проблемой:

Шаг 1. Создаю класс Person, возвращаю экземпляр. Всё прекрасно!

Простым созданием webapi-проекта и написанием контроллера

using Microsoft.AspNetCore.Mvc;

namespace MyJsonApp.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class UTypeController : ControllerBase
    {
        private readonly ILogger<UTypeController> _logger;

        public UTypeController(ILogger<UTypeController> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// Возвращает мой тип как json
        /// </summary>
        [HttpGet(Name = "GetPerson")]
        public ActionResult<Person> Get()
        {
            Person person = new Person()
            {
                Name = "Elena Samoylova",
                Description = "ready for companyonship",
                Age = 39,
                Gender = "Female",
                Id = 112,
                Phone = "+7 999 8559911"
            };
            return person;
        }

    }
}

я получаю вот что: по URL

http://localhost:5000/UType

мне возвращается ответ, и это настоящий json: я его вижу на экране, могу нажать на галочку Pretty-print и т.п.:

instant json

Шаг 2.

я беру json, полученный на предыдущем шаге. Сохраняю его в файл src/source.json.

Переписываю контроллер как

namespace MyJsonApp.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class JFileController : ControllerBase
    {
        private readonly ILogger<JFileController> _logger;

        public JFileController(ILogger<JFileController> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// Возвращает содержимое статического JSON файла
        /// </summary>
        [HttpGet(Name = "GetData")]
        public IActionResult Get()
        {
            try
            {
                // Путь к файлу относительно текущего каталога
                var filePath = Path.Combine(Directory.GetCurrentDirectory(), "src/source.json");

                if (!System.IO.File.Exists(filePath))
                    return NotFound("Файл 'source.json' не найден.");

                string jsonContent = System.IO.File.ReadAllText(filePath);
                jsonContent = jsonContent.Replace("\r\n", "");

                // Установка правильного типа содержимого
                Response.ContentType = "application/json";

                return Ok(jsonContent); // Ответ с успешным статусом 200 OK
            }
            catch (IOException ex)
            {
                _logger.LogError(ex.Message, ex.StackTrace);
                return StatusCode(StatusCodes.Status500InternalServerError, $"Ошибка при чтении файла: {ex.Message}");
            }
        }
    }
}

Тогда по URL

http://localhost:5000/JFile

я получаю... как будто бы json, но "разбавленный" обратными косыми чертами, и видно, что это "ненастоящий" json:

not instant json

Причем, в исходном json'е этих обратных косых черт - нет!

Ну и, например, "Pretty-print" больше не работает.

я попробовал всякие модификации, например, читать файл как бинарный, но это не помогло.

Исходник:

https://github.com/junecat/SoQuestions/tree/main/MyJsonApp

Вопрос: так как можно переписать код так, чтобы вывод файла не отличался от вывода "истинного json'а"?


Ответы (2 шт):

Автор решения: CrazyElf

Вообще вроде бы можно вот так:

var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
return response;
→ Ссылка
Автор решения: vitidev

Ok(data) он же OkObjectResult(data) - то есть сериализует data в жсон. В вашем случае data строка с кавычками, которая и сериализуется. На выходе получается строка в кавычках и экранированные кавычки внутри.

Поэтому нужно использовать return Content(jsonContent, "application/json");

var filePath = Path.Combine(Directory.GetCurrentDirectory(), "src/source.json");
if (!System.IO.File.Exists(filePath))
    return NotFound("Файл 'source.json' не найден.");
string jsonContent = System.IO.File.ReadAllText(filePath);
return Content(jsonContent, "application/json");

Также можно напрямую выдать файл без чтения в память.

var filePath = Path.Combine(Directory.GetCurrentDirectory(), "src/source.json");
if (!System.IO.File.Exists(filePath))
    return NotFound("Файл 'source.json' не найден.");

var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
return new FileStreamResult(stream, "application/json");

ну и, конечно же, можно просто напрямую писать в выходной поток (хотя при наличии FileStreamResult в этом нет смысла)

Response.ContentType = "application/json";
await using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
await fileStream.CopyToAsync(Response.Body);
return new EmptyResult();
→ Ссылка