Pergunta

Eu quero evitar ter muita if Request.IsAjaxRequest() em meus controladores. Eu estava pensando que se eu pudesse condensar esta lógica para uma ActionFilter seria fácil de adotar uma convenção no meu aplicativo para fornecer uma segunda ação para qualquer pedido que pode usar Ajax, enquanto fornece uma volta queda se JavaScript está desativado.

public ActionResult Details(int id)
{
  // called normally, show full page
}

public ActionResult Details_Ajax(int id)
{
  // called through ajax, return a partial view
}

Inicialmente eu pensei que eu poderia fazer algo parecido com isto:

public class AjaxRenameAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.RouteData.Values["action"] = filterContext.RouteData.Values["action"] + "_Ajax";

    }

Mas isso não vai funcionar porque a ação para invocar é decidida e, em seguida, os filtros que são processados.

Eu realmente não querem voltar a RedirectResult cada vez que alguém chama uma ação, parece um inútil pouco para dobrar a quantidade de solicitações HTTP.

Existe uma maneira diferente de rota através da solicitação para uma ação diferente? Ou é o que estou fazendo desaconselhável e eu deveria procurar uma maneira melhor de fazer as coisas?

Felicidades

Foi útil?

Solução

AcceptAjaxAttribute é, provavelmente, é o que é necessário aqui; no entanto, eu gostaria de propor uma maneira diferente de pensar sobre este problema.

Nem todas as requisições Ajax são iguais. pedido um Ajax poderia ser tentando realizar qualquer uma das seguintes coisas:

  • A ligação de dados JSON a uma grade rica (como jqGrid);
  • Análise / transformação de dados XML, como um feed RSS;
  • Carregando HTML parcial em uma área da página;
  • Assincronamente carregar um script (google.load pode fazer isso);
  • Como manusear uma mensagem de sentido único a partir do cliente;
  • E provavelmente mais alguns que eu estou esquecendo.

Quando você "selecione" um específico "ação alternativa" baseada exclusivamente no método IsAjaxRequest, você está amarrando algo muito genérico - uma solicitação assíncrona - a funcionalidade específica no servidor. É em última análise, vai fazer seu projeto mais frágil e também fazer o seu controlador mais difícil de teste de unidade (embora existam maneiras de fazer isso, você pode zombar do contexto).

A bem concebido action deve ser consistente , que só deve cuidar o o pedido foi para e não como o pedido foi feito. Um ponto forças para outros atributos como AuthorizeAttribute como exceções, mas gostaria de fazer uma distinção para filtros, que na maioria das vezes descrevem o comportamento que tem que acontecer, quer um "antes" ou "depois" a acção tem lugar, não "em vez de. "

Chegando ao ponto aqui, o objetivo declarado na pergunta é boa; você deve definitivamente tem métodos diferentes para o que está corretamente descrito como diferentes acções:

public ActionResult Details(int id)
{
    return View("Details", GetDetails(id));
}

public ActionResult JsonDetails(int id)
{
    return Json(GetDetails(id));
}

public ActionResult PartialDetails(int id)
{
    return PartialView("DetailTable", GetDetails(id));
}

E assim por diante. No entanto, usando um selector de acção Ajax para escolher entre estes métodos está a seguir a prática de "degradação progressiva" , a qual foi essencialmente substituído (pelo menos OMI) por melhoria progressiva .

É por isso que, embora eu ame ASP.NET MVC, eu principalmente evitam o AjaxHelper, porque eu não achar que ele expressa esse conceito tão bem; ele tenta esconder muito de você. Em vez de ter o conceito de um "Ajax Form" ou uma "ação Ajax", vamos acabar com a distinção e vara para HTML em linha reta, em seguida, injetar a funcionalidade Ajax separadamente uma vez que estamos certos de que o cliente pode lidar com isso .

Aqui está um exemplo em jQuery - embora você pode fazer isso em MS AJAX demasiado:

$(function() {
    $("#showdetails").click(function() {
        $("#details").load("PartialDetails", { id: <%= Record.ID %> });
        return false;
    }
});

Este é o suficiente para injetar Ajax em uma página MVC. Comece com um link HTML velho liso e substituí-lo com uma chamada Ajax que vai para uma ação de controlador diferente .

Agora, se em outro lugar em seu site que você decidir que quer usar uma grade em vez disso, mas não quero quebrar as páginas usando o processamento parcial, você pode escrever algo como isto (digamos que você tem um único mestre- página de detalhes com uma lista de "ordens" no lado esquerdo e uma tabela de detalhes à direita):

$(".detaillink").click(function() {
    $('#detailGrid').setGridParam({
        url: $(this).attr("href").replace(/\/order\/details/i,
            "/order/jsondetails")
    }); 
    $("#detailGrid").trigger("reloadGrid");  
});

Esta abordagem separa completamente o comportamento do cliente a partir do comportamento do servidor. O servidor é efetivamente dizendo ao cliente: Se você quiser a versão JSON, perguntar para a versão JSON, e oh, a propósito, aqui está um script para converter seus links se você sabe como para executá-lo. não seletores de ação e finagling com sobrecargas do método, não especial zombando você tem que fazer, a fim de executar um teste simples, sem confusão sobre que a ação faz o quê e quando. Apenas um par de linhas de JavaScript. As ações do controlador são curtos e doce, exatamente do jeito que deveria ser.

Esta não é a única abordagem. Obviamente, as classes tais como AcceptAjaxAttribute existem porque eles esperavam alguns desenvolvedores para usar o método de detecção de solicitação. Mas, depois de ter experimentado um pouco com os dois, acho que este caminho muito mais fácil raciocinar sobre e, portanto, mais fácil de projetar / código corretamente.

Outras dicas

Como cerca AcceptAjaxAttribute em MvcFutures?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top