Question

I created custom membership and custom role provider follow exact same this link:

for custom membership:

http://msdn.microsoft.com/en-us/library/6tc47t75(v=vs.100).aspx

more info:

http://msdn.microsoft.com/en-us/library/ms366730(v=vs.100).aspx

for custom role provider:

http://msdn.microsoft.com/en-us/library/317sza4k(v=vs.100).aspx

more info:

http://msdn.microsoft.com/en-us/library/tksy7hd7(v=vs.100).aspx

and i have a SimpleMembershipInitializer

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Threading;
using WebMatrix.WebData;
using TestProject.Web.Models;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace TestProject.Web.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
    {
        private static SimpleMembershipInitializer _initializer;
        private static object _initializerLock = new object();
        private static bool _isInitialized;

        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
        }

        private class SimpleMembershipInitializer
        {
            public SimpleMembershipInitializer()
            {
                Database.SetInitializer<UsersContext>(null);

                try
                {
                    using (var context = new UsersContext())
                    {
                        if (!context.Database.Exists())
                        {
                            ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                        }
                    }

                    WebSecurity.InitializeDatabaseConnection("TestProjectEntities", "Users", "UsrID","UsrLoginName", autoCreateTables: false);


                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
    }
}

and i wrote a web api for login:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
using WebMatrix.WebData;

using TestProject.Web.Models;
using TestProject.Web.Filters;

using System.Configuration;

namespace TestProject.Web.Controllers
{
    [Authorize]
    [InitializeSimpleMembership]
    public class APIAccountController : ApiController
    {
        [System.Web.Http.AcceptVerbs("GET", "POST")]
        [System.Web.Http.HttpGet]
        [System.Web.Http.HttpPost]
        [System.Web.Http.AllowAnonymous]
        [System.Web.Mvc.ValidateAntiForgeryToken]
        public string Login(string UserName, string Password, bool RememberMe)
        {
            if (WebSecurity.Login(UserName, Password, persistCookie: RememberMe))
            {
                return "OK";
            }

            return "Failed";
        }
    }
}

and my web.config is:

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <!--<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-TestProject.Web-20130430091159;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-TestProject.Web-20130430091159.mdf" providerName="System.Data.SqlClient" />-->
    <add name="TestProjectEntities" connectionString="Data Source=.;Initial Catalog=TestProject;Integrated Security=True" providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <appSettings>
    <add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="PreserveLoginUrl" value="true" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="enableSimpleMembership" value="false"/>
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
    <authentication mode="Forms">
      <forms protection="All" loginUrl="/" timeout="2880" requireSSL="false" slidingExpiration="true" cookieless="UseCookies">
        <credentials passwordFormat="SHA1" />
      </forms>
    </authentication>
    <authorization>
      <!--<deny users="?" lockAllAttributesExcept="AllowAnonymous"  />-->
      <allow users="*"/>
    </authorization>
    <machineKey validationKey="C50B3C89CB21F4F1422FF158A5B42D0E8DB8CB5CDA1742572A487D9401E3400267682B202B746511891C1BAF47F8D25C07F6C39A104696DB51F17C529AD3CABE"
      decryptionKey="8A9BE8FD67AF6979E7D20198CFEA50DD3D3799C77AF2B72F"
      validation="SHA1" />
    <membership defaultProvider="UsersMembershipProvider" userIsOnlineTimeWindow="15">
      <providers>
        <clear />
        <add
          name="UsersMembershipProvider"
          type="TestProject.Web.Utility.UsersMembershipProvider"
          connectionStringName="TestProjectEntities"
          applicationName="TestProject"
          enablePasswordRetrieval="true"
          enablePasswordReset="true"
          requiresQuestionAndAnswer="true"
          requiresUniqueEmail="true"
          passwordFormat="Hashed" />
      </providers>
    </membership>
    <roleManager defaultProvider="UsersRoleProvider"
      enabled="true"
      cacheRolesInCookie="true"
      cookieName=".ASPROLES"
      cookieTimeout="30"
      cookiePath="/"
      cookieRequireSSL="false"
      cookieSlidingExpiration="true"
      cookieProtection="All" >
      <providers>
        <clear />
        <add
          name="UsersRoleProvider"
          type="TestProject.Web.Utility.UsersRoleProvider"
          connectionStringName="TestProjectEntities"
          applicationName="TestProject"
          writeExceptionsToEventLog="false" />
      </providers>
    </roleManager>
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="System.Data.SqlServerCe.4.0" />
      </parameters>
    </defaultConnectionFactory>
    <!--<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>-->
  </entityFramework>
</configuration>

after run api with this link:

/api/APIAccount/Login/?UserName=test1&Password=123456&RememberMe=true

its give me error:

<Error>
    <Message>An error has occurred.</Message>
    <ExceptionMessage>
        To call this method, the "Membership.Provider" property must be an instance of "ExtendedMembershipProvider".
    </ExceptionMessage>
    <ExceptionType>System.InvalidOperationException</ExceptionType>
    <StackTrace>
        at WebMatrix.WebData.WebSecurity.VerifyProvider()
        at WebMatrix.WebData.WebSecurity.Login(String userName, String password, Boolean persistCookie)
        at TestProject.Web.Controllers.APIAccountController.Login(String UserName, String Password, Boolean RememberMe)
        in c:\Visual Studio 2012\Projects\TestProject\TestProject.Web\Controllers\APIAccountController.cs:line 30
        at lambda_method(Closure , Object , Object[] )
        at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters)
        at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)
        at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>b__4()
        at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
    </StackTrace>
</Error>

I check it and see that CustomRoleManager Initializer not run in Web API and when i use view and not web api, its ok.

What should i do?

I uploaded test project in http://filebin.net/k8cqbyltac and it made by VS 2012, C#, MVC4, .Net 4.5

plaese check this URL after run for seeing error:

/api/APIAccount/Login/?UserName=test1&Password=123456&RememberMe=true

Was it helpful?

Solution

After inspecting your source I found the culprit:

Your Membership class should inherit from ExtendedMembershipProvider instead of MembershipProvider.

The WebSecurity class works with this base-class instead of the MembershipProvider, if your class doesn't inherit from that class, it will get a null-reference and it correctly tells you that it doesn't have a reference to an object of the correct type.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top