title: Implementing Custom Profile Provider in ASP.NET MVC
body: <p>I tried a lot on implementing a custom profile provider in ASP.NET MVC.
  I've read lots and lots of tutorials, but I can't find where my problem is. It's pretty similar to <a href="https://stackoverflow.com/questions/79129/implementing-profile-provider-in-asp-net-mvc">Implementing Profile Provider in ASP.NET MVC</a>.</p>
  
  <p>But I'd like to create my own Profile Provider, so I wrote the following class that inherits from <code>ProfileProvider</code>:</p>
  
  <pre><code>public class UserProfileProvider : ProfileProvider
  {
      #region Variables
      public override string ApplicationName { get; set; }
      public string ConnectionString { get; set; }
      public string UpdateProcedure { get; set; }
      public string GetProcedure { get; set; }
      #endregion
  
      #region Methods
      public UserProfileProvider()
      {  }
  
      internal static string GetConnectionString(string specifiedConnectionString)
      {
          if (String.IsNullOrEmpty(specifiedConnectionString))
              return null;
  
          // Check &lt;connectionStrings&gt; config section for this connection string
          ConnectionStringSettings connObj = ConfigurationManager.ConnectionStrings[specifiedConnectionString];
          if (connObj != null)
              return connObj.ConnectionString;
  
          return null;
      }
      #endregion
  
      #region ProfileProvider Methods Implementation
      public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
      {
          if (config == null)
              throw new ArgumentNullException("config");
  
          if (String.IsNullOrEmpty(name))
              name = "UserProfileProvider";
  
          if (String.IsNullOrEmpty(config["description"]))
          {
              config.Remove("description");
              config.Add("description", "My user custom profile provider");
          }
  
          base.Initialize(name, config);
  
          if (String.IsNullOrEmpty(config["connectionStringName"]))
              throw new ProviderException("connectionStringName not specified");
  
          ConnectionString = GetConnectionString(config["connectionStringName"]);
  
          if (String.IsNullOrEmpty(ConnectionString))
              throw new ProviderException("connectionStringName not specified");
  
  
          if ((config["applicationName"] == null) || String.IsNullOrEmpty(config["applicationName"]))
              ApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
          else
              ApplicationName = config["applicationName"];
  
          if (ApplicationName.Length &gt; 256)
              throw new ProviderException("Application name too long");
  
          UpdateProcedure = config["updateUserProcedure"];
          if (String.IsNullOrEmpty(UpdateProcedure))
              throw new ProviderException("updateUserProcedure not specified");
  
          GetProcedure = config["getUserProcedure"];
          if (String.IsNullOrEmpty(GetProcedure))
              throw new ProviderException("getUserProcedure not specified");
      }
  
      public override System.Configuration.SettingsPropertyValueCollection GetPropertyValues(System.Configuration.SettingsContext context, System.Configuration.SettingsPropertyCollection collection)
      {
          SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
  
          SqlConnection myConnection = new SqlConnection(ConnectionString);
          SqlCommand myCommand = new SqlCommand(GetProcedure, myConnection);
          myCommand.CommandType = CommandType.StoredProcedure;
  
          myCommand.Parameters.AddWithValue("@FirstName", (string)context["FirstName"]);
  
          try
          {
              myConnection.Open();
              SqlDataReader reader = myCommand.ExecuteReader(CommandBehavior.SingleRow);
  
              reader.Read();
  
              foreach (SettingsProperty property in collection)
              {
                  SettingsPropertyValue value = new SettingsPropertyValue(property);
  
                  if (reader.HasRows)
                  {
                      value.PropertyValue = reader[property.Name];
                      values.Add(value);
                  }
              }
  
          }
          finally
          {
              myConnection.Close();
              myCommand.Dispose();
          }
  
          return values;
      }
  
      public override void SetPropertyValues(System.Configuration.SettingsContext context, System.Configuration.SettingsPropertyValueCollection collection)
      {
          SqlConnection myConnection = new SqlConnection(ConnectionString);
          SqlCommand myCommand = new SqlCommand(UpdateProcedure, myConnection);
          myCommand.CommandType = CommandType.StoredProcedure;
  
          foreach (SettingsPropertyValue value in collection)
          {
              myCommand.Parameters.AddWithValue(value.Name, value.PropertyValue);
          }
  
          myCommand.Parameters.AddWithValue("@FirstName", (string)context["FirstName"]);
  
          try
          {
              myConnection.Open();
              myCommand.ExecuteNonQuery();
          }
  
          finally
          {
              myConnection.Close();
              myCommand.Dispose();
          }
      }
  </code></pre>
  
  <p>Here is my CreateProfile action in my Controller:</p>
  
  <pre><code>[AcceptVerbs(HttpVerbs.Post)]
  public ActionResult CreateProfile(string Username, string Password, string FirstName, string LastName)
  {
      MembershipCreateStatus IsCreated = MembershipCreateStatus.ProviderError;
      MembershipUser user = null;
  
      user = Membership.CreateUser(Username, Password, "test@test.com", "Q", "A", true, out IsCreated);
  
      if (IsCreated == MembershipCreateStatus.Success &amp;&amp; user != null)
      {
          ProfileCommon profile = (ProfileCommon)ProfileBase.Create(user.UserName);
  
          profile.FirstName = FirstName;
          profile.LastName = LastName;
          profile.Save();
      }
  
      return RedirectToAction("Index", "Home");
  }
  </code></pre>
  
  <p>My procedure usp_GetUserProcedure is nothing special:</p>
  
  <pre><code>ALTER PROCEDURE [dbo].[usp_GetUserProcedure] 
  -- Add the parameters for the stored procedure here
  @FirstName varchar(50)
  AS
  BEGIN
  -- SET NOCOUNT ON added to prevent extra result sets from
  -- interfering with SELECT statements.
  SET NOCOUNT ON;
  
  -- Insert statements for procedure here
  SELECT * FROM dbo.Users WHERE FirstName = @FirstName
  END
  </code></pre>
  
  <p>And my Web.Config file:</p>
  
  <pre><code>&lt;profile enabled="true"
           automaticSaveEnabled="false"
           defaultProvider="UserProfileProvider"
           inherits="Test.Models.ProfileCommon"&gt;
  &lt;providers&gt;
  &lt;clear/&gt;
  &lt;add name="UserProfileProvider"
           type="Test.Controllers.UserProfileProvider"
           connectionStringName="ApplicationServices"
           applicationName="UserProfileProvider"
           getUserProcedure="usp_GetUserProcedure"
           updateUserProcedure="usp_UpdateUserProcedure"/&gt;
  &lt;/providers&gt;
  &lt;/profile&gt;
  </code></pre>
  
  <p>But I always get this exception:</p>
  
  <blockquote>
    <p>Procedure or function 'usp_GetUserProcedure' expects parameter '@FirstName', which was not supplied.</p>
  </blockquote>
  
  <p>Any thoughts on what I might be doing wrong?</p>