Search code examples
asp.netasp.net-web-apiasp.net-identityowinasp.net-identity-2

ASP.NET WebAPI Identity 2 - Error with GetOwinContext on user registration /Register method


I have a WebAPI 2.1 application and I am having a problem with User Registration. I placed a breakpoint on the first line of the Register method but it is not reached. Instead it fails in the area below:

    public ApplicationUserManager UserManager
    {
        get
        {
            var a = Request; // this is null !!
            return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

    [AllowAnonymous]
    [Route("Register")]
    [ValidateModel]
    public async Task<IHttpActionResult> Register(RegisterBindingModel model)
    {

        var user = new ApplicationUser() { // <<<<< Debug breakpoint here never reached
            Email = model.Email, 
            FirstName = model.FirstName, 
            LastName = model.LastName,
            OrganizationId = 1,
            OrganizationIds = "1",
            RoleId = (int)ERole.Student,
            SubjectId = 1,
            SubjectIds = "1",
            UserName = model.UserName
        };




System.ArgumentNullException was unhandled by user code
  HResult=-2147467261
  Message=Value cannot be null.
Parameter name: request
  Source=System.Web.Http.Owin
  ParamName=request
  StackTrace:
       at System.Net.Http.OwinHttpRequestMessageExtensions.GetOwinContext(HttpRequestMessage request)
       at WebRole.Controllers.AccountController.get_UserManager() in c:\G\abr\WebRole\Controllers\Web API - Data\AccountController.cs:line 50
       at WebRole.Controllers.AccountController.Dispose(Boolean disposing) in c:\G\ab\WebRole\Controllers\Web API - Data\AccountController.cs:line 376
       at System.Web.Http.ApiController.Dispose()
       at System.Web.Http.Cors.AttributeBasedPolicyProviderFactory.SelectAction(HttpRequestMessage request, IHttpRouteData routeData, HttpConfiguration config)
       at System.Web.Http.Cors.AttributeBasedPolicyProviderFactory.GetCorsPolicyProvider(HttpRequestMessage request)
  InnerException: 

If anyone could give me any advice on where I could look to help solve this problem I would much appreciate it.

In particular can some explain to me the flow of how a request is handled in this configuration. I find it pretty confusing and I would like to know how the WebAPI and Owin fit together. Not knowing this is making it me difficult for me to understand the problem.

Thanks.

For reference here is my WebAPI start up class:

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }

    public static string PublicClientId { get; private set; }

    // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {

        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

    }
}

Update 1 - question correct after Darin's comments. The problem is not in the constructor.

Update 2 - Dispose Method:

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            UserManager.Dispose();
        }

        base.Dispose(disposing);
    }

Update 3 - Added the /Register method to show where I have a breakpoint (that's never reached)


Solution

  • There is no check for a null _userManager in your dispose method but the backing field can still be null. Also you access the UserManager property instead of using the backing field directly. So every time _userManager is null and the AccountController gets disposed the UserManager will try to create a new OwinContext. And that will fail.

    Change your dispose method to:

    protected override void Dispose(bool disposing)
    {
        if (disposing && _userManager != null)
        {
            _userManager.Dispose();
            _userManager = null
        }
    
        base.Dispose(disposing);
    }