Adding action id to a history repository In my system I have a history repository.
My history class is big and with a lot of information regarding operations.
My warehouse needs, for some actions to know which histories are caused by the same action.

My first idea was to create an overloaded version of each method requiring to write histories and make all the clients using that services create and supply a guid if they want to specify an action.

As my system has a lot of services that some use other services and a lot of clients that may need to specify an action that solution sounds bad. Complicated, error prone and would pollute code that is not interested in knowing anything about this.

My solution:
I created a ActionIdContext class that my clients can use to specify a group action and then my HistoryBuilder uses a static property to get the current ActionId if any. This way no services or overloads have to be created or changed.

Do you like this design or maybe you have another idea?



public class ActionIdContext : IDisposable
{
    private static Guid? actionId;
    private readonly bool isActionIdSet;

    public ActionIdContext()
    {
        if (actionId == null)
        {
            actionId = Guid.NewGuid();
            isActionIdSet = true;
        }
    }

    public static Guid? ActionId
    {
        get { return actionId; }
        set { actionId = value; }
    }

    public void Dispose()
    {
        if (isActionIdSet)
        {
            actionId = null;
        }
    }
}

public class HistoryBuilder
{
    private string text;

    public HistoryBuilder SetText(string value)
    {
        this.text = value;
        return this;
    }

    public History Build()
    {
        return new History()
        {
            Text = text,
            ActionId = ActionIdContext.ActionId
        };
    }
}

public class Client
{
    private readonly ISomeService someService;

    public Client(ISomeService someService)
    {
        this.someService = someService;
    }

    public void DoSomeAction()
    {
        someService.DoSomething("Flying in the sky");
    }

    public void DoSomeGroupAction()
    {
        using (new ActionIdContext())
        {
            someService.DoSomething("Driving in the corner");
            someService.DoSomething("Reading Hulk!");
            someService.DoSomething("Doing math");
        }
    }
}
The problem is that the action id is static so it will be shared with all instances of the ActionIdContext class. That means that 2 separate pieces of work excuting at the same time could log everything with the same action id.

var client1 = new Client(someService);
var client2 = new Client(someService);
var client3 = new Client(someService);

Task.Run(() =&gt; client1.DoSomeGroupAction());
Task.Run(() =&gt; client2.DoSomeGroupAction());
Task.Run(() =&gt; client3.DoSomeGroupAction());


You have no idea how this code will log the actions - it could log them all with the same action id, it could log some with no action id and some with a common action id. It could also log some with one action id and others with another. 

The point I'm trying to make is, although a nice idea in theory, you can't locally instantiate state then share it via a static property and expect it to work.

Can't you add a LogHistories(Guid actionId, param History[] histories) method or something?



You should implement the full IDisposable.Dispose pattern;



public static Guid? ActionId
{
    get { return actionId; }
    set { actionId = value; }
}


would be better as an auto property.



HistoryBuilder is a bit weird - Builders are generally used with immutables or objects with very complex constructors (in my experience).