Quem trabalhou de perto nos meus projetos sabe que tenho uma opinião bem radical a respeito da maioria dos frameworks de injeção de dependência. Aliás, compartilhando contigo minha opinião: Eles fazem injeção de dependência, mas pouco sobre IoC, e podem, diversas vezes ser encarados meramente como Service Locators, o que na minha opinião deixa pobre qualquer implementação que queira se fundamentar em IoC e DI.
A origem
Eu já disse o que me levou a portar o Spring.NET para .NET Standard, eu fiz isso faz um tempinho, agora já tenho projetos em produção usando. Agora que estou começando um novo projeto do zero, acho que esse é um bom momento para começar uma série de posts sobre o tema. A propósito Dependency Injection é um tema que me interessa já faz muito tempo, pelo menos 10 anos, e por isso gosto de tocar nesse assunto com certa freqüência, e você pode achar diversos posts no tópico #dependency-injection.
Propósito desse post
Esse post tem o propósito de apresentar o mais básico: o setup de um projeto ASP.NET Core 2.2 com .NET Core, rodando em containers, no Linux.
Criando o projeto
O primeiro passo é criar um projeto do zero, fica mais fácil explicar assim, pois um projeto simples torna todo o fluxo mais compreensível.
Adicionando dependências
Agora que o projeto está criado, devemos adicionar as dependências Oragon.Spring. Com um único pacote nuget podemos fazer isso:
Adicione o pacote nuget Oragon.Spring.Extensions.DependencyInjection. Ele traz consigo Oragon.Spring.Core (mas não traz Oragon.Spring.AOP fique atento a isso). Nesse tutorial aqui, não será necessário, mas como minha ideia é usar esse post como referência na série, lá na frente vamos precisar desse pacote, quando falarmos de AOP.
Pronto, até aqui temos um novo projeto, com o Oragon.Spring, falta agora criar um arquivo de configuração e alterar alguns detalhes no Startup.cs. Vamos lá?
No Startup.cs vamos alterar o método ConfigureServices:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
return services.WithSpring(
$"assembly://Oragon.Spring.GetStarted/Oragon.Spring.GetStarted/Container.config.xml"
);
}
Note que a versão default do método ConfigureServices tem a assinatura void ConfigureServices(IServiceCollection services) enquanto a nossa é ligeiramente diferente e retorna um IServiceProvider. Nesse exemplo estou usando o arquivo de configuração como embedded resource. Veremos isso a seguir.
A sintaxe para é de formação de nome é a seguinte:
$”assembly://[AssemblyName]/[Namespace]/[FileName]”
A parte de namespace segue o mesmo princípio que o visual studio usa para criar arquivos nos devidos namespaces (usando o namespace padrão do projeto e suas pastas).
O próximo elemento que você precisa criar é o arquivo XML do Spring, eu criei com o nome de Container.config.xml. A primeira versão dele, vazio é a seguinte.
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.net/aop" > </objects>
Esse é o arquivo em que vamos configurar o container IoC. O Oragon.Spring, nem o Sprinng.net não exigem a utilização de embedded resources, no entanto, como na configuração desse exemplo será necessário. A única demanda para funcionar é que seja coerente. (se configurar como embedded resource, coloque-o como embedded resource, se quer carregar a partir do disco, configure corretamente o path para isso).
Checkpoint 1
Nesse momento se você fez tudo certo, teu projeto vai rodar e vai exibir a rota default (api/values) sem apresentar nenhum problema. O Oragon.Spring já está sendo carregado, mas não tem o que entregar ainda, pois sua configuração está vazia e não há ninguém demandando nada dele. Mas a partir de agora vamos mudar isso e integrá-lo ao seu código, mas antes disso:
Teste rodando com os diversos profiles:
- Docker
- Oragon.Spring.GetStarted
- IIS Express
Nesse ponto, todos os profiles devem funcionar perfeitamente.
Caso apareça algum erro, revise todos os passos anteriores, você deve ter pulado ou ignorado alguma coisa.
Configurando seu Visual Studio
Até o momento teu projeto está pronto, mas falta configurar seu visual studio. Essa configuração é super simples, você vai colocar 3 arquivos XSD que no path de Schemas do Visual Studio, é o suficiente para habilitar o intellisense do XML de configuração do Spring.
Fique atento e não pule essa etapa. Se você não tiver os XSD no teu visual studio, você levará de 4 a 7 vezes mais tempo para se adaptar. E é provável que você abandone a ideia de testar exatamente nessa parte.
A forma mais fácil de descobrir o path é achar a instalação do visual studio que estiver rodando seu projeto. Nem precisa fechar a IDE, basta achar o path.
Seu Visual Studio roda sob a pasta ./Common7/IDE, volte 2 níveis e você já se depara com a pasta XML, dentro dela há uma pasta Schemas. Como mostra a imagem abaixo:
Copie os arquivos (estão no repositório do projeto ou faça download aqui).
Uma vez copiados os arquivos, está tudo pronto, e agora é hora de testar:
Vá no meio do arquivo (entre a tag <objects> e </objects>) e digite “<” (sinal de menor).
Se você fez tudo certinho, você já verá o intelisense trabalhando por você:
Em 2010 eu fiz um vídeo para mostrar isso na prática, funcionando:
Esse passo não é necessário, nem requisito para nada funcionar, exceto o intellisense. Porém, sem ele, a chance de você ficar perdido(a) é muito grande.
Dando vida à injeção de dependência.
Agora é hora de da vida a isso tudo, seu projeto está configurado, seu ambiente está configurado.
Eu criei uma classe OragonSpringExample, um POCO simples, apenas para demonstrar algumas capacidades bem básicas.
public class OragonSpringExample { public string StringExample { get; set; } public int IntExample { get; set; } public DateTime? ReveillonTime { get; set; } public DateTime CurrentTime { get; set; } public bool BooleanProperty { get; set; } public List<OragonSpringExample> ChildList { get; set; } public string FillOnConstructor { get; } public OragonSpringExample(string constructorParameter) { this.FillOnConstructor = constructorParameter; } }
Coloquei algumas datas, strings, números, booleans, listas, enfim, não há limitação pelo aspecto de factory do spring.
Nosso ValuesController, mudou um pouco, afinal queremos mostrar o resultado no browser!
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { [HttpGet] public ActionResult<OragonSpringExample> Get([FromServices] OragonSpringExample oragonSpringExample) { return oragonSpringExample; } }
E por fim, nosso xml de configuração ficou assim:
<?xml version="1.0" encoding="utf-8" ?> <objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.net/aop" > <object name="OragonSpringExample" type="Oragon.Spring.GetStarted.Model.OragonSpringExample, Oragon.Spring.GetStarted"> <constructor-arg name="constructorParameter" value="On Constructor Too"/> <property name="StringExample" value="aa" /> <property name="IntExample" value="7" /> <property name="ReveillonTime" expression="date('2017/12/31')" /> <property name="CurrentTime" expression="DateTime.Now" /> <property name="BooleanProperty" value="true"/> <property name="ChildList"> <list element-type="Oragon.Spring.GetStarted.Model.OragonSpringExample, Oragon.Spring.GetStarted"> <object name="OragonSpringExample" type="Oragon.Spring.GetStarted.Model.OragonSpringExample, Oragon.Spring.GetStarted"> <constructor-arg name="constructorParameter" value="Child - Composite"/> </object> </list> </property> </object> </objects>
Agora executando como um container docker, vemos o seguinte resultado no browser!
{ "stringExample": "aa", "intExample": 7, "reveillonTime": "2017-12-31T00:00:00", "currentTime": "2019-01-27T03:03:51.9106723+00:00", "booleanProperty": true, "childList": [ { "stringExample": null, "intExample": 0, "reveillonTime": null, "currentTime": "0001-01-01T00:00:00", "booleanProperty": false, "childList": null, "fillOnConstructor": "Child - Composite" } ], "fillOnConstructor": "On Constructor Too" }
Conclusão
Bom, chegamos ao fim!
Esse é um hello world ASP.NET Core com o Oragon Spring, fork do Spring .NET portado para .NET Standard.
Limitações: Container são tipos especiais do qual não podem ser configurados no spring. O pipeline do .NET Core complica muito a gestão de dependência das outras dependências ao redor dos Controllers, portanto conseguimos resulta dependências dos controllers, mas não os controllers em si.
Outro ponto é que como o resultado do Extension Method ser um IServiceProvider, ele já dá a pista de que consegue rodar em modo console, integrado ao ASP.NET Core. Mas pode trabalhar isolado e independente, é uma questão de gosto. Nos meus projetos eu sempre trabalho integrado para não perder características fundamentais, como os arquivos de configuração do projeto.
Exemplo no github
O projeto está no repositório do github https://github.com/Oragon/Oragon.Spring.GetStarted.
Fique de olho nos branches. O branch para esse post é esse aqui: https://github.com/Oragon/Oragon.Spring.GetStarted/tree/01-GetStarted
0 comentários