Olá pessoal! Para todos aqueles que querem aprender um pouco mais sobre Blazor. Hoje, continuaremos a criar nosso site para uma pizzaria, ou seja, criaremos um controlador de API da Web e tentaremos exibir os dados que vêm dele no componente Blazor.Como nosso aplicativo é sobre pizza, seria lógico adicionar imediatamente uma classe representando nosso produto principal. Chame-o de BasePizza e adicione-o ao projeto BlazingPizza.DomainModels . Na minha opinião, adicionar uma nova classe é muito legal implementado no Rider, uma caixa de diálogo sem bloqueio é exibida, insira o nome da classe e podemos escolher o que exatamente precisamos criar:
Depois disso, uma caixa de diálogo será exibida com uma solicitação para adicionar um arquivo ao git, responderemos afirmativamente.Conteúdo da turma:public class BasePizza
{
public int Id { get; set; }
public string Name { get; set; }
public decimal BasePrice { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
}
É um modelo para algum tipo de pizza, depois pode ser configurado como gostamos, redimensionamos, adicionamos coberturas e muito mais. O nome dos campos parece-me falar por si.No projeto BlazingPizza.DomainPizza , teremos classes representando o domínio comercial do nosso aplicativo. Ou seja, eles não devem e não saberão nada sobre como nossos dados são armazenados ou como são exibidos. Somente informações sobre o objeto de negócios, ou seja, pizza.Em seguida, precisamos de algo para, de alguma forma, obter esses dados para o cliente. Para fazer isso, vá para o projeto BlazingPizza.Server e adicione o PizzasController à pasta Controllers :public class PizzasController : Controller
{
public IActionResult Index()
{
return View();
}
}
Precisamos de um método que nos forneça uma lista de todos os princípios básicos da pizza.Além de adicionar um método, você precisa executar algumas etapas simples:- Vamos marcar o controlador com o atributo [ApiController], que oferece algumas vantagens, em particular, o retorno automático do código 400 se o modelo não passou na validação, sem ele é um controlador MVC normal que fornece o View.
- [Route(«pizzas»)]. Attribute Routing, , Conventional Routing, . “pizzas” ? http{s}://hostName/pizzas/{}
. - Controller ControllerBase, MVC .
Ok, por exemplo, fizemos uma solicitação localhost : 5000 / pizzas na esperança de obter uma lista de todas as pizzas e nada aconteceu. Novamente, o acordo está nos acordos.Se fosse uma solicitação Get , é necessário ter um método ( Action em termos de Asp.Net ) marcado com o atributo [HttpGet] ou, ainda mais óbvio, apenas um método chamado Get e é isso! Tudo o mais. Net e reflexão farão por nós.E renomeie o único método Index para Get. Altere o tipo do valor de retorno para IEnumerable <BasePizza>, não esqueça de adicionar o uso necessário. Bem, insira temporariamente um stub que o método não está implementado para, de alguma forma, compilar o código e garantir que não haja erros.Como resultado, o PizzasController.cs ficará assim:using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using BlazingPizza.DomainModels;
namespace BlazingPizza.Server.Controllers
{
[ApiController]
[Route("pizzas")]
public class PizzasController : ControllerBase
{
public IEnumerable<BasePizza> Get()
{
throw new NotImplementedException();
}
}
}
No momento, inicie o aplicativo de depuração, um botão com um bug verde.
e verifique se as rotas estão configuradas corretamente. A porta na qual você precisa fazer solicitações pode ser vista na guia Console :
no nosso caso, é 5000, se você fizer uma solicitação no caminho localhost : 5000 / pizzas, entraremos na ação Get e capturaremos uma NotImplementedException. Ou seja, enquanto nosso controlador não faz nada útil, ele simplesmente aceita solicitações e falha com um erro.Retornamos dados do controlador
É hora de fazer com que nosso código faça algo útil, como devolver pizzas. Até o momento, não implementamos uma camada de dados, apenas devolvemos algumas pizzas de nossa ação . Para fazer isso, retorne uma matriz que consiste em dois objetos BasePizza . O método Get será semelhante ao exemplo abaixo:
public IEnumerable<BasePizza> Get()
{
return new[]
{
new BasePizza()
{
BasePrice = 500,
Description = " ",
Id = 0,
ImageUrl = "img/pizzas/pepperoni.jpg"
},
new BasePizza()
{
BasePrice = 400,
Description = " ",
Id = 1,
ImageUrl = "img/pizzas/meaty.jpg"
},
};
}
O resultado da solicitação no navegador será assim:
Configurar a página inicial
A parte visível do aplicativo está nos componentes .razor no projeto BlazingPizza.Client . Estamos interessados no Index.razor na pasta Pages , abra-o e exclua todo o conteúdo que herdamos do projeto padrão. E vamos começar a adicionar o que realmente precisamos.1. Adicione:página"/" Esta diretiva é usada para configurar o roteamento do cliente e diz que esse controle será carregado por padrão, ou seja, se for apenas para o endereço do aplicativo localhost : 5000 / sem nenhum / Index, / Pizzas ou qualquer outra coisa.2)injetarHttpClient HttpClient Usando a diretivainjetar adicione um serviço como HttpClient à nossa página e chame o objeto HttpClient também . Um objeto do tipo HttpClient já está configurado para nós pela estrutura do Blazor, para que possamos fazer as solicitações necessárias. Esse tipo de injeção é chamado de Injeção de propriedades , uma implementação mais familiar por meio do construtor não é suportada e, como dizem os desenvolvedores, é improvável que isso apareça, mas é necessário aqui?3. Adicione uma diretiva @code{
}
É especificamente necessário para hospedar o código C # do cliente, o mesmo que substitui o JavaScript. Dentro deste bloco, colocamos uma coleção de objetos do tipo BasePizzaViewModelIEnumerable<BasePizzaViewModel> PizzaViewModels;
4. Como você já entendeu, BasePizzaViewModel não existe, é hora de criá-lo, este modelo será completamente análogo ao modelo de domínio BasePizza , exceto que ele terá o corpo de expressão GetFormattedBasePrice que retorna o preço da pizza base no formato que precisamos. O modelo irá adicionar à raiz do projeto BlazingPizza.ViewModels arquivo BasePizzaViewModel.cs :public class BasePizzaViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public decimal BasePrice { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public string GetFormattedBasePrice() => BasePrice.ToString("0.00");
}
5. Voltar ao nosso Index.razor e bloquearcódigo, adicione um código para obter todas as pizzas disponíveis. Vamos colocar esse código no método assíncrono OnInitializedAsync :protected async override Task OnInitializedAsync() {
}
Este método é chamado depois que o componente é inicializado e, no momento da chamada, todos os seus parâmetros já foram inicializados pelo componente pai. Nele, você pode executar algumas operações assíncronas, após as quais é necessária uma atualização de estado. Mais tarde vou falar sobre isso em mais detalhes. O método é chamado apenas uma vez quando o componente é criado.Por fim, adicione as pizzas que ficam dentro deste método:var queryResult = await HttpClient.GetJsonAsync<IEnumerable<BasePizza>>("pizzas");
pizzas - um caminho relativo que é adicionado à base e já foi definido para nós pela Blazor . Como segue da assinatura do método, os dados são solicitados pela solicitação get e, em seguida, o cliente tenta serializá-los em IEnumerable <BasePizza> .6. Como recebemos dados do tipo errado que queremos exibir no componente, precisamos obter objetos do tipo BasePizzaViewModel , Linq e seu método Select os usarão para converter objetos da coleção recebida em objetos do tipo que planejamos usar. Adicione o método OnInitializedAsync ao final :PizzaViewModels = queryResult.Select(i => new BasePizzaViewModel()
{
BasePrice = i.BasePrice,
Description = i.Description,
Id = i.Id,
ImageUrl = i.ImageUrl,
Name = i.Name
});
Mais tarde mostrarei como fazer sem escrever esse código de modelo, mas, por enquanto, vamos deixar como está. Parece que temos tudo o que precisamos e podemos continuar exibindo os dados recebidos.7. Acima da diretiva code , adicione o código html , dentro do qual estarão as próprias pizzas:<div class="main">
<ul class="pizza-cards">
</ul>
</div>
Como você pode ver, a lista ul com o nome da classe falante "cartões de pizza" está vazia até agora;@foreach (var pizza in PizzaViewModels)
{
<li style="background-image: url('@pizza.ImageUrl')">
<div class="pizza-info">
<span class="title">@pizza.Name</span>
@pizza.Description
<span class="price">@pizza.GetFormattedBasePrice()</span>
</div>
</li>
}
Toda a diversão aqui está dentro do circuito. para cada(var {item} in {items})Essa é uma marcação típica do Razor que nos permite usar o poder do C # na mesma página do código html comum . O principal é colocar o símbolo "@" na frente das palavras-chave e variáveis do idioma .Dentro do loop, simplesmente acessamos as propriedades do objeto de pizza .No final, exibimos o preço base formatado da pizza usando o método GetFormattedBasePrice . A propósito, essa é a diferença entre o modelo de domínio BasePizza e seu ViewModel representações, pois esse método contém a lógica mais simples para exibir o preço no formato exigido, o que não precisamos no nível de serviço, onde de alguma forma manipulamos o preço, mas não o mostramos em nenhum lugar.Exibimos os dados recebidos no navegador
Temos todos os dados necessários para exibir. É hora de iniciar nosso aplicativo e garantir que tudo funcione. Clicamos no botão Debug (no Rider, o botão Run apenas inicia o aplicativo sem o recurso Debug ).E ooh-ho, nada funciona também :) Abra o console ( F12 ) e veja que está tudo vermelho, algo obviamente deu errado. O Blazor não é tão inútil na depuração e toda a pilha de chamadas pode ser vista no console , e na minha opinião isso é feito ainda melhor do que no mesmo angular . Não há necessidade de adivinhar por sinais indiretos onde ocorreu o erro, basta olhar para a pilha de chamadas:
Ocorreu uma mensagem NullReferenceException ao renderizar a página . Como isso pôde acontecer, porque inicializamos a única coleção que usamos no método OnInitializedAsync .Para entender um pouco melhor, insira a saída de tempo nos lugares certos para ver o prazo do que aconteceu:Console.WriteLine($"Time from markup block: {DateTime.Now.ToString()}:{DateTime.Now.Millisecond.ToString()}");
Console.WriteLine($"Time from cycle: {DateTime.Now.ToString()}:{DateTime.Now.Millisecond.ToString()}");
Console.WriteLine($"Time from code block, before await: {DateTime.Now.ToString()}:{DateTime.Now.Millisecond.ToString()}");
Console.WriteLine($"Time from code block, after await: {DateTime.Now.ToString()}:{DateTime.Now.Millisecond.ToString()}");
Na captura de tela abaixo, no console, o que aconteceu no momento da renderização da página. Pode-se observar que a página começa a renderizar mesmo antes da conclusão dos métodos assíncronos.Na primeira passagem, o PizzaViewModels ainda não havia sido inicializado e capturamos uma NullReferenceException . Em seguida, conforme o esperado após a tarefa retornar o método OnInitializedAsync ao status RanToCompletion , o controle foi reprojetado. O que é digno de nota, durante a segunda passagem, entramos em um ciclo, como pode ser visto nas mensagens no console. Mas, neste momento, a interface do usuário não está mais sendo atualizada e não vemos nenhuma alteração visível.
De fato, o problema é muito fácil de resolver, você só precisa executar uma verificação nula de forma assíncrona antes de executar o loop ; uma exceção não ocorrerá pela primeira vez e, durante a segunda passagem, veremos os dados necessários.@if (PizzaViewModels != null)
{
@foreach (var pizza in PizzaViewModels)
{
………………………..
}
}
Parece um pouco melhor agora, não há mais mensagens de erro no console e você pode ver as informações que chegaram do servidor:
É muito melhor, mas não há estilos e recursos suficientes, em particular fotos, substituindo o conteúdo da pasta wwwroot pelo conteúdo da pasta "~ / Articles / Part2 /BlazingPizza.Client/wwwroot "(link no final do artigo) e execute o projeto novamente, muito melhor. Embora ainda esteja longe do ideal:
Eventos de vida útil dos componentes
Como já conhecemos um dos eventos de vida útil do componente OnInitializedAsync, seria lógico mencionar os outros:Nesta parte, aprendemos como receber dados do controlador e exibi-los para o usuário.Na próxima parte, organizaremos o Layout e adicionaremos uma camada de acesso a dados para exibir dados reais na página principal.Link para o repositório desta série de artigos.Link para a fonte original.