Git Product home page Git Product logo

dynamic-decorator's People

Contributors

aoancea avatar

Watchers

 avatar  avatar

Forkers

mariancristian

dynamic-decorator's Issues

feature: define tracing - log inputs and outputs

This decorator is going to support the logging of inputs and outputs of every method from a class, thus, I define the following interface and its implementation:

public interface IFoo
{
    string Bar(string text);
}

public class Foo : IFoo
{
    public string Bar(string text)
    {
        return text;
    }
}

Given the above interface, I define the following decorator

public class Foo_IO_Decorator : IFoo
{
    private readonly IFoo decorated;

    public Foo_IO_Decorator(IFoo decorated)
    {
        this.decorated = decorated;
    }

    public string Bar(string text)
    {
        // TODO: provide a mechanics to log the input
        string result = decorated.Bar(text);
        // TODO: provide a mechanics to log the output

        return result;
    }
}

Note: For methods which don't accept any parameters or return void, input and respectively output logging will be NOT be performed.

feat(ambient-transaction): proposal description

Below I will describe the Ambient Transaction proposal. Example code can be found here.

I would name this Decorator with Ambient Transaction Pattern

What

Why

  • Unit of Work with Repository Pattern requires the Unit of Work to handle the instantiation of all repositories or say the least attach the shared DbContext to all of them known as Property Injection
  • Each usage of Unit of Work ends up beginning with the creation of one and saving the changes when finished which leads to code duplication. I reference DRY
  • This never lets you see clearly the dependencies which your class has directly from .ctor
  • Usage of each repository is inferred from the Unit of Work which acts more like a Service Locator with specific service resolving properties. I reference Service Locator anti-pattern

How

Implications

  • Queries will become transactional
  • Transactional queries might run into deadlocks(this may be avoided with proper care)
  • This looks more like how WCF handles transactions but these are inProc ones
  • I'm not yet sure on the implications these will have when used together with async await but if there are any I'm sure it will definitely be awesome ๐Ÿ’ฃ

Pending investigations

  • Looking at the actual queries that get run against the database using the SQL Profiler
  • Load and performance testing on high loads. Compare results with Unit of Work with Repository Pattern

Example

Given we have two repositories which are going to be called to insert a record each from a service. This need to run in a transaction because if either of the repository call fails, the operation need to account for neither.

I will outline below the two cases.

Common code:

public interface ISquareRepository
{
    void Upsert(Square square);
}

public interface IRectangleRepository
{
    void Upsert(Rectangle square);
}

public interface ITransactionService
{
    void InsertSquareAndRectangle(Square square, Rectangle rectangle);
}

Unit of Work with Repository Pattern

public class UnitOfWorkTransactionService : ITransactionService
{
    private readonly IUnitOfWorkFactory unitOfWorkFactory;

    public UnitOfWorkTransactionService(IUnitOfWorkFactory unitOfWorkFactory)
    {
        this.unitOfWorkFactory = unitOfWorkFactory;
    }

    public void InsertSquareAndRectangle(Square square, Rectangle rectangle)
    {
        using(IUnitOfWork unitOfWork = unitOfWorkFactory.Create())
        {
            unitOfWork.SquareRepository.Upsert(new Square());

            unitOfWork.RectangleRepository.Upsert(new Rectangle());

            unitOfWork.SaveChanges();
        }
    }
}

Note: The repositories do not call .SaveChanges() on the DbContext, but it is the duty of the Unit of Work as seen in the example

Ambient Transaction

public class TransactionService : ITransactionService
{
    private readonly ISquareRepository squareRepository;
    private readonly IRectangleRepository rectangleRepository;

    public UnitOfWorkTransactionService(ISquareRepository squareRepository, IRectangleRepository rectangleRepository)
    {
        this.squareRepository = squareRepository;
        this.rectangleRepository = rectangleRepository;
    }

    public void InsertSquareAndRectangle(Square square, Rectangle rectangle)
    {
        squareRepository.Upsert(new Square());

        rectangleRepository.Upsert(new Rectangle());
    }
}

The TransactionService's InsertSquareAndRectangle will be wrapped in an Ambient Transaction as present below(Decorator pattern is applied)

public class AmbientTransactionService : ITransactionService
{
    private readonly ITransactionService transactionService;

    public UnitOfWorkTransactionService(ITransactionService transactionService)
    {
        this.transactionService = transactionService;
    }

    public void InsertSquareAndRectangle(Square square, Rectangle rectangle)
    {
        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted }))
        {
            transactionService.InsertSquareAndRectangle(square, rectangle);

            scope.Complete();
        }
    }
}

In contrast to Unit of Work with Repository Pattern where the repositories do not call .SaveChanges() on the DbContext, here, each repository is going to save its work. We know that when calling .SaveChanges() on the DbContext a transaction will always be created if there isn't one already present, you can't change that as it's standard EF flow. If there is one already created, it will be enlisted in it.

Hence both repository calls save their work inside a single transaction.

feature: define tracing - log time

This decorator is going to support the logging of time taken by a method from a class to execute, thus, I define the following interface and its implementation:

public interface IFoo
{
    string Bar(string text);
}

public class Foo : IFoo
{
    public string Bar(string text)
    {
        return text;
    }
}

Before I can talk about the decorator, a mechanism is needed to provide access to data, and more exactly to the elapsed time. For this I define the following interface:

public interface ILogger
{
    void Log(Stopwatch sw);
}

Given the above interfaces, I define the following decorator:

public class Foo_Time_Decorator : IFoo
{
    private readonly IFoo decorated;
    private readonly ILogger logger;

    public Foo_Time_Decorator(IFoo decorated, ILogger logger)
    {
        this.decorated = decorated;
        this.logger = logger;
    }

    public string Bar(string text)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        string result = decorated.Bar(text);

        sw.Stop();

        logger.Log(sw);

        return result;
    }
}

Usage example:

public class ConsoleLogger : ILogger
{
    public void Log(Stopwatch sw)
    {
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

class Program
{
    static void(string args)
    {
        IFoo foo = new Foo();
        ILogger logger = new ConsoleLogger();
        IFoo fooDecorator = new Foo_Time_Decorator(foo, logger);

        fooDecorator.Bar("some text");
    }
}

When running a console application, the ElapsedMilliseconds would be displayed in the console.

Note: The wiring of objects will be done using a DI container.

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.