Działania kontrolera ASP.NET MVC, które zwracają JSON lub częściowy HTML

406

Próbuję utworzyć akcje kontrolera, które zwrócą albo JSON, albo częściowy HTML w zależności od parametru. Jaki jest najlepszy sposób, aby asynchronicznie zwrócić wynik na stronę MVC?

NathanD
źródło

Odpowiedzi:

519

W metodzie akcji zwróć Json (obiekt), aby zwrócić JSON na twoją stronę.

public ActionResult SomeActionMethod() {
  return Json(new {foo="bar", baz="Blech"});
}

Następnie po prostu wywołaj metodę działania za pomocą Ajax. Możesz użyć jednej z metod pomocniczych z ViewPage, takich jak

<%= Ajax.ActionLink("SomeActionMethod", new AjaxOptions {OnSuccess="somemethod"}) %>

SomeMethod byłby metodą javascript, która następnie ocenia zwracany obiekt Json.

Jeśli chcesz zwrócić zwykły ciąg, możesz po prostu użyć ContentResult:

public ActionResult SomeActionMethod() {
    return Content("hello world!");
}

ContentResult domyślnie zwraca tekst / zwykły jako jego contentType.
Jest to przeciążalne, więc możesz także:

return Content("<xml>This is poorly formatted xml.</xml>", "text/xml");
Haacked
źródło
9
przepraszam phil! to właściwie nie odpowiada na pytanie, prawda? jest to zdecydowanie przydatne, ale jak mówi Brad, musisz dowiedzieć się, o co proszą, i odpowiednio zwrócić wynik.
Simon_Weaver
zobacz moje nieco powiązane (no i to, które mnie tu doprowadziło) pytanie na stackoverflow.com/questions/482363/…
Simon_Weaver
9
jeśli znajdziesz odpowiedź, połącz ją w samym pytaniu. Nie sądzę też, by sprawdzanie tego było właściwą odpowiedzią.
Cherian
stackoverflow.com/questions/320291/... jest powiązany
Cherian
Jaka jest w pełni kwalifikowana nazwa tej klasy Json?
Josh Withee,
112

Myślę, że powinieneś rozważyć AcceptTypes żądania. Używam go w moim bieżącym projekcie, aby zwrócić poprawny typ zawartości w następujący sposób.

Twoje działanie na kontrolerze może to przetestować jak na obiekcie żądania

if (Request.AcceptTypes.Contains("text/html")) {
   return View();
}
else if (Request.AcceptTypes.Contains("application/json"))
{
   return Json( new { id=1, value="new" } );
}
else if (Request.AcceptTypes.Contains("application/xml") || 
         Request.AcceptTypes.Contains("text/xml"))
{
   //
}

Następnie możesz zaimplementować aspx widoku, aby uwzględnić przypadek częściowej odpowiedzi xhtml.

Następnie w jQuery możesz go pobrać, przekazując parametr type jako json:

$.get(url, null, function(data, textStatus) {
        console.log('got %o with status %s', data, textStatus);
        }, "json"); // or xml, html, script, json, jsonp or text

Mam nadzieję, że to pomaga Jamesowi

James Green
źródło
5
Dzięki James, może to być bardzo przydatne do stworzenia strony internetowej i interfejsu API REST przy użyciu tych samych akcji kontrolera.
NathanD
Jeśli mam wiele takich metod w moim kontrolerze, czy jest jakiś sposób, aby to zrobić bardziej ogólnie?
Seph
W której przestrzeni nazw znajduje się klasa Json? Jaka jest zależność dla project.json? Z góry dziękuję
Andrei
1
To klasa JsonResult z System.Web.Mvc (w System.Web.Mvc.dll) @Andrei
James Green
Dziękuję, znalazłem to. Może zaktualizujesz odpowiedź, aby odzwierciedlić nowy interfejs API? Btw, używam rdzenia dotnet, gdzie jest Microsoft.AspNetCore.Mvc.JsonResult.
Andrei
78

Innym dobrym sposobem radzenia sobie z danymi JSON jest użycie funkcji getJSON JQuery. Możesz zadzwonić do

public ActionResult SomeActionMethod(int id) 
{ 
    return Json(new {foo="bar", baz="Blech"});
}

Metoda z metody getJSON jquery po prostu ...

$.getJSON("../SomeActionMethod", { id: someId },
    function(data) {
        alert(data.foo);
        alert(data.baz);
    }
);
SaaS Developer
źródło
15
To w ogóle nie odpowiada na pytanie.
Aaronaught
2
@Aaronaught Właściwie pierwsza część return Json(new {foo="bar", baz="Blech"});ma!
SparK
Weź również pod uwagę $ .post stackoverflow.com/questions/751218/... (ASP.Net MVC domyślnie wyłącza żądania JSON Get ze względów bezpieczeństwa)
Greg
50

Znalazłem kilka problemów z implementacją wywołań MVC ajax GET z JQuery, które spowodowały u mnie bóle głowy, dlatego dzielę się rozwiązaniami tutaj.

  1. Pamiętaj, aby w wywołaniu ajax uwzględnić typ danych „json”. Spowoduje to automatyczne przeanalizowanie zwróconego obiektu JSON (pod warunkiem, że serwer zwróci prawidłowy plik json).
  2. Uwzględnij JsonRequestBehavior.AllowGet; bez tego MVC zwrócił błąd HTTP 500 ( dataType: jsonpodany na kliencie).
  3. Dodaj cache: falsedo wywołania $ .ajax, w przeciwnym razie ostatecznie otrzymasz odpowiedzi HTTP 304 (zamiast odpowiedzi HTTP 200), a serwer nie przetworzy Twojego żądania.
  4. Wreszcie, w Json rozróżniana jest wielkość liter, więc obudowa elementów musi być dopasowana po stronie serwera i po stronie klienta.

Przykładowy JQuery:

$.ajax({
  type: 'get',
  dataType: 'json',
  cache: false,
  url: '/MyController/MyMethod',
  data: { keyid: 1, newval: 10 },
  success: function (response, textStatus, jqXHR) {
    alert(parseInt(response.oldval) + ' changed to ' + newval);                                    
  },
  error: function(jqXHR, textStatus, errorThrown) {
    alert('Error - ' + errorThrown);
  }
});

Przykładowy kod MVC:

[HttpGet]
public ActionResult MyMethod(int keyid, int newval)
{
  var oldval = 0;

  using (var db = new MyContext())
  {
    var dbRecord = db.MyTable.Where(t => t.keyid == keyid).FirstOrDefault();

    if (dbRecord != null)
    {
      oldval = dbRecord.TheValue;
      dbRecord.TheValue = newval;
      db.SaveChanges();
    }
  }

    return Json(new { success = true, oldval = oldval},
                JsonRequestBehavior.AllowGet);
}
Shane
źródło
13

Aby odpowiedzieć na drugą połowę pytania, możesz zadzwonić:

return PartialView("viewname");

gdy chcesz zwrócić częściowy kod HTML. Musisz tylko znaleźć sposób, aby zdecydować, czy żądanie chce JSON czy HTML, być może na podstawie części / parametru adresu URL.

Brad Wilson
źródło
2
więc pytanie nie pozostaje bez odpowiedzi?
Simon_Weaver
2
To nie odpowiada na pytanie.
Aaronaught
szuka żądania ajax, aby uzyskać HTML za pomocą PartialView wymaga odświeżenia strony, chyba że zwrócisz widok z metody akcji za pomocą wywołania ajax
Chris McGrath
7

Alternatywne rozwiązanie ze szkieletem incoding

Działanie zwróć json

Kontroler

    [HttpGet]
    public ActionResult SomeActionMethod()
    {
        return IncJson(new SomeVm(){Id = 1,Name ="Inc"});
    }

Strona Razor

@using (var template = Html.Incoding().ScriptTemplate<SomeVm>("tmplId"))
{
    using (var each = template.ForEach())
    {
        <span> Id: @each.For(r=>r.Id) Name: @each.For(r=>r.Name)</span>
    }
}

@(Html.When(JqueryBind.InitIncoding)
  .Do()
  .AjaxGet(Url.Action("SomeActionMethod","SomeContoller"))
  .OnSuccess(dsl => dsl.Self().Core()
                              .Insert
                              .WithTemplate(Selector.Jquery.Id("tmplId"))
                              .Html())
  .AsHtmlAttributes()
  .ToDiv())

Akcja zwraca HTML

Kontroler

    [HttpGet]
    public ActionResult SomeActionMethod()
    {
        return IncView();
    }

Strona Razor

@(Html.When(JqueryBind.InitIncoding)
  .Do()
  .AjaxGet(Url.Action("SomeActionMethod","SomeContoller"))
  .OnSuccess(dsl => dsl.Self().Core().Insert.Html())
  .AsHtmlAttributes()
  .ToDiv())
Vlad
źródło
4

PartialViewResult i JSONReuslt dziedziczą z klasy podstawowej ActionResult. więc jeśli typ zwrotu zostanie określony dynamicznie, zadeklaruj wynik metody jako ActionResult.

public ActionResult DynamicReturnType(string parameter)
        {
            if (parameter == "JSON")
                return Json("<JSON>", JsonRequestBehavior.AllowGet);
            else if (parameter == "PartialView")
                return PartialView("<ViewName>");
            else
                return null;


        }
Anil Vaddepally
źródło
3

Dla osób, które dokonały aktualizacji do MVC 3, tutaj jest fajny sposób korzystania z MVC3 i Json

Sarath
źródło
1
możesz także skorzystać z tej samej techniki, co w tym artykule w MVC 2
longhairedsi
2
    public ActionResult GetExcelColumn()
    {            
            List<string> lstAppendColumn = new List<string>();
            lstAppendColumn.Add("First");
            lstAppendColumn.Add("Second");
            lstAppendColumn.Add("Third");
  return Json(new { lstAppendColumn = lstAppendColumn,  Status = "Success" }, JsonRequestBehavior.AllowGet);
            }
        }
sakthi
źródło
czy możesz dodać trochę więcej informacji o tym, co to robi?
RealCheeseLord,
Ponieważ kod pokazuje, że zwraca JSON, typem zwrotu powinien być JsonResult, a nie ActionResult
noobprogrammer
0

Elastyczne podejście do tworzenia różnych wyników na podstawie żądania

public class AuctionsController : Controller
{
  public ActionResult Auction(long id)
  {
    var db = new DataContext();
    var auction = db.Auctions.Find(id);

    // Respond to AJAX requests
    if (Request.IsAjaxRequest())
      return PartialView("Auction", auction);

    // Respond to JSON requests
    if (Request.IsJsonRequest())
      return Json(auction);

    // Default to a "normal" view with layout
    return View("Auction", auction);
  }
}

Request.IsAjaxRequest()Metoda jest bardzo prosta: to tylko sprawdza nagłówki HTTP na żądanie przychodzące, aby sprawdzić, czy wartość żądanego X-Z jest nagłówekXMLHttpRequest , który jest automatycznie dołączany przez większość przeglądarek i ram AJAX.

Niestandardowa metoda rozszerzenia, aby sprawdzić, czy żądanie dotyczy json, czy nie, abyśmy mogli je wywołać z dowolnego miejsca, podobnie jak metoda rozszerzenia Request.IsAjaxRequest ():

using System;
using System.Web;

public static class JsonRequestExtensions
{
  public static bool IsJsonRequest(this HttpRequestBase request)
  {
    return string.Equals(request["format"], "json");
  }
}

Źródło: https://www.safaribooksonline.com/library/view/programming-aspnet-mvc/9781449321932/ch06.html#_javascript_rendering

Mannan Bahelim
źródło