Desenvolvimento - C#
WCF - Herança de Objetos com KnownTypes
Esse artigo descreve como implementar herança em classes DataContract no WCF usando o atributo KnownTypes.
por Pedro Henrique Barbosa FernandesÉ comum em aplicações orientadas a objetos, usarmos classes que são classes derivadas de outras classes base, como por exemplo, uma classe Carro e uma classe Moto que possuem como classe base a classe Veiculo. Baseando neste exemplo, imagine um método chamado CalculaParcela que recebe como parâmetro um objeto do tipo Veiculo:
public decimal CalculaParcela(Veiculo Veiculo) { …..
Uma das grandes vantagens de usar classes base é que, o parâmetro do tipo base consequentemente aceita todos os tipos derivados, assim um parâmetro do tipo Veiculo, irá aceitar objetos do tipo Carro e Moto.
Infelizmente com serviços fornecidos com WCF não acontece da mesma forma. Entretanto através do atributo KnownType podemos contornar este problema, dizendo para a classe base quais tipos derivados aquela classe irá suportar. Vamos entender melhor analisando os códigos abaixo:
Classe base Veiculo, note que usamos o atributo KnownType para dizermos que todo parâmetro do tipo Veiculo, também irá aceitar o tipo Carro:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
namespace WCFService.DataContracts
{
[DataContract]
[KnownType(typeof(Carro))]
public class Veiculo
{
[DataMember]
public string Nome { get; set; }
[DataMember]
public decimal Preco { get; set; }
[DataMember]
public string Fabricante { get; set; }
public virtual decimal CalculaPrecoParcela(int NumParcelas)
{
return (Preco + (Preco / 100) * NumParcelas) / NumParcelas;
}
}
}
Criamos um método na classe Veiculo que recebe o número de parcelas e calcula o preço de cada parcela aumentando em 1% para cada parcela, assim um carro de R$ 10000,00 parcelado em dez vezes irá aumentar 10% do total, resultando um valor de R$ 1100,00 por parcela.
Agora temos a classe Carro que deriva da classe Veiculo e sobrepõe o método CalculaPrecoParcela(), aumentando o valor em 1,5% por parcela em vez de 1% como foi definido na classe Veiculo:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;
namespace WCFService.DataContracts
{
[DataContract]
public class Carro : Veiculo
{
public override decimal CalculaPrecoParcela(int NumParcelas)
{
return (Preco + (Preco / 100) * (NumParcelas * (decimal)1.5)) / NumParcelas;
}
}
}
Definindo o contrato:
using System.ServiceModel;
using WCFService.DataContracts;
namespace WCFService.ServiceContracts
{
[ServiceContract]
public interface IVeiculoService
{
[OperationContract]
decimal CalculaParcela(Veiculo Veiculo, int NumParcelas);
}
}
E agora o serviço:
using WCFService.ServiceContracts;
using WCFService.DataContracts;
namespace WCFService.Implementation
{
public class VeiculoServiceImpl : IVeiculoService
{
public decimal CalculaParcela(Veiculo Veiculo, int NumParcelas)
{
return Veiculo.CalculaPrecoParcela(NumParcelas);
}
}
}
Podemos agora chamar o serviço e passar para a operação CalculaParcela() objetos do tipo Veiculo ou Carro:
using System;
using WCFClient.VeiculoServiceClient;
namespace WCFClient
{
class Program
{
static void Main(string[] args)
{
var Carro = new Carro
{
Preco = 100000,
Nome = "Uno",
Fabricante = "Fiat"
};
var Veiculo = new Veiculo
{
Fabricante = "Mercedes",
Nome = "Ônibus",
Preco = 100000
};
Console.WriteLine("=== Testando o KnownTypes ===");
using (var client = new VeiculoServiceClient.VeiculoServiceClient())
{
Console.WriteLine("Carro = {0:C}", client.CalculaParcela(Carro, 10));
Console.WriteLine("Ônibus = {0:C}", client.CalculaParcela(Veiculo, 10));
}
Console.ReadKey();
}
}
}
Com esse simples recurso podemos usar no cliente que vai consumir o serviço o mesmo modelo de classes que há no servidor, planejando e definindo os tipos bases e derivados permitindo assim uma maior interação entre cliente e servidor.