Giter Site home page Giter Site logo

avanade / liquid-application-framework Goto Github PK

View Code? Open in Web Editor NEW
490.0 28.0 50.0 6.45 MB

Liquid Application Framework documentation, useful links and sample project

License: MIT License

C# 100.00%
dotnet-core api microservices architecture framework hexagonal-architecture multicloud dotnet abstraction-layer grpc restful-api azure aws gcp servicebus sqs rabbitmq cosmosdb mongodb entity-framework-core

liquid-application-framework's Introduction

Liquid Application Framework

GitHub issues GitHub GitHub Repo stars Contributor Covenant Ready Ava Maturity

This repository contains Liquid Application Framework full code, samples, templates and documentation.

New Major Version Warning
  • This is the new major version of Liquid Application Framework, launched on April/2021.
  • We've made significant breaking changes and a complete rearchitecture of our framework. So, this version isn't compatible and there is no easy conversion from the old one.
  • We decided to deprecate the old version and it will not receive any kind of updates, not even bug fixes. But, for historical purposes and to allow anyone relying on it to fork the code and maintain its own version of it, we'll keep the old repository public.

What is Liquid?

Liquid is a multi-cloud framework designed to accelerate the development of cloud-native microservices while avoiding coupling your code to specific cloud providers.

When writing Liquid applications, you stop worrying about the technology and focus on your business logic - Liquid abstracts most of the boilerplate and let you just write domain code that looks great and gets the job done.

Feature

  • Abstracts a number of services from cloud providers such as Azure, AWS and Google Cloud to enable you to write code that could run anywhere.
  • Brings a directed programming model that will save you time on thinking how to structure your application, allowing you to focus on writing business code.

Getting Started

To use Liquid, you create a new base ASP.Net Core application and then download and install the following nuget packages:

Liquid Application Framework Binaries Type Version
Liquid.Core mandatory Nuget (with prereleases)
Liquid.Domain desirable Nuget (with prereleases)
Liquid.Repository optional Nuget (with prereleases)
Liquid.Cache optional Nuget (with prereleases)
Liquid.Messaging optional Nuget (with prereleases)
Liquid.WebApi.Http optional Nuget (with prereleases)

And then choose the implementation cartridges you need to your project, for example:

Liquid Templates new

Now you can use Liquid Templates to get your microservice started faster!

To use it, just install the templates by running the following dotnet CLI command at the PowerShell prompt :

dotnet new --install Liquid.Templates

and run dotnet new command with the name and parameters of the following templates:

Name Description
liquidcrudsolution Liquid WebAPI CRUD Solution (Domain and WebAPI projects)
liquidwebapisolution Liquid WebAPI solution (Domain and WebAPI projects)
liquidcrudextsolution Liquid CRUD Extension solution (Domain and WebAPI projects)
liquidworkersolution Liquid WorkerService solution (Domain and WorkerService projects)
liquiddomainaddhandler Liquid mediator command handler
liquidcrudaddentity Liquid entity class, CRUD mediator handlers and CRUD controller
liquidcrudextaddentity Liquid CRUD Extension entity and controller classes
liquidwebapiaddentity Liquid entity class, mediator command handler and CRUD controller
liquidbcontextaddentity Liquid DbContext entity configuration class (for Entity Framework)
liquiddbcontextproject Liquid Repository project (EntityFramework DbContext configurations)
liquidwebapiproject Liquid WebAPI project
liquidworkerproject Liquid WorkerService project
liquiddomainproject Liquid Domain project (mediator command handler)

Sample:

To create an WebAPI solution with CRUD handlers, you must:

  • execute command :
dotnet new liquidcrudsolution --projectName "some root namespace" --entityName "some entity" --entityIdType "type of your unique ID"
  • open the folder where the command was executed, and open the project created in the IDE of your choice:

template_sample

  • follow the instructions found in the generated code TODOs, and run!

You can make changes in code, add more classes and project if you need, and also using others Liquid templates to do it!

Contribute

Some of the best ways to contribute are to try things out, file issues, and make pull-requests.

  • You can provide feedback by filing issues on GitHub or open a discussion in Discussions tab. We accept issues, ideas and questions.
  • You can contribute by creating pull requests for the issues that are listed. Look for issues marked as ready if you are new to the project.
  • Avanade asks that all commits sign the Developer Certificate of Origin.

In any case, be sure to take a look at the contributing guide before starting, and see our security disclosure policy.

Useful Links

Liquid Application Framework Old Repositories
Liquid.Core
Liquid.Domain
Liquid.Repository
Liquid.Cache
Liquid.Messaging
Liquid.Services
Liquid.WebApi
Liquid.Serverless
Liquid.Tests

Who is Avanade?

Avanade is the leading provider of innovative digital, cloud and advisory services, industry solutions and design-led experiences across the Microsoft ecosystem.

liquid-application-framework's People

Contributors

aledaccas avatar alexandrenetit avatar andreracz avatar barbosa-renan avatar dependabot[bot] avatar dervanil avatar dervanil-junior avatar felipementel avatar fructuoso avatar lucianareginalino avatar marcoshidalgonunes-avanade avatar matheus-sabino-avanade avatar matheusdsb avatar rodrigogfreire avatar sealjay avatar snyk-bot avatar tayaracaires avatar ycamargo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

liquid-application-framework's Issues

Remove the need for creating the mandatory constructor overload

During the presentation stream on YouTube, one of the team members was introducing a sample made with Liquid. At some point (around 59m15s), he also needed to demonstrate how things are done at the HTTP layer of the application, which uses ASP.NET Core. The first thing he stumbles upon is the need of some very specific constructor parameters for a very specific constructor overload — a requirement enforced by the language and the runtime for inheritance to work yadda yadda yadda. He does what probably anyone would do at presentations/teaching lessons: just kind of skips it (aka "don't worry about it for now") because it's not relevant for the context.
The aforementioned expression "don't worry about it for now" is being taken seriously by Microsoft's C# and ASP.NET Core engineering team. They acknowledged it as a problem and are actively working on solutions to improve these sort of initial barriers for newcomers, such as the removal of the main method. Lately, we can also see David Fowler (an Architect of the ASP.NET Core team) working on similar efforts to ease things out for the framework.

That being said, I think we're facing the same issue here: there's an overwhelming amount of information for beginners to create Controllers.

What if we take the same path as the Microsoft engineering team? Let's make things easier by removing this cognitive complexity-like thing from the code.
My proposal is to make this:

using Liquid.Core.Context;
using Liquid.Core.Localization;
using Liquid.Core.Telemetry;
using Liquid.WebApi.Http.Controllers;
using MyProject.Domain.Queries;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

[ApiController]
[Route("/api/[controller]")]
public class MyController : BaseController
{
    public MyController(ILoggerFactory loggerFactory,
                        IMediator mediator,
                        ILightContext context,
                        ILightTelemetry telemetry,
                        ILocalization localization)
        : base(loggerFactory,
                  mediator,
                  context,
                  telemetry,
                  localization)
        { }

    [HttpGet()]
    public async Task<IActionResult> SearchMovies([FromQuery(Name="nameSearch")] string nameSearch) =>
        await ExecuteAsync(new ListMoviesQuery() { SearchString = nameSearch });
}

turn into this:

using Liquid.WebApi.Http.Controllers;
using MyProject.Domain.Queries;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

[ApiController]
[Route("/api/[controller]")]
public class MyController : BaseController
{
    [HttpGet()]
    public async Task<IActionResult> SearchMovies([FromQuery(Name="nameSearch")] string nameSearch) =>
        await ExecuteAsync(new ListMoviesQuery() { SearchString = nameSearch });
}

ASP.NET Core is an extraordinary well built and modular framework, and this can be easily achieved by either decorating its ControllerFactory/ControllerActivator or simply by annotating the BaseController properties with the [FromServices] attribute.

The tradeoff here is that some things would become implicit (for good) and the properties from the BaseController class would need to have public setters, as they are going to be filled dynamically. We're also trading compile time for run-time, but, of course, people wouldn't need to worry about creating constructors, so less of "why do we need to put this thing here?".

Configuração do Liquid.Services

Olá pessoal!

Antes de mais nada, parabéns pelo trabalho. Este framework foi uma excelente iniciativa de vocês!

Estou criando um projeto conceito com a utilização do Liquid ( https://github.com/Passarimm/LiquidPOC ). O objetivo é implementar tudo o que o framework oferece da melhor forma possível (imagino que eu ainda esteja um pouco longe disso, mas chego lá... rsrs). Qualquer ajuda será bem vinda.

Agora queria tirar uma dúvida....

Estou com problemas para configurar o Liquid.Services.

O exemplo da página https://github.com/Avanade/Liquid.Services está correto? Parece que houve uma alteração do parâmetro do tipo ILightConfiguration para ILightServiceConfiguration. Qual a configuração necessária para injetar essas dependências corretamente?

Liquid.Messaging Consumers handlers are initialized in the constructor

Consumers should implement an IHostedService, so that the application builder would handle the start of the messagehandlers.
This way it also makes it possible to create the Consumer host separate from the WebApi, preventing them from competing for the resources of the can and allowing them to be scaled separately.

Allow multiple configuration sources

Currently Liquid only allows configuration from the appsettings.json file. It should allow multiple sources (multiple files, environment variables, key vault, and others, using standard .net core configuration providers)

Simplify messaging consumer development

As is, to implement a consumer, is necessary to implement base "Consumer", as exemplified below:

 public class ServiceBusTestConsumer : ServiceBusConsumer<ServiceBusTestMessage>
    {
        public ServiceBusTestConsumer(IServiceProvider serviceProvider, 
                                      IMediator mediator, 
                                      IMapper mapper, 
                                      ILightContextFactory contextFactory, 
                                      ILightTelemetryFactory telemetryFactory, 
                                      ILoggerFactory loggerFactory, 
                                      ILightMessagingConfiguration<ServiceBusSettings> messagingConfiguration, 
                                      ServiceBusConsumerParameter serviceBusConsumerParameter) : base(serviceProvider, mediator, mapper, contextFactory, telemetryFactory, loggerFactory, messagingConfiguration, serviceBusConsumerParameter)
        {
        }


        /// <inheritdoc/>
        public override async Task<bool> ConsumeAsync(ServiceBusTestMessage message, IDictionary<string, object> headers, CancellationToken cancellationToken)
        {
           //Some bussiness code
        }
    }

The proposal is implement using Mediator, like this :

public class ServiceBusTestConsumer : ServiceBusConsumer<ServiceBusTestMessage>
{
public async Task<TResult> Execute() =>  await ExecuteAsync(new MySampleQuery());
}

Some extension classes are violating SRP

Allow extension on WebApi error return message

Today, Liquid Http WebApi only sends the error message to the client, using the following code:

return StatusCode(ex.ResponseCode.Value, new { messages = Localization.Get(ex.Message) });

In some cases, clients might want to enhance the returning object to include other information such as module name, a custom ID or other relevant information and this is currently not possible.

The idea is to create a method in the BaseController that can be expanded, such as:

   protected dynamic GetExceptionReturn(LightException ex) {
       return new { messages = Localization.Get(ex.Message) };
   }

Users can then override the method to include additional information.

Simplify Liquid Configuration implementation and injection

Today, to create and inject a configuration section using Liquid.Core.Configuration, it's necessary implement 2 classes as exemplified below:

public class MyCustomSetting
{
    public bool Prop1 { get; set; }
    public string Prop2 { get; set; }
}
[LiquidConfigurationSection("customSettings")]
public class MyCustomSettingConfiguration : LightConfiguration, ILightConfiguration<MyCustomSetting>
{
    //DotNet Configuration dependency injection
    public MyCustomSettingConfiguration(IConfiguration configuration) : base(configuration)
    { }

    // Get configuration section from Liquid configuration provider
    public CustomSetting Settings => GetConfigurationSection<CustomSetting>();
}

By the way, the current implementation of LightConfiguration makes it impossible to use IOptions.

Liquid.Messaging Producer samples may use mediator pattern

Liquid Messaging could use the mediator's notification pattern instead of using ILightProducer directly.

as-is:

var message = new MySampleMessage(config);                       
 await _producer.SendMessageAsync(message, new Dictionary<string, object> { { "headerTest", "value" } });

to-be:

var message = new MySampleMessage(config);
MediatorService.Publish(new Notification(message, new Dictionary<string, object> { { "headerTest", "value" } }));

Therefore, we do not suggest the creation of a dependency between an api handdler and the producer.

Review functional and unit test

Some Liquid components have unit tests and other functional tests.
My proposal is to separate the test projects into 2, so that every component or cartridge has a functional test project and a unit test project.
I also suggest that functional tests are not performed on the CD.

[Message] - Problem to send message using Azure Service Bus

I was forced to information Dictionary parameter (customHeaders) when I was using method SendMessageAsync

await _lightProducer.SendMessageAsync(
                message: new MovieAudience { Id = result.ImdbId, MovieName = result.Title },
                customHeaders: new Dictionary<string, object>());   < --------- THIS

RemoveAsync by Id

In the current implementation of Liquid.Repository, it’s necessary call function FindById then call function RemoveAsync.
Could we implement a function to remove by Id? Because it would simplify the implementation.

ServiceBus Consumer and Producer implementation gives no option for Queue

To register a ServiceBusConsumer or a ServiceBus Producer, today Liquid.Messaging just gives this options :

Consumer - just a topic subscription

services.AddServiceBusConsumer<ServiceBusTestConsumer, ServiceBusTestMessage>("TestAzureServiceBus", "TestMessageTopic", "TestMessageSubscription");

Producer DI - It is not explicit whether it is a queue or a topic

services.AddServiceBusProducer<ServiceBusTestMessage>("TestAzureServiceBus", "TestMessageTopic", true);

Producer Implementation - but the client instance is a Topic by default.

  private void InitializeClient()
        {
            _client = new TopicClient(_messagingSettings.ConnectionString, _serviceBusProducerParameter.Topic);
        }

My proposal is :

For the consumer and producer solution, build a ClientFactory interface, and implement a TopicClientFactory and a QueueClientFactory. Both of Base class should be changed to include an "IClientFactory" in their dependency.

To the Consumer, the ServiceCollection extension methods would be like this:

//to consume a Topic
services.AddServiceBusConsumer<ServiceBusTestConsumer, ServiceBusTestMessage>("TestAzureServiceBus", "TestMessageTopic", "TestMessageSubscription");

// to consume a Queue
services.AddServiceBusConsumer<ServiceBusTestConsumer, ServiceBusTestMessage>("TestAzureServiceBus", "TestMessageQueue");

To the Poducer, the ServiceCollection extension methods would be like this:

//to send messages to a topic
services.AddServiceBusTopicProducer<ServiceBusTestMessage>("TestAzureServiceBus", "TestMessageTopic", true);

//to send messages to a queue
services.AddServiceBusQueueProducer<ServiceBusTestMessage>("TestAzureServiceBus", "TestMessageTopic", true);

So the injection methods abstract the choice of QueueClient or TopicClient.

Simplify Liquid.WebApi.Http dependency injection

For inject all dependencies needed to use Liquid.WebApi.Http, is necessary call four methods as exemplified below:

 //Liquid WebApi Injection
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddAutoMapper(typeof(MySampleQuery).Assembly);
            services.ConfigureLiquidHttp();
            services.AddDomainRequestHandlers(GetType().Assembly);

In order to keep the Liquid an intuitive framework, the injection of the components should be more intuitive to.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.