views:

145

answers:

3

I'm still struggling a bit with OOP concepts and dependency injection so bear with me.

I have generated my Linq2Sql model with a User table and now I would like to be able to send a confirmation email to this user so I created a partial class file for my User object and I felt it was natural to add a SendConfirmationEmail() method to the User class. This method will use a MailService to send the actual email and I would like to use dependency injection to pass in the service so I created a constructor overload on the User object like this

public User(IMailService service) : this()
{
    _service = service;
}

The SendConfirmationEmail method would look like this

public void SendConfirmationEmail()
{
    _service.SendMail(params...);
}

I realize this is a kind of poor mans dependency injection and I hope to switch to a dependency injection framework later as I am getting more grips on this.

The problem for me is that I need to make a reference from my model dll to my service dll which does not seem right and because I am unsure of how nice my linq2sql generated entities plays with Dependency injection frameworks and OOP concepts (I think ninject looks most promising).

I was hoping someone with a bit more experience than me could tell I'm if I am going in the right direction with this. I know I can make it work but I would like to educate my self in doing it in the correct way in the same step.

+1  A: 

The problem with that approach is that much of the time the entity is going to come from the LINQ-to-SQL back-end, and so isn't going to use your constructor (LINQ-to-SQL creates objects in its own way; you cannot force LINQ-to-SQL to use your constructor) - so this would only be useful for the (few) objects you create yourself. Data-binding (etc) will also commonly use the parameterless constructor by default.

I wonder if this wouldn't work better as a utility method that accepts the service, or obtains the service itself via a factory / singleton.

Marc Gravell
My inspiration for doing it this way is that I feel that the SendConfirmationEmail method on the user object is the natural and correct way OOP wise, but I guess Linq2Sql does not support this approach very well. I could build a layer on top of the Linq2Sql entities, but this seems like overhead
TT
@TT: I am not sure its the responsibility of the user to send a confirmation. It's a confirmation of "some action", the confirmation is context sensitive to the "action". Something like this: RegisteredUsers.Add(User) also has: RegisteredUsers.SendConfirmation(User)
Cohen
+1  A: 

I think you're ok doing this, but you might want to do two additional things to protect yourself from future cross-layer dependency problems:

  1. Create an interface for your User object. You should do this because not doing so will mean that everything that consumes this business object will have to reference the LINQ dlls unnecessarily.
  2. Move your dependency injection from the constructor into a property. You do this because constructor injection tends to limit your ability to dynamically create your object. Doing this, though poses a problem, since you would have to implement a lot of null checking code for _service. You can fix this by creating an "empty" implementation of IMailService and make it the default value for _service.
Michael Meadows
+2  A: 

I personally would change some things in your architecture:

  • I don't think that SendConfirmationEmail should be a method on your User object. But should be a method on another object with the user as a parameter. (this also better seperates your Dal from the other logic.
  • Second in this method use something like this:

    Services.Get<IMailService>().SendMail(params ...);

You can implement Services as the folowin (just an example):

public class Services
{
    protected static Dictionary<Type, object> services = new Dictionary<Type, object>();

    private Services() 
    {
    }

    static Services()
    {
        // hard coded implementations...
        services.Add(typeof(IMailService), new DefaultMailServiceImplementation());
    }

    public static T Get<T>() where T : class
    {
        Type requestedType = typeof(T);
        return services[requestedType] as T;
    }
}

By using a "Services"-class (or call it what you like) you add an additional layer between the IOC-framework and your code which makes it easy to change IOC-frameworks. Just change the implementation in the Get method to use one. You can also use a hardcoded temporary solution (until you use an IOC-framework) in the static constructor (like I did in the above example).

Cohen