Pergunta

Quero criar uma aplicação da web com uma "interface de página única", usando o ASP.NET MVC.

Eu procurei se isso era pelo menos possível e acho que a resposta é: não por meios simples (lendo http://msdn.microsoft.com/en-us/magazine/cc507641.aspx#s2 parágrafo de segunda duração; Esse artigo é de maio de 2008, no entanto).

Encontrei outros exemplos que implementaram isso codificando/hackers com jQuery. No entanto, estou procurando uma solução limpa, usando abordagens .NET padrão, se possível.

O que eu quero é precisamente a mesma funcionalidade quando você cria um novo "aplicativo da Web MVC". No entanto, em vez de links para "/home/sobre" que recarregue a página inteira, eu quero links para "#Home/sobre "que carrega apenas a nova peça via Ajax.

A abordagem padrão dos modelos de chamada (visualizações parciais) com html.renderParcial é exatamente o que eu quero, só então carregando-as através de pedidos de Ajax.

Claro, pode ser que eu não possa usar esses Modelos que são renderizados pela Página Mestre por algum motivo (talvez espera sempre ser chamado em um determinado contexto de um determinado local). Mas talvez haja outra solução limpa para construir suas páginas de modelo e buscá-las na página principal.

Quem tem uma boa solução para implementar isso, uma interface de página única?

PS: Estou desenvolvendo o Visual Web Developer 2008 Express Edition com o MVC 1.0 instalado, em C#

editarAbaixo, li que trabalhar com os modelos é possível e que o jQuery parece realmente inevitável, então eu o testei. O código a seguir transforma links regulares criados por html.actionlink em links de âncora (com #) para conter a história e, em seguida, buscar a página via Ajax e apenas injetar a parte HTML em que estou interessado (ou seja, a página parcial dentro de div # ParcialView):

$("a").each(function() {
    $(this).click(function() {
        $("div#partialView").load($(this).attr("href") + " div#partialView");
        location.hash = $(this).attr("href");
        return false;
    });
});

Esses vínculos também permitem a degredação graciosa.

Mas o que me resta agora, ainda está buscando o todo página em vez de apenas a página parcial. Alterar o controlador não ajudou; Ainda me forneceu HTML de toda a página, com todas essas declarações:

public ActionResult About()
{
    return View();
    return View("About");
    return PartialView();
    return PartialView("About");
}

Como eu só poderia devolver o conteúdo da parte em que estou interessado (ou seja, o conteúdo da casa/sobre.aspx)? O que eu gostaria é postar um valor com Ajax (por exemplo, "requesttype = ajax") para que meu controlador saiba que a página é buscada via Ajax e retorna apenas a página parcial; Caso contrário, ele retornará a página inteira (ou seja, quando você visitar/home/em vez de #home/sobre).

É uma boa prática alterar o global.asax.cs, talvez, para criar um novo esquema de roteamento para o Ajax-Calls, que retornará apenas páginas parciais? (Ainda não olhei para isso.)

Edit2Robert Koritnik estava certo: eu também precisava de uma página do.ASCX (UserControl) com apenas o pequeno conteúdo de HTML dessa página. A primeira linha de aproximadamente.aspx estava ligada à página mestre via MasterPageFile="~/..../Site.master" o que causou que todo o HTML foi impresso.

Mas ser capaz de executar o seguinte no meu controlador:

public ActionResult About()
{
    return Request.IsAjaxRequest() ? (ActionResult)PartialView() : View();
}

Eu precisava alterar a maneira como um PartialView (arquivo .ascx) e um View (.aspx) foi encontrado, caso contrário, ambos os métodos retornariam a mesma página (About.aspx, em última análise, resultando em um loop infinito). Depois de colocar o seguinte Global.asax.cs, as páginas corretas serão devolvidas com PartialView() e View():

protected void Application_Start()
{
    foreach (WebFormViewEngine engine in ViewEngines.Engines.Where(c => c is WebFormViewEngine))
    {
        /* Normal search order:
        new string[] { "~/Views/{1}/{0}.aspx",
            "~/Views/{1}/{0}.ascx",
            "~/Views/Shared/{0}.aspx"
            "~/Views/Shared/{0}.ascx"
        };
        */

        // PartialViews match with .ascx files
        engine.PartialViewLocationFormats = new string[] { "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.ascx" };

        // Views match with .aspx files
        engine.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.aspx", "~/Views/Shared/{0}.aspx" };
    }

    RegisterRoutes(RouteTable.Routes);
}
Foi útil?

Solução

Vista completa vs. visão parcial

Parece que você estragou algo. Se você criar um About.aspx página com todo o HTML necessário para exibir a página inteira que realmente não importa se você diz

return PartialView('About');

A vista ainda retorna todo o HTML que está escrito nela.

Você deve criar um separado About.ascx Isso terá apenas o conteúdo da página sem o cabeçalho e outras coisas que fazem parte de toda a página.

Sua página original About.aspx terá algo assim em seu conteúdo (para evitar repetir a redação do mesmo conteúdo duas vezes):

<%= Html.RenderPartial("About") %>

E você pode ter duas ações do controlador. Um que retorna uma visão regular e que retorne uma visão parcial:

return View("About"); // returns About.aspx that holds the content of the About.ascx as well
return PartialView("About"); // only returns the partial About.ascx

Sobre rotas em global.asax

Em vez de escrever rotas separadas para chamadas de Ajax, você prefere escrever um filtro de ação que funcione semelhante ao AcceptVerbsAttribute filtro de ação. Dessa forma, suas solicitações do cliente permaneceriam as mesmas (e, assim, impedir que o usuário solicite manualmente coisas erradas), mas dependendo do tipo de solicitação, a ação correta do controlador será executada.

Outras dicas

Bem, você pode carregar a visualização parcial através da solicitação AJAX. Em exemplo, usarei o jQuery para fazer uma chamada AJAX.

Essas podem ser a ação no controlador (chamado Homecontroller):

public ActionResult About()
    {
        //Do some logic...
        //AboutView is the name of your partial view
        return View("AboutView");
    }

JQuery Ajax Call para colocar o HTML retido no lugar que você deseja:

var resultDiv = $('#contentDIV');

    $.ajax({
        type: "POST",
        url: "/Home/About",
        success: function(responseHTML) {
            resultDiv.replaceWith(responseHTML);
        }
    });

Editar-perguntas é atualizado

É possível fazer exatamente o que você deseja. A ação do primeiro controlador pode devolver a visão parcial, para que a minha "empréstimo" poderia ter sido algo assim:

<table>
<tr>
    <th>
        Column1Header
    </th>
    <th>
        Column2Header
    </th>
</tr>
<tr>
    <td>
    ...
    </td>
    <td>
    ...
    </td>
</tr>

E este HTML é exatamente o que você terá em respostahtml no Handler de sucesso no método jQuery Ajax.

Segundo, você pode distinguir na ação do controlador se a solicitação for uma solicitação AJAX:

public ActionResult About()
    {
        //partial AboutView is returned if request is ajax
        if (Request.IsAjaxRequest())
            return View("AboutView");
        else //else it will be the default view (page) for this action: "About"
            return View();
    }

Temos um site que faz exatamente isso e você realmente deseja usar a rota do jQuery aqui-quase mais fácil de implementar a longo prazo. E você pode facilmente se degradar graciosamente para usuários que não têm JavaScript ativado-como o Google.

Não está tão claro o que você está pedindo, é um exemplo completo ou para alguma funcionalidade específica? Você deve fazer isso sem jQuery para cenários simples, você pode usar os ajudantes do Ajax, como o método ActionLink. Além disso, eu realmente não entendo qual é o seu problema com renderpartial, mas talvez você esteja procurando algo como renderização do ASP.NET MVC Futures.

ASP.NET MVC 4 (agora na versão beta) adiciona suporte para aplicativos de página única no MVC.

http://www.asp.net/single-page-Application

Atualização: ... e eles o removeram do MVC 4 RC

Atualização: ... e está de volta com a atualização do outono de 2012

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