9
respostas

Error endpoint GET /Artistas/{nome}

Estou tendo o seguinte errro com o endpoint GET /Artistas/{nome}:

An unhandled exception occurred while processing the request. NotSupportedException: The deserialization constructor for type 'Castle.Proxies.ArtistaProxy' contains parameters with null names. This might happen because the parameter names have been trimmed by ILLink. Consider using the source generated serializer instead.

Este é o código do meu endpoint:

app.MapGet("/Artistas/{nome}", ([FromServices] DAL<Artista> dal, string nome) =>
{
   var artista = dal.RecuperarPor(a => a.Nome.ToUpper().Equals(nome.ToUpper()));
   if (artista is null)
   {
       // 404
       return Results.NotFound();
   }
   // 200
   return Results.Ok(artista);
});

Quando passo um parametro de um nome de artista que não existe este erro nao ocorre, entra na condição artista is null e retorna erro 404 Not Found.

Quando passo um parametro de um nome de artista que existe (ex: Djavan) retorna este erro.

Testei a função RecuperarPor através do programa de console > MenuMostrarMusicas que também utiliza esssa função e ela funcionou normalmente

Endpoints que também utilizam esta função como atualizar artista(MapPut), deletar artista(MapDelete) estão funcionando normalmente

9 respostas

Olá, Erik!

Pelo que você descreveu, parece que o problema está ocorrendo na deserialização do objeto Artista. A mensagem de erro sugere que a deserialização está tentando usar um construtor que contém parâmetros com nomes nulos, o que não é suportado.

A causa mais comum para esse problema é a utilização de um proxy para a classe Artista. Proxies são usados em alguns frameworks, como o Entity Framework, para permitir recursos como o carregamento preguiçoso de dados. No entanto, eles podem causar problemas com a serialização e deserialização de dados.

Uma possível solução para o problema seria desabilitar a criação de proxies. No contexto do Entity Framework, isso pode ser feito ao configurar o contexto de dados, como no exemplo abaixo:

public class MeuContexto : DbContext
{
    public MeuContexto(DbContextOptions<MeuContexto> opcoes)
        : base(opcoes)
    {
        // Desabilita a criação de proxies
        this.ChangeTracker.LazyLoadingEnabled = false;
        this.ChangeTracker.AutoDetectChangesEnabled = false;
        this.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    }

    // Restante da classe...
}

Note que desabilitar a criação de proxies pode ter implicações no comportamento do seu aplicativo, então é importante testar bem a aplicação após essa alteração.

Outra opção seria utilizar um DTO (Data Transfer Object) para transferir os dados do artista, em vez de usar a entidade Artista diretamente. Isso pode evitar problemas com a serialização e deserialização de dados.

Espero ter ajudado e bons estudos!

Estou com o mesmo problema de Deserialização e a possivel solução acima não deu certo na minha aplicação. Insira aqui a descrição dessa imagem para ajudar na acessibilidade

A principio, o erro faz pensar que é a tentativa de deseralization em proxys, porém, depois de comparar o código do github (e mt tempo brigando com google e chatgpt), eu descobri que o erro está na classe Artista.cs, dentro de ScreenSound.Modulos, um erro até engraçado por assim dizer:

no curso passado terminamos com o começo da classe assim:

namespace ScreenSound.Modelos; 

public class Artista 
{
    public virtual ICollection<Musica> Musicas { get; set; } = new List<Musica>();

    public Artista(string nome, string bio)
    {
        Nome = nome;
        Bio = bio;
        FotoPerfil = "https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png";
    }

fonte: https://github.com/alura-cursos/3506-csharpWeb-screensound-curso1/blob/aula05-relacionamento/ScreenSound/Modelos/Artista.cs e nesse curso, em algum momento da produção da aula 2 o código está assim:

namespace ScreenSound.Modelos; 

public class Artista 
{
    public virtual ICollection<Musica> Musicas { get; set; } = new List<Musica>();
    public Artista()
    {
        FotoPerfil = "https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png";
    }

fonte: https://github.com/alura-cursos/ScreenSound.API/blob/Aula2-MaoNaMassa-Musica/ScreenSound.Shared.Modelos/Modelos/Artista.cs

agora, confesso que meu conhecimento de ASP.NET é bem baixo k, mas, não sei dizer se, o lazy loading instancia a classe Artista, em começo vazio, e com esse construtor, o Serialization, entende que é possível carregar com os parametros de nome nulo (pois, existe um construtor vazio) e nisso ele consegue puxar todas as informações que vem da proxy.

porém, isso é um achismo meu, se tiver alguém mais experiente que ver isso, e achar que está errado, pfvr me corrija k, mas a solução é essa ai de colocar um construtor sem parametros na classe artista.

Pedro, deu certo. Eu tinha dado uma parada nos estudos e por curiosidade voltei hoje e realizei a mudança

Não sei se alguém ainda está com esse problema mas eu simplesmente tirei o construtor da classe Artista() e defini Nome e Bio como sendo textos vazios. Isso muda a regra de negócio mas acredito que se esses forem usados como objetos de negócio mesmo eles não deveriam ser usados para serialização. Deveria haver alguma DTO para separar a regra dos frameworks. A classe ficou assim

public class Artista
{
    public string Nome { get; set; } = "";
    public string FotoPerfil { get; set; } = "https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png";
    public string Bio { get; set; } = "";
    
    //Construtor apagado.

Então Julio, eu tinha pensado antes de adicionar o construtor, era usar o Newton pra não ter que mexer na model, mas foi onde acabei vendo que no github estava já com o modelo alterado e só segui o bonde k. Mas realmente, pelo que conheço, a model só tem as props e nada mais, pois como o proprio nome diz, é um modelo.

E outra, quando tentei usar Newton, eu cai em vários problemas como questão de ciclo e memória do sistema, a ponto do próprio chatgpt por exemplo falar que não era uma boa ideia k, foi onde fui pra opção ver github, e achar essa inconsistência k.

Tive o mesmo problema e percebi que o erro estava no construtor mesmo. Em algum momento do curso quando é montado o construtor de Artistas é despercebido que foi deixado passar o construtor padrão, e quando a classe é instanciada no projeto da API não é passado informações de nome, bio, etc. então apenas adicionei o construtor padrão e funcionou

public class Artista 
{
 
    public Artista() { } //Este aqui
    
    public Artista(string nome, string bio)
    {
        Nome = nome;
        Bio = bio;
        FotoPerfil = "https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png";
    }

Eu sei que já tem várias soluções acima, porém eu encontrei uma em que não é preciso alterar nada no código, só adicionar um novo método que retorna uma lista ao invés de só um JSON, é só adicionar este método no DAL e ao invés do RecuperaPor, substitui por RecuperaListaPor (novo método)

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Após pesquisar para entender sobre as correções aqui obtidas, vi que ambas estão corretas, entre outras varias que possa sugir, mais com base nas duas abaixo fui atras de explicação para cada uma.

Fica a criterio de cada uma escolher qual usar, pois vai depender muito da forma e a arquitetura usada por cada um para desenvolver o projeto, muitos segui o curso, porem pode haver outros com uma base maior sobre o assunto que use uma outra forma ou arquitetura.

Construtor Vazio classe Artista.cs

// Classe Artista.cs
public class Artista 
{
    public Artista() { } // Construtor vazio
    
    public Artista(string nome, string bio) // Construtor personalizado
    {
        Nome = nome;
        Bio = bio;
        FotoPerfil = "https://cdn.pixabay.com/photo/2016/08/08/09/17/avatar-1577909_1280.png";
    }
    
    // restante do código
}

Prós:

  • Simplicidade: Um construtor vazio oferece uma maneira simples de criar instâncias da classe sem a necessidade de fornecer parâmetros.
  • Flexibilidade: Ele permite a criação de instâncias da classe com valores padrão para seus membros, o que pode ser útil em alguns cenários.

Contras

  • Ocultação de requisitos: Se a classe requer parâmetros para serem inicializados corretamente, um construtor vazio pode ocultar esses requisitos e levar a instâncias inválidas.

Adicionar novo metodo classe DAL.cs

// Classe DAL.cs
public class DAL<T> where T : class
{
    private readonly ScreenSoundContext context;

    public DAL(ScreenSoundContext context)
    {
        this.context = context;
    }

    // metodo RecuperarPor usado no curso
    public T? RecuperarPor(Func<T, bool> condicao)
    {
        return context.Set<T>().FirstOrDefault(condicao);
    }

    // metodo RecuperarPorNome adicionado ao projeto
    public IEnumerable<T>? RecuperarPorNome(Func<T, bool> condicao)
    {
        return context.Set<T>().Where(condicao).ToList();
    }
    
    // restante do código
}
// (ScreenSound.API)  Program.cs  
app.MapGet("/Artistas/{nome}", (string nome) =>
{
    var dal = new DAL<Artista>(new ScreenSoundContext());
    return dal.RecuperarPorNome(a => a.Nome.ToUpper().Equals(nome.ToUpper()));
});

Prós

  • Separação de responsabilidades: A recuperação de objetos é uma responsabilidade da classe DAL, e um método específico para isso pode melhorar a coesão e a clareza do código.
  • Flexibilidade: O método de recuperação permite a implementação de lógica personalizada para recuperar objetos com base em critérios específicos.

Contras

  • Complexidade adicional: Adicionar um método de recuperação pode introduzir complexidade adicional na classe DAL e no código em geral.
  • Violação do princípio da responsabilidade única: Se o método de recuperação tiver muitas responsabilidades ou se misturar com lógica de negócios, ele pode violar o princípio da responsabilidade única.

Fonte: chat.openai.com

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software