1

How do I convert the following Ninject DI to the equivalent for LightInject DI? I'm having issues with getting to the right syntax.

Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());

kernel.Bind<UserAccountService>().ToSelf();
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>();
kernel.Bind<IUserAccountQuery>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();

On my original question, I didn't include this, but this (also posted as comment to this post) was the not working code I attempted to make it work:

Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());

container.Register<UserAccountService>();
container.Register<AuthenticationService, SamAuthenticationService>();
container.Register<IUserAccountQuery, DefaultUserAccountRepository>(new PerRequestLifeTime());
container.Register<IUserAccountRepository, DefaultUserAccountRepository>(new PerRequestLifeTime());

The error message (without the stack trace) given was this:

Exception Details: System.InvalidOperationException: Unresolved dependency [Target Type: BrockAllen.MembershipReboot.Ef.DefaultUserAccountRepository], [Parameter: ctx(BrockAllen.MembershipReboot.Ef.DefaultMembershipRebootDatabase)], [Requested dependency: ServiceType:BrockAllen.MembershipReboot.Ef.DefaultMembershipRebootDatabase, ServiceName:]

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

*If anyone wants to see the stack trace too - * just ask, and I'll post it in a reply to this question.

The constructor for DefaultMembershipRebootDatabase (as was in a sample project, my project used the dll provided through nuget, and the constructor wasn't available, but I'm pretty sure they're more than likely the same in both cases (seeing as how it comes from the same source...) is:

public class DefaultMembershipRebootDatabase : MembershipRebootDbContext<RelationalUserAccount>
{
    public DefaultMembershipRebootDatabase()
        : base()
    {
    }

    public DefaultMembershipRebootDatabase(string nameOrConnectionString)
        : base(nameOrConnectionString)
    {
    }

    public DefaultMembershipRebootDatabase(string nameOrConnectionString, string schemaName)
        : base(nameOrConnectionString, schemaName)
    {
    }
}

This is the constructor (as was in the same aforementioned sample project) for the DefaultUserAccountRepository:

public class DefaultUserAccountRepository
       : DbContextUserAccountRepository<DefaultMembershipRebootDatabase, RelationalUserAccount>, 
         IUserAccountRepository
{
    public DefaultUserAccountRepository(DefaultMembershipRebootDatabase ctx)
        : base(ctx)
    {
    }

    IUserAccountRepository<RelationalUserAccount> This { get { return (IUserAccountRepository<RelationalUserAccount>)this; } }

    public new UserAccount Create()
    {
        return This.Create();
    }

    public void Add(UserAccount item)
    {
        This.Add((RelationalUserAccount)item);
    }

    public void Remove(UserAccount item)
    {
        This.Remove((RelationalUserAccount)item);
    }

    public void Update(UserAccount item)
    {
        This.Update((RelationalUserAccount)item);
    }

    public new UserAccount GetByID(System.Guid id)
    {
        return This.GetByID(id);
    }

    public new UserAccount GetByUsername(string username)
    {
        return This.GetByUsername(username);
    }

    UserAccount IUserAccountRepository<UserAccount>.GetByUsername(string tenant, string username)
    {
        return This.GetByUsername(tenant, username);
    }

    public new UserAccount GetByEmail(string tenant, string email)
    {
        return This.GetByEmail(tenant, email);
    }

    public new UserAccount GetByMobilePhone(string tenant, string phone)
    {
        return This.GetByMobilePhone(tenant, phone);
    }

    public new UserAccount GetByVerificationKey(string key)
    {
        return This.GetByVerificationKey(key);
    }

    public new UserAccount GetByLinkedAccount(string tenant, string provider, string id)
    {
        return This.GetByLinkedAccount(tenant, provider, id);
    }

    public new UserAccount GetByCertificate(string tenant, string thumbprint)
    {
        return This.GetByCertificate(tenant, thumbprint);
    }
}

And this is the controller in my project:

namespace brockallen_MembershipReboot.Controllers
{
using System.ComponentModel.DataAnnotations;

using BrockAllen.MembershipReboot;
using BrockAllen.MembershipReboot.Mvc.Areas.UserAccount.Models;

public class UserAccountController : Controller
{
    UserAccountService _userAccountService;
    AuthenticationService _authService;

    public UserAccountController(AuthenticationService authService)
    {
        _userAccountService = authService.UserAccountService;
        _authService = authService;
    }

    // GET: /UserAccount/
    [Authorize]
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Login()
    {
        return View(new LoginInputModel());
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Login(LoginInputModel model)
    {
        if (ModelState.IsValid)
        {
            /*BrockAllen.MembershipReboot.*/UserAccount account;
            if (_userAccountService.AuthenticateWithUsernameOrEmail(model.Username, model.Password, out account))
            {
                _authService.SignIn(account, model.RememberMe);

                _authService.SignIn(account, model.RememberMe);

                /*if (account.RequiresTwoFactorAuthCodeToSignIn())
                {
                    return RedirectToAction("TwoFactorAuthCodeLogin");
                }
                if (account.RequiresTwoFactorCertificateToSignIn())
                {
                    return RedirectToAction("CertificateLogin");
                }

                if (_userAccountService.IsPasswordExpired(account))
                {
                    return RedirectToAction("Index", "ChangePassword");
                }*/

                if (Url.IsLocalUrl(model.ReturnUrl))
                {
                    return Redirect(model.ReturnUrl);
                }

                return RedirectToAction("Index");
            }
            else
            {
                ModelState.AddModelError("", "Invalid Username or Password");
            }
        }

        return View(model);
    }

    public ActionResult Register()
    {
        return View(new RegisterInputModel());
    }

    [ValidateAntiForgeryToken]
    [HttpPost]
    public ActionResult Register(RegisterInputModel model)
    {
        if (ModelState.IsValid)
        {
            try
            {
                var account = _userAccountService.CreateAccount(model.Username, model.Password, model.Email);
                ViewData["RequireAccountVerification"] = _userAccountService.Configuration.RequireAccountVerification;
                return View("Success", model);
            }
            catch (ValidationException ex)
            {
                ModelState.AddModelError("", ex.Message);
            }
        }
        return View(model);
    }
}
}

The constructor for AuthenicationService is:

public abstract class AuthenticationService : AuthenticationService<UserAccount>
{
    public new UserAccountService UserAccountService
    {
        get { return (UserAccountService)base.UserAccountService; }
        set { base.UserAccountService = value; }
    }

    public AuthenticationService(UserAccountService userService)
        : this(userService, null)
    {
    }

    public AuthenticationService(UserAccountService userService, ClaimsAuthenticationManager claimsAuthenticationManager)
        : base(userService, claimsAuthenticationManager)
    {
    }
}
AspCoder
  • 83
  • 8
  • container.Register(); container.Register(); container.Register(new PerRequestLifeTime()); container.Register(new PerRequestLifeTime()); – AspCoder Dec 24 '15 at 00:24
  • And that didn't work? What error are you getting? Can you please post the code in the question? – Yacoub Massad Dec 24 '15 at 01:12
  • What you are trying to resolve when you get the exception? – Yacoub Massad Dec 24 '15 at 10:28
  • What does the constructor of `DefaultMembershipRebootDatabase` look like? does it have a dependency on `DefaultUserAccountRepository` or `IUserAccountQuery` or `IUserAccountRepository`? – Yacoub Massad Dec 24 '15 at 11:38
  • What am I trying to resolve when I get the exception? My understanding of MVC is moderate, so overlook it if I'm answering wrong (and if I don't provide the answer you're looking for, please be a little bit more specific), I'm running the app in my browser, and I go to the route for the controller, and the controller is using the classes that're involved with what was set up with di (ninject - it worked with that setup, and lightinject - it doesn't work - with what I've tried so far) as I showed in the code above, and I get this error message I'm posting about. – AspCoder Dec 24 '15 at 16:35
  • Can you provide the constructor signatures for the following classes: `DefaultMembershipRebootDatabase`, `DefaultUserAccountRepository` and the controller class? – Yacoub Massad Dec 24 '15 at 16:40
  • As for the constructor for DefaultMembershipRebootDatabase - well, in the project I'm trying to make this setup work, I downloaded the nuget packages for MembershipReboot - and used it with it in a more normal way. In that setup, the constructor is inaccessible (I guess because I didn't create a custom constructor, and the default comes with the dll through nuget), but, there's also a sample project provided, and in that, there is a custom constructor (that probably is identical to the default one in my project), and I added it to my original question. – AspCoder Dec 24 '15 at 16:43
  • Ok, so as I was saying, I'll add that constructor, and the other constructor and controller code in just a minute – AspCoder Dec 24 '15 at 16:44
  • Try adding these lines: `container.Register(new PerRequestLifeTime());` and `container.Register(new PerRequestLifeTime());` – Yacoub Massad Dec 24 '15 at 16:51
  • As well as the constructor for DefaultMembershipRebootDatabase, I just added into my question the constuctor for DefaultUserAccountRepository and the controller class as you requested, and you can look and analyse that too. After writing this comment I will go and try to see what happens when I add your suggestions you just gave. – AspCoder Dec 24 '15 at 17:01
  • Also add this `container.Register();` – Yacoub Massad Dec 24 '15 at 17:05
  • Also, what does the constructor signature of `AuthenticationService` look like? – Yacoub Massad Dec 24 '15 at 17:05
  • Ok, I'm going to post the constructor from the sample project for AuthenticationService in just a moment, but I'm trying your suggestions right now. The first suggestion did nothing to improve the situation, I now added your second suggestion. Also, in your first suggestion, you said to add two lines - "container.Register(new PerRequestLifeTime());" - but the both of them were the exact same. Is this an error in stackoverflow? Or I'm unsure, but I really do appreciate your help though. – AspCoder Dec 24 '15 at 17:18
  • So, your first suggestion did nothing. But your second one (container.Register();) - did it! Thank you so much. If there is anything else unexpected, I will add to this post, but if not, I will provide a Answer post below referencing yourself and your suggestion and mark it as the answer. Even though, from as I see it right - all is well, and I'm pretty sure there won't be any further issues here, just in case, I'll also add the constructor for AuthenticationService as you requested into the original question. – AspCoder Dec 24 '15 at 17:32

2 Answers2

2

By default, LightInject does not resolve concrete classes without registering them, while NInject does.

For example, NInject can resolve DefaultMembershipRebootDatabase without registering it, while LightInject cannot by default. Take a look at this.

In any way, to fix your issue, make sure that you register your concrete classes (that are needed as dependencies in other classes). Here is an example:

container.Register<DefaultMembershipRebootDatabase>();

I am assuming here that some class has a dependency on the concrete class DefaultMembershipRebootDatabase. If you have other concrete class dependencies, make sure that you also register them.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
2

You should use the PerScopeLifetime rather than the PerRequestLifetime. PerRequestLifetime represents a transient lifetime that tracks disposable instances and disposes them when the scope ends. PerScopeLifetime ensures the same instance within a scope which in this case means the same instance within a web request.

seesharper
  • 3,249
  • 1
  • 19
  • 23