MVC: как вернуть строку в JSON
Чтобы сделать процесс отчетов о проделанной работе немного более надежным и отделить его от запроса/ответа, я выполняю обработку в службе Windows и сохраняю предполагаемый ответ на файл. Когда клиент начинает опрос обновлений, предполагается, что контроллер возвращает содержимое файла, независимо от того, что они есть, как строка JSON.
Содержимое файла предварительно сериализуется в JSON. Это должно гарантировать, что на пути ответа нет ничего. Никакой обработки не должно произойти (не дочитав содержимое файла в строке и возвращая его), чтобы получить ответ.
Я изначально, хотя это было бы довольно просто, но это не так.
В настоящее время мой метод контроллера выглядит следующим образом:
Controller
Обновление
[HttpPost]
public JsonResult UpdateBatchSearchMembers()
{
string path = Properties.Settings.Default.ResponsePath;
string returntext;
if (!System.IO.File.Exists(path))
returntext = Properties.Settings.Default.EmptyBatchSearchUpdate;
else
returntext = System.IO.File.ReadAllText(path);
return this.Json(returntext);
}
И Fiddler возвращает это как сырой ответ
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 19 Mar 2012 20:30:05 GMT
X-AspNet-Version: 4.0.30319
X-AspNetMvc-Version: 3.0
Cache-Control: private
Content-Type: application/json; charset=utf-8
Content-Length: 81
Connection: Close
"{\"StopPolling\":false,\"BatchSearchProgressReports\":[],\"MemberStatuses\":[]}"
AJAX
Обновление
Далее, скорее всего, будет изменено позже, но пока это работает, когда я генерирую класс ответа и возвращаю его как JSON, как обычный человек.
this.CheckForUpdate = function () {
var parent = this;
if (this.BatchSearchId != null && WorkflowState.SelectedSearchList != "") {
showAjaxLoader = false;
if (progressPending != true) {
progressPending = true;
$.ajax({
url: WorkflowState.UpdateBatchLink + "?SearchListID=" + WorkflowState.SelectedSearchList,
type: 'POST',
contentType: 'application/json; charset=utf-8',
cache: false,
success: function (data) {
for (var i = 0; i < data.MemberStatuses.length; i++) {
var response = data.MemberStatuses[i];
parent.UpdateCellStatus(response);
}
if (data.StopPolling = true) {
parent.StopPullingForUpdates();
}
showAjaxLoader = true;
}
});
progressPending = false;
}
}
Ответы
Ответ 1
Я считаю, что проблема заключается в том, что результат действия Json предназначен для того, чтобы взять объект (вашу модель) и создать HTTP-ответ с содержимым в виде данных в формате JSON из вашего объекта модели.
То, что вы передаете контроллеру Json, однако, является строковым объектом в формате JSON, поэтому он "сериализует" строковый объект JSON, поэтому содержимое ответа HTTP окружено двойными кавычками (Я предполагаю, что это проблема).
Я думаю, что вы можете изучить результат действия Content в качестве альтернативы результату action Json, поскольку у вас по существу уже имеется необработанный контент для ответа HTTP.
return this.Content(returntext, "application/json");
// not sure off-hand if you should also specify "charset=utf-8" here,
// or if that is done automatically
Другой альтернативой было бы десериализовать результат JSON от службы в объект, а затем передать этот объект методу Json контроллера, но недостатком является то, что вы будете де-сериализовать и затем повторно сериализовать данные, которые может быть ненужным для ваших целей.
Ответ 2
Вам просто нужно вернуть стандартный ContentResult и установить ContentType в "application/json".
Вы можете создать для него пользовательский ActionResult:
public class JsonStringResult : ContentResult
{
public JsonStringResult(string json)
{
Content = json;
ContentType = "application/json";
}
}
И затем верните экземпляр:
[HttpPost]
public JsonResult UpdateBatchSearchMembers()
{
string returntext;
if (!System.IO.File.Exists(path))
returntext = Properties.Settings.Default.EmptyBatchSearchUpdate;
else
returntext = Properties.Settings.Default.ResponsePath;
return new JsonStringResult(returntext);
}
Ответ 3
Да, это без каких-либо дополнительных проблем, чтобы избежать raw string json, это он.
public ActionResult GetJson()
{
var json = System.IO.File.ReadAllText(
Server.MapPath(@"~/App_Data/content.json"));
return new ContentResult
{
Content = json,
ContentType = "application/json",
ContentEncoding = Encoding.UTF8
};
}
ПРИМЕЧАНИЕ: обратите внимание, что тип возвращаемого метода JsonResult
для меня не работает, поскольку JsonResult
и ContentResult
оба наследуют ActionResult
, но между ними нет отношения.
Ответ 4
Все ответы здесь дают хороший и рабочий код. Но кто-то будет недоволен, что все они используют ContentType
качестве возвращаемого типа, а не JsonResult
.
К сожалению, JsonResult
использует JavaScriptSerializer
без возможности отключить его. Лучший способ обойти это - унаследовать JsonResult
.
Я скопировал большую часть кода из оригинального JsonResult
и создал JsonStringResult
класса, который возвращает переданную строку в качестве application/json
. Код для этого класса ниже
public class JsonStringResult : JsonResult
{
public JsonStringResult(string data)
{
JsonRequestBehavior = JsonRequestBehavior.DenyGet;
Data = data;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("Get request is not allowed!");
}
HttpResponseBase response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
response.Write(Data);
}
}
}
Пример использования:
var json = JsonConvert.SerializeObject(data);
return new JsonStringResult(json);
Ответ 5
от контроллера:
return Json (new {success = string}, JsonRequestBehavior.AllowGet);
и в случае успеха Javascript: function (data) {var response = data.success; .... }....}