Injecting Dependencies into Domain Model classes with Nhibernate (ASP.NET MVC + IOC)

谁都会走 提交于 2019-12-03 07:25:54
Miroslav Popovic

There are already similar questions here on SO:

Dependency injection with NHibernate objects

DI/IoC, NHibernate and help in getting them to work together

You'll need to use Interceptors. Take a look at Fabio Maulo's post for implementation:

http://nhforge.org/blogs/nhibernate/archive/2008/12/12/entities-behavior-injection.aspx

You need to remember how it was hashed. This is so that you can hash a string in the future to check and see if it's their password, comparing that with the hashed value. That means that you need to store an enum or some other field in your object that indicates the hashing mechanism that was used in your database.

Otherwise, if you change your default hashing implementation, all of your old hashed passwords are no longer good, and your users will be left scratching their heads as to why their passwords no longer work--and you'll end up an IHashingService interface that provides no flexibility (since the hashing implementation cannot be changed without adding weird rules like "use this hash for Administrators created before 2010-01-12"), existing for no real good reason.

To that end, I would add the appropriate field (an enum, a string returned by the IHashingService interface, something) and either have NHibernate instantiate the hashing service for me via an IUserType implementation, or I'd use a factory pattern where the concrete instances were provided to the factory by the IoC container. This would be combining Jarrett's method-level injection with a solution that allows re-hydrated objects to find their hashing implementations without being dependent on the IoC container.

Good luck!

Is there a reason that you can't pass the IHashingService in the constructor for the Administrator class? That's how I would resolve the dependency.

public class Administrator
{
    private readonly IHashingService _hashingService;

    public Administrator(IHashingService hashingService)
    {
        _hashingService = hashingService;
    }

    // <snip>

    public void SetPassword(string plainTextPassword)
    {
        this.HashedPassword = _hashingService.Hash(plainTextPassword);
    }
}

Edit #1

If pulling from a model, try using method-level injection.

public void SetPassword(string plainText, IHashingService hasher)
{
    if (hasher == null) throw new ArgumentNullException("hasher");
    this.HashedPassword = hasher.Hash(plainText);
}

Edit #2

Also, why not make it easy on yourself and just make an extension on string?

public static class ExtensionsOfString
{
    public static string Hash(this string s)
    {
        // hash with SHA256
        return hashedString;
    }
}

While I do realize that there's a "replaceable" code aspect of using dependency injection, this isn't exactly a big deal for this example. You don't really need a IPasswordEncryptionService the same way you'd need a, say, ICreditCardAuthorizationService. If, someday, you change your hashing algorithm from SHA256 to SHA512, you will now have invalidated every password in your database.

Either hash the password in an application façade (if you are using any) or supply the IHashingService implementation on every call to Administrator.SetPassword(..). I think it was called double dispatch?!

If you insist on DI-in-entity solution, I have done something like that with PostSharp AOP and PostSharp4Spring by declaring [Configurable] attribute on the entity, but the solution is for Spring.Net. You can look here for more info. Also, if you are configuring NHibernate from the DI container, you can fall in a recursion trying to DI an entity before the container has finished configuring. You need a simple static class with method to suppress DI on entity construction during container initialization. Cannot provide an example a the moment though :(

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!