Mussammil
Mussammil

Reputation: 894

How do I inject dependency in owin startup class

In my web api application I implemented OAuth2. On GrantResourceOwnerCredentials of ApplicationOAuthProvider I am calling my custom membership service to login and get the token.The problem is I have to inject the membership service into ApplicationOAuthProvider in order to use the service but it didn't allow it due to owinStartup class which don't support the parameter constructor.How do I inject/use my membership service in GrantResourceOwnerCredentials method.

  public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
  {
      private readonly string _publicClientId;
      private readonly IMembershipService _membershipService;

      public ApplicationOAuthProvider(string publicClientId, 
           IMembershipService membershipService)
      {
        if (publicClientId == null)
        {
            throw new ArgumentNullException("publicClientId");
        }

        _publicClientId = publicClientId;
        this._membershipService = membershipService;
      }

      public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
      {
            AccountLogin LogCredentials = new AccountLogin();
            LogCredentials.UserName = context.UserName;
            LogCredentials.Password = context.Password;

            ProviderLoginResponse providerLoginResponse = 
                _membershipService.UserLogin(LogCredentials);
            if (providerLoginResponse.LoginStatus != "Y")
            {
                context.SetError("invalid_grant", "The user name or password 
                is incorrect.");
                return;
            }

            var claims = new List<Claim>()
            {
                    new Claim(ClaimTypes.Sid, Convert.ToString(1)),
                    new Claim(ClaimTypes.Name, providerLoginResponse.UserName),
                    new Claim(ClaimTypes.Email, providerLoginResponse.UserEmail)
            };

            ClaimsIdentity oAuthIdentity = new ClaimsIdentity(claims,
                    Startup.OAuthOptions.AuthenticationType);

            AuthenticationProperties properties = CreateProperties(context.UserName);

            AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);

            context.Validated(ticket);
      }
  }

My owin startup class :

 public partial class Startup
 {
    private readonly IMembershipService _membershipService;

    //This will cause a runtime error owin startup class only support parameterless constructor
    public Startup(IMembershipService membershipService)
    {
        this._membershipService = membershipService;
    }

    public void ConfigureAuth(IAppBuilder app)
    {
          OAuthOptions = new OAuthAuthorizationServerOptions
          {
            TokenEndpointPath = new PathString("/Token"),

            //Here passing the _membershipService to ApplicationOAuthProvider constructor
            Provider = new ApplicationOAuthProvider(PublicClientId,_membershipService ),

            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
          };
    }
 }

Upvotes: 3

Views: 5579

Answers (1)

Marcus H&#246;glund
Marcus H&#246;glund

Reputation: 16801

One solution is to store the dependecy resolver as a static variable in, for example, the Startup.cs class and then resolve the interface against that.

As you tagged this question with MVC I'm guessing you have the Global.asax file along with the Startup.cs class. The Global.asax will be executed before the Startup.cs and that we can use in this solution.

In this solution I use Unity as container but you could use what ever you like.

Declare the static variable in Startup.cs class

public partial class Startup
{
    public static UnityContainer IoC { get; set; }

    ...

Then in the WebApiConfig.Register() method, where the resolver is attached to the current HttpConfiguration, also set the variable in Startup.cs (Note that this will be called before the Startup.cs class)

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        var container = new UnityContainer();
        //register all your interfaces in the container
        container.RegisterType<IMembershipService, MembershipService>(new HierarchicalLifetimeManager());
        Startup.IoC = container;
        config.DependencyResolver = new UnityResolver(Startup.IoC);
    }
}

Then use it in your Startup.cs

public partial class Startup
 {
    public static UnityContainer IoC { get; set; }

    public void ConfigureAuth(IAppBuilder app)
    {
          OAuthOptions = new OAuthAuthorizationServerOptions
          {
            TokenEndpointPath = new PathString("/Token"),

            //Resolve the interface here
            Provider = new ApplicationOAuthProvider(PublicClientId, Startup.IoC.Resolve<IMembershipService>() ),

            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
          };
    }
 }

Upvotes: 8

Related Questions