Setting the provider's connection string at run time

Discussion of open issues, suggestions and bugs regarding ADO.NET provider for PostgreSQL
JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Setting the provider's connection string at run time

Post by JORGEMAL » Fri 27 Apr 2012 21:34

I wonder if this is a question for your or an ASP.NET issue. Please let me know.
I need to change/set the connection string of the providers in the Membership and RoleManager section in the web.config at run time. I only have one provider in each section which are PgSqlMembershipProvider and PgSqlRoleProvider. I have tried getting the connection string using Membership.Provider but it does not appear, I can see all of the parameters (name, type, description, passwordFormat, enablePasswordRetrieval, etc) except the one for connection string. Is this task possible? Can a string connection be specified instead of a connection name?

Respectfully,
Jorge Maldonado

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Setting the provider's connection string at run time

Post by Shalex » Fri 04 May 2012 12:12

We recommend you to implement your own descendants of our PgSqlMembershipProvider and PgSqlRoleProvider classes (which are public) and add the functionality for setting connection string at runtime as it is described at http://forums.asp.net/t/997608.aspx/1/10 .

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Tue 08 May 2012 16:19

How do I inherit PgSqlMembershipProvider and PgSqlRoleProvider into my provider implementation?
I can inherit MembershipProvider and RoleProvider from the System.Web.Security namespace, but I cannot find PgSqlMembershipProvider and PgSqlRoleProvider.
Is this the approach you refer to ?

With respect,
Jorge Maldonado

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Setting the provider's connection string at run time

Post by Shalex » Wed 09 May 2012 12:34

You can find public Devart.Data.PostgreSql.Web.Providers.PgSqlMembershipProvider and Devart.Data.PostgreSql.Web.Providers.PgSqlRoleProvider classes in the Devart.Data.PostgreSql.Web.dll assembly.

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Wed 09 May 2012 23:34

I have seen that setting a membership provider connectionstring at run-time is not a common procedure, I have not found very much information about it; nevertheless, what you suggest is a good choice. Below is a brief description of what I am doing and I would like you to tell me if I am correct.

Devart's pgSqlMembershipProvider inherits from .NET MembershipProvider and implements its own methods being "Initialize" one of them, which is precisely the one I need to update (override and extend) in order to set the provider's connectionstring at run-time. Is this correct?

What is getting me a bit confused is the following line of code from the site you recommended me to get a solution, where "_sqlConnectionString" is a public field according to the MSDN documentation:

Membership.Provider.GetType().GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic)

Where do I get such a public field from? Is it a field that I need to implement?

I know this an ASP.NET issue and I apologize for asking help from you, but as I told you above, I have been looking around for information about this issue for some weeks without response and it is really important for me to get a solution as soon as possible, and because the Devart team are experts about this matter, I have felt free to ask for your suport.

Respectfully,
Jorge Maldonado

Pinturiccio
Devart Team
Posts: 2420
Joined: Wed 02 Nov 2011 09:44

Re: Setting the provider's connection string at run time

Post by Pinturiccio » Tue 15 May 2012 12:37

JORGEMAL wrote:Devart's pgSqlMembershipProvider inherits from .NET MembershipProvider and implements its own methods being "Initialize" one of them, which is precisely the one I need to update (override and extend) in order to set the provider's connectionstring at run-time. Is this correct?
Between pgSqlMembershipProvider and MembershipProvider there is DbMembershipProvider - it is our base class. The DbMembershipProvider class has the connectionString private property, so you could use the following code:

Code: Select all

// Set private property of Membership provider.
FieldInfo connectionStringField = GetType().BaseType.GetField("connectionString", BindingFlags.Instance | BindingFlags.NonPublic);
connectionStringField.SetValue(this, connectionString);
But our assemblies undergo obfuscation and the property name will be unknown when you use Reflection. However, we will introduce this property in the next release in the base classes PgSqlMembershipProvider and PgSqlRoleProvider with the protected access modifier and you will be able to get access to this field by inheriting PgSqlMembershipProvider or PgSqlRoleProvider classes via the code:

Code: Select all

base.connectionString

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Tue 15 May 2012 15:19

It is great news !!!

Does this mean that it will be possible to directly get/set the connection string for the providers just by inheriting PgSqlMembershipProvider and/or PgSqlRoleProvider classes?

I really appreciate your support and effort for making developer's lives easier (and happier).

Respectfully,
Jorge Maldonado

Pinturiccio
Devart Team
Posts: 2420
Joined: Wed 02 Nov 2011 09:44

Re: Setting the provider's connection string at run time

Post by Pinturiccio » Wed 16 May 2012 09:28

JORGEMAL wrote:Does this mean that it will be possible to directly get/set the connection string for the providers just by inheriting PgSqlMembershipProvider and/or PgSqlRoleProvider classes?
Yes, you've got it right.
We will post here when the corresponding build of dotConnect for PostgreSQL is available for download.

Pinturiccio
Devart Team
Posts: 2420
Joined: Wed 02 Nov 2011 09:44

Re: Setting the provider's connection string at run time

Post by Pinturiccio » Wed 23 May 2012 14:25

The new build of dotConnect for PostgreSQL 6.0 is available for download now!
It can be downloaded from http://www.devart.com/dotconnect/postgr ... nload.html (trial version) or from Registered Users' Area (for users with valid subscription only).
For more information, please refer to http://forums.devart.com/viewtopic.php?t=24182

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Thu 07 Jun 2012 16:47

I have been testing this new feature with some trouble. Here is what I do.
Firstly, I inherit the PgSqlMembershipProvider to my class and that way I am able to set the connectionString property you implemented. After that, I tried 2 approaches to create a user: Membership.CreateUser and base.CreateUser.

What I think is that I should use the base.CreateUser method because I see that the Membership.CreateUser still gets information about the connection string from the membership section in web.config. When I use the Membership.CreateUser method I get an error as follows (message and stack):

An exception occurred. Please contact your administrator.

at Devart.Common.Web.Providers.DbMembershipProvider.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object userId, MembershipCreateStatus& status)
at System.Web.Security.Membership.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, Object providerUserKey, MembershipCreateStatus& status)
at System.Web.Security.Membership.CreateUser(String username, String password, String email, String passwordQuestion, String passwordAnswer, Boolean isApproved, MembershipCreateStatus& status)
at Usuarios.Inserta(String& strMensaje, String strOrigen) in d:\Visual Studio 2010 Projects\ePYMES\App_Code\Usuarios.cs:line 114

So, I decided to use base.CreateUser and this is a sample of my code. No exception is thrown but I get a MembershipCreateStatus of InvalidPassword. If I use the base.CreateUser method, are the parameters in the web.config's membership section taken into account? Why do I get the InvalidPassword status and how can I get a Success status? Do I need to set additional properties? I see that most of them are read-only. I will very much appreciate your advice.

Code: Select all

public class Usuarios : PgSqlMembershipProvider
{
    // Here go the properties.

    public void Inserta(ref String strMensaje, String strOrigen)
    {
        MembershipCreateStatus Estatus;
        String strConn = "";
        Object objUserID = String.Empty;

        try
        {
            // I get a connection string name from web.config based on the user logged on.
            strConn = ConnStrings.ObtenerConnString_ePYMES();

            // I get the connection string parameters of the connection string name.
            strConn = System.Configuration.ConfigurationManager.ConnectionStrings[strConn].ToString();

            // I add the dababase name to the connection string. Our app connects to different databases with the same schema.
            strConn += ";Database=" + HttpContext.Current.Session["sesBaseDatos"];

            // I set the connectionString property of the PgSqlMembershipProvider.
            base.connectionString = strConn;

            // The user is created.
            base.CreateUser(this.NombreUsuario, this.ClaveAcceso, this.CorreoElectronico, this.PreguntaSecreta, this.Respuesta, true,objUserID, out Estatus);

            // Check for the status of the create user operation.
            switch (Estatus)
            {
                case MembershipCreateStatus.Success:
                    strMensaje += "SU CUENTA DE USUARIO SE HA CREADO SATISFACTORIAMENTE.";
                    break;
                case MembershipCreateStatus.DuplicateEmail:
                    strMensaje += "LA DIRECCION E CORREO ELECTRONICO QUE DESEA REGISTRAR ";
                    strMensaje += "YA EXISTE EN LA BASE DE DATOS. INTENTE CON OTRA DIFERENCTE.";
                    break;
                case MembershipCreateStatus.DuplicateUserName:
                    strMensaje += "EL NOMBRE DE USUARIO YA EXISTE EN NUESTRO SISTEMA, ";
                    strMensaje += "SELECCIONE OTRO E INTENTE NUEVAMENTE.";
                    break;
                case MembershipCreateStatus.InvalidAnswer:
                    strMensaje += "LA RESPUESTA A LA PREGUNTA SECRETA ES INVALIDA, ES POSIBLE ";
                    strMensaje += "QUE CONTENGA CARACETRES NO PERMITIDOS.";
                    break;
                case MembershipCreateStatus.InvalidEmail:
                    strMensaje += "LA DIRECCION DE CORREO ELECTRONICO ES INVALIDA, VERIFIQUE QUE ";
                    strMensaje += "SE HAYA ALIMENTADO EN EL FORMATO CORRECTO.";
                    break;
                case MembershipCreateStatus.InvalidPassword:
                    strMensaje += "LA CLAVE DE ACCESO ES INVALIDA. DEBE CONTENER POR LO MENOS ";
                    strMensaje += Convert.ToString(Membership.MinRequiredPasswordLength) + " CARACTERES.";
                    break;
                case MembershipCreateStatus.InvalidQuestion:
                    strMensaje += "LA PREGUNTA SECRETA ES INVALIDA, ES POSIBLE ";
                    strMensaje += "QUE CONTENGA CARACTERES NO PERMITIDOS.";
                    break;
                case MembershipCreateStatus.InvalidUserName:
                    strMensaje += "EL NOMBRE DE USUARIO ES INVALIDO, ";
                    strMensaje += "VERIFIQUE QUE LO HAYA ALIMENTADO CORRECTAMENTE. ";
                    break;
                case MembershipCreateStatus.DuplicateProviderUserKey:
                    strMensaje += "EL IDENTIFICADOR DE USUARIO YA EXISTE EN LA BASE DE DATOS, ";
                    strMensaje += "INTENTE SU REGISTRO CON OTRO NOMBRE DE USUARIO.";
                    break;
                case MembershipCreateStatus.InvalidProviderUserKey:
                    strMensaje += "EL IDENTIFICADOR DE USUARIO QUE SE HA GENERADO ES INVALIDO, ";
                    strMensaje += "INTENTE SU REGISTRO CON OTRO NOMBRE DE USUARIO. ";
                    break;
                case MembershipCreateStatus.UserRejected:
                    strMensaje += "NO FUE POSIBLE CREAR LA CUENTA DE USUARIO, ";
                    strMensaje += "INTENTE SU REGISTRO CON OTRO NOMBRE DE USUARIO.";
                    break;
                case MembershipCreateStatus.ProviderError:
                    strMensaje += "HA OCURRIDO UN ERROR DESCONOCIDO, ";
                    strMensaje += "INTENTE SU REGISTRO CON OTRO NOMBRE DE USUARIO.";
                    break;
            }
        }
        catch (Exception error)
        {
            strMensaje += error.StackTrace;
        }
    }
}

Pinturiccio
Devart Team
Posts: 2420
Joined: Wed 02 Nov 2011 09:44

Re: Setting the provider's connection string at run time

Post by Pinturiccio » Mon 11 Jun 2012 13:34

JORGEMAL wrote:What I think is that I should use the base.CreateUser method because I see that the Membership.CreateUser still gets information about the connection string from the membership section in web.config. When I use the Membership.CreateUser method I get an error as follows (message and stack):
We could not reproduce the issue. In our environment the Membership.Create method works correctly. I will give an example below. Please, execute it and inform us whether it works:

web.config:

Code: Select all

<configuration>
  <connectionStrings>
    <add name="ApplicationServices"
         connectionString="hi"
         providerName="Devart.Data.PostgreSql" />
  </connectionStrings>
...
    <membership defaultProvider="Prov">
      <providers>
        <remove name="Prov" />
        <clear/>
        <add name="Prov" type="PgSqlMembershipProviderInherit.Prov"
             connectionStringName="ApplicationServices"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="false"
             requiresUniqueEmail="false"
             maxInvalidPasswordAttempts="5"
             minRequiredPasswordLength="6"
             minRequiredNonalphanumericCharacters="0"
             passwordAttemptWindow="10"
             applicationName="/" />
      </providers>
    </membership>
Default.aspx.cs:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Devart.Data.PostgreSql.Web.Providers;
using System.Web.Security;

namespace PgSqlMembershipProviderInherit
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Membership.CreateUser("scott2", "tigerSmart_83Proff");
        }
    }

    public class Prov : PgSqlMembershipProvider
    {
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            base.Initialize(name, config);
            base.connectionString = "host=your host;port=your port;user id=***;password=***;schema=test;";
        }
    }
}
You should also run the InstallWebTables.sql script on the database you want to use. The script can be found in the \Program Files\Devart\dotConnect\Oracle\ folder.

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Mon 11 Jun 2012 21:14

It worked, I was taking a wrong approach.
I need to do the same with the roles but I have not been able to succeed. I see that my problem is with the web.config in the provider's section of the roleManager definition; the "type" parameter of the provider´s name is a bit different than that in the membership section. Would you give me an idea of how to solve it?

With respect,
Jorge Maldonado

Pinturiccio
Devart Team
Posts: 2420
Joined: Wed 02 Nov 2011 09:44

Re: Setting the provider's connection string at run time

Post by Pinturiccio » Thu 14 Jun 2012 12:09

Working with a class inheriting from the PgSqlRoleProvider class is just the same as with a class inheriting from the PgSqlMembershipProvider class. It is necessary to make some changes.

web.config:

Code: Select all

<configuration>
  <connectionStrings>
    <add name="ApplicationServices"
         connectionString="hi"
         providerName="Devart.Data.PostgreSql" />
  </connectionStrings>
...
    <roleManager defaultProvider="Role" enabled="true">
      <providers>
        <clear/>
        <remove name="Role" />
        <add name="Role" type="PgSqlMembershipProviderInherit.Role" connectionStringName="ApplicationServices" />
      </providers>
    </roleManager>
Default.aspx.cs:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Devart.Data.PostgreSql.Web.Providers;
using System.Web.Security;

namespace PgSqlMembershipProviderInherit
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Roles.CreateRole("Master");
        }
    }

    public class Role : PgSqlRoleProvider
    {
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            base.Initialize(name, config);
            base.connectionString = "host=db;port=5439;user id=postgres;password=postgres;schema=test;";
        }
    }
}
For more information about how to configure ASP.NET providers, please, refer to
http://www.devart.com/dotconnect/postgr ... iders.html

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Fri 15 Jun 2012 16:57

I am getting an error message that I include below. I am not using a namespace, the "Grupos" class is defined directly in the App_Code folder. I am using the same approach with the membership provider and it works perfectly.

Configuration Error

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Object reference not set to an instance of an object.
Source Error:
Line 69: <providers>
Line 70: <clear/>
Line 71: <add name="AspNetPgSqlRoleProvider" type="Grupos" connectionStringName="eUsuarioConnString" description="dotConnect for PostgreSQL role provider" applicationName="/"/>
Line 72: </providers>
Line 73: </roleManager>

Source File: D:\Visual Studio 2010 Projects\ePYMES\web.config Line: 71

JORGEMAL
Posts: 171
Joined: Thu 03 Jul 2008 23:55

Re: Setting the provider's connection string at run time

Post by JORGEMAL » Thu 21 Jun 2012 00:37

Are there any news about this issue?

Regards,
Jorge Maldonado

Post Reply