Lucent Fox
Lucent Fox

Reputation: 1795

Creating Re-usable Components w/ Private Data/EF Store via Dependency Injection

I'm vexed by the best way to create a re-usable component that depends on some sort of persisted data store such as a database/entity framework.

For example say that I want to create a re-usable event logger that I just just import into my projects via nuget. I want it to store its data in the same database that the main application is using, but I don't want to make the logger dependent on the data context that the rest of my application is using; doing so would seemingly tie the component to that specific application. Instead I'm wondering if it should have it's own data context, or have another abstraction that deals with the data persistance...

I guess the question that I want to ask, is how do I program to a generic interface when working with entity framework when it defines a bunch of concrete things that kind of live in my main project....?

public class SqlEventLogger : IEventLogger
{
    private DataContext _ctx;
    private Repository<ExceptionLog> repo;

    public SqlEventLogger(DataContext ctx)
    {
        _ctx = ctx;
        repo = new Repository<ExceptionLog>(ctx);
    }

    public void Log(string message, Severity severity, Exception exception = null, string requestType = null, string user = null, string location = null, string data = null)
    {
        repo.Add(new ExceptionLog
        {
            CreatedDate = DateTime.UtcNow,
            Message = String.Format("{0} || {1}", message, exception.Message),
            Source = exception.Source,
            StackTrace = exception.StackTrace,
            TargetSite = exception.TargetSite.ToString(),
            RequestForm = data,
            Url = location,
            RequestType = requestType,
            CurrentUser = user
        });

        _ctx.SaveChanges();
    }

DataContext in this case is my code-first DbContext, and ExceptionLog is the entity.

Upvotes: 0

Views: 94

Answers (1)

Steven
Steven

Reputation: 172835

You should extract all code that is specific to persistance into its class with its own abstraction. This way you can have a logger class that only contains logger logic and can swap persistance implementations on a per-project basis.

In your example however, the SqlEventLogger class only contains persistance related logic. If this is the actual situation, there is no need to extract that persistance logic, since you'll end up with an empty logger implementation. So if this is your actual case, the IEventLogger is the only abstraction to deal with. Your reusable component should just contain that IEventLogger abstraction and perhaps one or multiple default implementations.

This is actually how most logging frameworks work. When using a default SQL logger in your framework, it is probably easier to use plain SQL or stored procedures and supply a SQL script with the package so users can create the needed tables and stored procedures to get the logging framework up and running in a matter of minutes.

And even when you use Entity Framework, that EF model is specific to your implementation and should be placed in your reusable library. So there is no need to inject it. Instead, users should supply the SQLEventLogger with the connection string. However, you still need supply users with SQL scripts. To make life easier, you might allow the SqlEventLogger to auto-create the the tables for the user (when using a specific configuration switch). This is something that the SqlLoggingProvider of CuttingEdge.Logging does as well.

Upvotes: 2

Related Questions