Skip to content

Latest commit

 

History

History
107 lines (82 loc) · 3.53 KB

quickstart2.md

File metadata and controls

107 lines (82 loc) · 3.53 KB

ComposerCore Sample - Quick Start scenario two

In this sample, the first quick start sample is extended to show how components can depend upon each other, and how ComposerCore detects and injects dependencies among them.

Complete source of this sample

When you ask ComposerCore to prepare a component for you, it will also inject any declared dependencies on the component to other components. Here's an example, where you have three contracts declared as below:

    [Contract]
    public interface IOrderLogic
    {
        void PlaceOrder(string customerName, int amount);
    }

    [Contract]
    public interface IOrderData
    {
        void SaveOrderData(string description);
    }

    [Contract]
    public interface ICustomerData
    {
        int GetCustomerId(string customerName);
    }

Each of the above contracts can have an implementation class (a class marked with [Component]). But each of the components will need help from other components to achieve the goal. For placing the order, DefaultOrderLogic will need to have a component that provides ICustomerData to lookup the customer id, and it will also need someone with IOrderData capabilities to store the new order. All of them will also need to log some data for later.

By placing [ComponentPlug] attribute on properties, each component can declare required contracts. It means that the component needs ComposerCore to provide them with an implementation of the contract before the component can function properly. Here's the code:

    [Component]
    public class DefaultOrderLogic : IOrderLogic
    {
        [ComponentPlug] public IOrderData OrderData { get; set; }
        [ComponentPlug] public ICustomerData CustomerData { get; set; }
        [ComponentPlug] public ILogger Logger { get; set; }

        public void PlaceOrder(string customerName, int amount)
        {
            Logger.Log($"Placing order for {customerName} with the amount = {amount}");

            var customerId = CustomerData.GetCustomerId(customerName);
            OrderData.SaveOrderData($"Order for customer {customerId}: {amount} items");

            Logger.Log("Done.");
        }
    }

    [Component]
    public class DefaultOrderData : IOrderData
    {
        [ComponentPlug] public ILogger Logger { get; set; }

        public void SaveOrderData(string description)
        {
            Logger.Log($"Saving order: {description}");    
        }
    }

    [Component] public class DefaultCustomerData : ICustomerData
    {
        [ComponentPlug] public ILogger Logger { get; set; }

        public int GetCustomerId(string customerName)
        {
            Logger.Log($"Looking up customer with name {customerName}...");
            return 5;
        }
    }

When registering these components, ComposerCore will identify these required contracts and build a graph. Upon querying, when ComposerCore instantiates the components, it will then compose them to each other and form a completely initialized component before returning it.

After registering all components:

    var composer = new ComponentContext();
    composer.Register(typeof(ConsoleLogger));
    composer.Register(typeof(DefaultCustomerData));
    composer.Register(typeof(DefaultOrderData));
    composer.Register(typeof(DefaultOrderLogic));

you can use the same GetComponent method to ask for an IOrderLogic component, and use it immediately, without worrying about dependencies.

    composer.GetComponent<IOrderLogic>().PlaceOrder("John", 17);