O ASP.NET vNext usa o compilador Roslyn para compilar e carregar código C# antes de executá-lo. David Fowler demonstra como é possível se beneficiar da abordagem de injeção de dependências por design (DI-by-design) do KRuntime para injetar suporte para outras linguagens.
O KRuntime contém todos os elementos necessários para construir e executar uma aplicação ASP.NET vNext. Por questão de princípio, o runtime não reconhece um "tempo de design": a compilação e o carregamento ocorrem simultaneamente. Para isso, o KRuntime possui diferentes loaders(carregadores). Eles percorrem as dependências listadas no arquivo project.json e as constroem, juntamente com o código-fonte.
Por padrão, o loader de referências do projeto usa o RoslynProjectReferenceProvider que por sua vez retorna uma instância de RoslynProjectReference. Como o nome sugere, é usado o compilador Roslyn C# para compilar código C# e carregar os assemblies.
Entretanto, este comportamento pode ser sobrescrito e David Fowler nos mostra como fazer isto:
Suporte ao F# no ASP.NET vNext
Para visualizar este exemplo, consulte o projeto vNextLanguageSupport de David no github. Nele, o autor define uma implementação de IProjectReferenceProvider (FSharpProjectReferenceProvider). Esta implementação, por sua vez, retorna uma implementação customizada de IMetadataProjectReference (FSharpProjectReference).
O FSharpProjectReference faz a maior parte do trabalho. O seu método Emit realiza as seguintes operações:
- Percorre as referências do projeto;
- copia as referências para um diretório temporário;
- Compila o código-fonte, juntamente com as referências usando o compilador fsc;
- Remove os arquivos temporários.
Ambas as classes estão contidas no projeto FSharpSupport, para que possam ser compiladas e referenciadas com um assembly. Observe que, embora essa implementação ofereça suporte à linguagem F#, ela foi implementada utilizando C#.
David então usa estas classes em um projeto de exemplo em F#. Para isto, define o projectReferenceProviderType em seu arquivo project.json:
"language": { "name": "F#", "assembly": "FSharpSupport", "projectReferenceProviderType": "FSharpSupport.FSharpProjectReferenceProvider" },
E dessa forma o F# é agora suportado em sua aplicação ASP.NET vNext. A classe de inicialização (starup) é agora um tipo F# ao invés de uma classe C#.
Esse exemplo usa F#, mas é possível usar a mesma técnica para habilitar o suporte para qualquer outra linguagem compatível com o CLR. Desta forma, é necessário apenas prover a implementação de IMetadataProjectReference e de IProjectReferenceProvider.
Aleksander Heintz publicou alguns artigos explicando detalhadamente o exemplo de David Fowler:
- Como os carregadores de projetos funcionam (Nota do InfoQ: artigo um pouco desatualizado; por exemplo, não se usa mais o RoslynAssemblyLoader)
- Detalhes sobre o FSharpReferenceProvider
- Como usar a implementação apresentada em C# de FSharpReferenceProvider para carregar uma implementação F# (e então utilizá-la para carregar código fonte F#)
O exemplo não é simples, mas demonstra o poder de uma abordagem de injeção de dependência feita pelo KRuntime, que permite muita flexibilidade para adição de novos recursos. Como é explicado na estrutura do KRuntime, cada camada do runtime, incluindo Native Process, Host, Managed Entry Point e Application Host, é resolvida por meio de injeção de dependências (por exemplo, o KRuntime funciona em Linux e em Mac OS X usando o Mono).