(ASP.NET) ASP NET (2010 год)

Избавляемся от базы стандартных пользователей ASP.NET на MS SQL - пример ASP.NET сайта на MySQL.

MS SQL является тяжелейшим обременителем технологии ASP.NET. Я многократно разъяснял причины этого - повторятся не будем, интересующихся отсылаю к страничкам - Используем MySQL вместо MS SQL в проектах на ASP.NET, Программирование в SQL SERVER, Осторожно Microsoft. Вероятно, наличие именно этого безумно дорогого продукта в пакете технологий ASP.NET и приводит к тому, что эта неплохая в целом технология занимает всего 0,4% рынка Web-технологий.

Поэтому очевидно, что все что может интересовать на практике ASP.NET-программистов - это снижение стоимости их законченных ASP.NET-сайтов для конечных потребителей. В первую очередь путем избавления от немыслимо дорогого MS SQL-сервера и от Windows конечно тоже. Тем более конкурирующие бесплатные продукты не хуже, а лучше билогейтсовских. Просто их бренды не настолько раскрученные и их не навязывают детям на уроках дэз-информатики в школе. Да и навязывать и раскручивать бесплатные продукты особо некому - не то что шестерки Билла Гейтса с чемоданами баксов, проталкивающие Windows.


Собственно же ASP.NET-программирование c СУБД MySQL не требует хитростей типа сохранения коннекта (как это требуется в PostgreSQL - Этюды на ASP.NET. Пример сайта на СУБД PostgreSQL) - техника ASP-NET программирования с MySQL ничем не отличается от техники программирования с MS SQL. Поэтому я сделал этот пример не просто примером сайта с MySQL - а примером ASP.NET-сайта с отказом от стандартных пользователей ASP.NET, обычно устанавливаемых в MS SQL.

Описанное здесь решение является сильно упрощенной реализацией моего популярного коммерческого решения для управления ASP.NET-пользователями, описанного здесь AspNet_UserManager - компонент сайта для управления пользователями. Здесь, как вы понимаете все правильно - для платного микрософтовского MS SQL Server у меня рапространяется платное управления ASP.NET-пользователями, а для бесплатного MySQL аналогичное по функционалу решение - полностью OpenSource. Кроме того, платное решение включает в себя мою фирменную и пока никем не взломанную капчу и представляет собой просто библитеку, которую надо положить в BIN-директорию проекта и просто оплатить, а описанный на этой страничке OpenSource-проект - это конструктор, из которого вы сами должны выделить в свой проект нужные вам фрагменты кода.

Еще один пример использования MySQL вместо MS SQL вы можете посмотреть у меня на страничке Как сделать SOAP/WSDL-вебсервис на ASP.NET/MONO для вызова его из FLEX.


Итак, если призадуматься, то использование стандартных ASP.NET-пользователей (устанавливаемых обычно мастером aspnet_regsql.exe) непонятно что приносит больше - пользы или вреда:


Итак, вы выполнили инсталяцию MySQL, установили коннектор к MySQL - как это описано на этой моей страничке Используем MySQL вместо MS SQL в проектах на ASP.NET. Скопировали MySql.Data.dll в папку BIN проекта и лучше даже прописали его в Mashine.config (это должен автоматически сделать инсталятор коннектора).

MySQL Connector Net состоит с точки зрения .NET-программиста из четырех компонентов:

Последняя сборка как раз и предназначена для тех, кто не хотел бы отказываться от стандартных пользователей в базах aspnet_users, aspnet_membership, считывания/записи пользователей из этих баз с помощью заведомо сделанной микрософтом обвязки Membership.GetUser/Membership.Save. А также сохранения/загрузки профиля ASP.NET пользователя с помощью встроенных микрософтовских классов UserProfile.GetProfile и UserProfile.Save.


Теперь посмотрим, как программистам, травмированным Microsoft Sql Server, создать юзера release для работы сайта, назначить ему нужные права, создать базу release и необходимую структуру данных в ней. Те, чей мозг не травмирован Microsoft SQL Server - могут этот раздел пропустить.

При инсталяции MySQL вы указывали пароль MySQL-юзера root и возможно ставили галку анонимного доступа к MySQL. Теперь (последовательно) приконнектитесь к вашему MySQL из под root, создайте себе базу для сайта, создайте юзера для работы сайта и поставьте ему доступ по чтению на базу MySQL и полный доступ на свою базу:

Далее необходимо переконнектится к серверу уже из-под вновь созданного юзера и начать создавать нужную структуру таблиц в базе:


Эту структуру (если она будет меняться в вашем проекте) вы можете в любой момент заскриптовать и сохранить в тектовом виде в своем SQL-проекте (см скрины ниже). Кроме того, при работе с MySQL под Windows важно правильно выставить во всех местах кодировку UTF-8 - иначе будет бесконечная чехарда с русскими буквами. В студии DevArt (если вы будете что-то править руками в таблицах и хотете там видеть русский текст, а не абракадабру) - это ставится в свойствах коннекта. А для работы сайта я просто добавляю в конфигурационном файле MySQL.ini команду SET NAMES utf8 (на скринах вы видите куда это вписывается). Кроме того, как вы видите на скринах - я сделал скриптик для рестарта MySQL и указал файл журнала для профилирования SQL-запросов (в журнале видно, как я из админки забанил какого-то юзера).

Для учета пользователей нашего сайта мы создадим следующую структуру таблиц и процедур:


   1:  -- Скрипт сгенерирован Devart dbForge Studio for MySQL, Версия 4.50.285.1
   2:  -- Дата: 19/07/2010 23:10:21
   3:  -- Версия сервера: 5.1.48-community
   4:  -- Версия клиента: 4.1
   5:   
   6:  USE release;
   7:   
   8:  CREATE TABLE release.aspnet_users(
   9:    i INT(12) NOT NULL AUTO_INCREMENT,
  10:    id VARCHAR(36),
  11:    Email VARCHAR(50) NOT NULL,
  12:    Pass VARCHAR(50) NOT NULL,
  13:    ActivateID VARCHAR(36) NOT NULL,
  14:    IsActivate TINYINT(1) DEFAULT NULL,
  15:    CrDate DATETIME NOT NULL,
  16:    UserName VARCHAR(50) NOT NULL,
  17:    Name1 VARCHAR(50) DEFAULT NULL,
  18:    Name2 VARCHAR(50) DEFAULT NULL,
  19:    IP VARCHAR(16) NOT NULL,
  20:    IsAdmin TINYINT(1) DEFAULT NULL,
  21:    IsBan TINYINT(1) DEFAULT NULL,
  22:    PRIMARY KEY (i, id),
  23:    UNIQUE INDEX ActivateID (ActivateID),
  24:    UNIQUE INDEX Email (Email)
  25:  )
  26:  ENGINE = INNODB
  27:  AUTO_INCREMENT = 28
  28:  AVG_ROW_LENGTH = 16384
  29:  CHARACTER SET utf8
  30:  COLLATE utf8_general_ci;
  31:   
  32:  CREATE TABLE release.sendmail(
  33:    i INT(12) NOT NULL AUTO_INCREMENT,
  34:    CrDate DATETIME NOT NULL,
  35:    ToAddr VARCHAR(250) NOT NULL,
  36:    MailSubject VARCHAR(500) NOT NULL,
  37:    Body VARCHAR(4000) DEFAULT NULL,
  38:    SendError TINYINT(1) DEFAULT NULL,
  39:    PRIMARY KEY (i)
  40:  )
  41:  ENGINE = INNODB
  42:  AUTO_INCREMENT = 18
  43:  CHARACTER SET utf8
  44:  COLLATE utf8_general_ci;
  45:   
  46:  DELIMITER $$
  47:   
  48:  CREATE DEFINER = 'release'@'%'
  49:  PROCEDURE release.AddMail(IN ToAddr VARCHAR(256), IN MailSubject VARCHAR(500), IN Body VARCHAR(4000))
  50:  BEGIN
  51:    START TRANSACTION;
  52:    INSERT
  53:      release.sendmail (CrDate, ToAddr, MailSubject, Body) VALUES (NOW(), ToAddr, MailSubject, Body);
  54:    SELECT
  55:      LAST_INSERT_ID() AS MailId;
  56:    COMMIT;
  57:  END
  58:  $$
  59:   
  60:  CREATE DEFINER = 'release'@'%'
  61:  PROCEDURE release.AddMailError(IN i1 INTEGER, IN SendError1 VARCHAR(1000))
  62:  BEGIN
  63:    UPDATE
  64:      release.sendmail
  65:    SET
  66:      SendError = SendError1
  67:    WHERE
  68:      i = i1;
  69:  END
  70:  $$
  71:   
  72:  CREATE DEFINER = 'release'@'%'
  73:  PROCEDURE release.ClearAllUserInfo(IN id1 VARCHAR(36))
  74:  BEGIN
  75:    DECLARE EXIT HANDLER FOR SQLEXCEPTION
  76:    BEGIN
  77:      SELECT
  78:        mysql_error() AS Error_message;
  79:    END;
  80:   
  81:    DELETE
  82:    FROM
  83:      release.aspnet_users
  84:    WHERE
  85:      id = id1;
  86:    SELECT
  87:      NULL AS Error_Number;
  88:  END
  89:  $$
  90:   
  91:  CREATE DEFINER = 'release'@'%'
  92:  PROCEDURE release.CreateUser(IN Email VARCHAR(50), IN Pass VARCHAR(50), IN UserName VARCHAR(50), IN Name1 VARCHAR(50), IN Name2 VARCHAR(50), IN IP VARCHAR(16))
  93:  BEGIN
  94:    START TRANSACTION;
  95:    INSERT
  96:      release.aspnet_users (id, Email, Pass, ActivateID, IsActivate, CrDate, UserName, Name1, Name2, IP, IsAdmin) VALUES (release.StrongGuid(), Email, Pass, release.StrongGuid(), FALSE, NOW(), UserName, Name1, Name2, IP, FALSE);
  97:    SELECT
  98:      *
  99:    FROM
 100:      release.aspnet_users
 101:    WHERE
 102:      i = LAST_INSERT_ID();
 103:    COMMIT;
 104:  END
 105:  $$
 106:   
 107:  CREATE DEFINER = 'release'@'%'
 108:  FUNCTION release.StrongGuid()
 109:  RETURNS CHAR(36) CHARSET utf8
 110:  BEGIN
 111:    DECLARE MD5_hash CHAR(32);
 112:   
 113:    SET MD5_hash = MD5(UUID());
 114:    RETURN CONCAT(
 115:    SUBSTRING(MD5_hash, 1, 8),
 116:    '-',
 117:    SUBSTRING(MD5_hash, 9, 4),
 118:    '-',
 119:    SUBSTRING(MD5_hash, 13, 4),
 120:    '-',
 121:    SUBSTRING(MD5_hash, 17, 4),
 122:    '-',
 123:    SUBSTRING(MD5_hash, 21, 12));
 124:  END
 125:  $$
 126:   
 127:  DELIMITER ;

Как видите, в этой структуре нет ничего необычного - табличко aspnet_users для учета пользователей, табличко sendmail для учета отправленных писем, табличко audio для работы моего сайтика. Процедурко AddMail для отправки писем и AddMailError для фиксации опибиок при отправке писем, процедурко CreateUser для создания пользователей и ClearAllUserInfo для удаления пользователей. Процедурко CreateAudio для работы моего сайтика и фнукиця StrongGuid для генерации строгого GUID.

Обратите также внимание на имена пользователей - они самодокументируемые в MySQL - после знака @ у них указывается хост - с которого можно входить в MySQL - если % - то с любого.


Теперь посмотрим как правильно сконфигурировать конфиг проекта. Для NET 3.5 полный конфиг проекта будет выглядеть вот так:


   1:  <?xml version="1.0"?>
   2:  <configuration>
   3:      <configSections>
   4:          <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
   5:              <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
   6:                  <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
   7:                  <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
   8:                      <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere"/>
   9:                      <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
  10:                      <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
  11:                      <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>
  12:                  </sectionGroup>
  13:              </sectionGroup>
  14:          </sectionGroup>
  15:      </configSections>
  16:      <appSettings>
  17:          <!-- Этот адрес нужен для активации логина -->
  18:          <add key="HostingURL" value="release.asp-net.ru"/>
  19:          <add key="NameURL" value="release.ru"/>
  20:          <add key="AdminURL" value="release-admin.asp-net.ru"/>
  21:          <!-- Доступ к почтовому серверу -->
  22:          <add key="SMTP_FromAddr" value="[email protected]"/>
  23:          <add key="SMTP_Server" value="XXX.XXX.XXX.XXX"/>
  24:          <add key="SMTP_Port" value="125"/>
  25:          <add key="SMTP_Login" value="[email protected]"/>
  26:          <add key="SMTP_Pass" value="XXXXXXXXXXXXXXX"/>
  27:          <!-- Реквизиты главного неудаляемого админа сайта -->
  28:          <add key="Admin_Login" value="release"/>
  29:          <add key="Admin_Pass" value="XXXXXXXXXXXXXXX"/>
  30:          <add key="Admin_Mail" value="[email protected]"/>
  31:      </appSettings>
  32:      <connectionStrings>
  33:          <add name="MySQLConnectionString" connectionString="Server=release.asp-net.ru;Database=release;User ID=release;Password=XXXXXXXXXX;Connection Timeout=2;Max Pool Size=500;" providerName="MySql.Data.MySqlClient"/>
  34:      </connectionStrings>
  35:      <system.web>
  36:          <compilation debug="true" strict="false" explicit="true">
  37:              <assemblies>
  38:                  <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
  39:                  <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  40:                  <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
  41:                  <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
  42:                  <add assembly="MySql.Data, Version=6.2.2.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"/>
  43:                  <add assembly="MySql.Web, Version=6.2.2.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"/>
  44:              </assemblies>
  45:          </compilation>
  46:          <pages>
  47:              <namespaces>
  48:                  <clear/>
  49:                  <add namespace="System"/>
  50:                  <add namespace="System.Collections"/>
  51:                  <add namespace="System.Collections.Generic"/>
  52:                  <add namespace="System.Collections.Specialized"/>
  53:                  <add namespace="System.Configuration"/>
  54:                  <add namespace="System.Text"/>
  55:                  <add namespace="System.Text.RegularExpressions"/>
  56:                  <add namespace="System.Linq"/>
  57:                  <add namespace="System.Xml.Linq"/>
  58:                  <add namespace="System.Web"/>
  59:                  <add namespace="System.Web.Caching"/>
  60:                  <add namespace="System.Web.SessionState"/>
  61:                  <add namespace="System.Web.Security"/>
  62:                  <add namespace="System.Web.Profile"/>
  63:                  <add namespace="System.Web.UI"/>
  64:                  <add namespace="System.Web.UI.WebControls"/>
  65:                  <add namespace="System.Web.UI.WebControls.WebParts"/>
  66:                  <add namespace="System.Web.UI.HtmlControls"/>
  67:              </namespaces>
  68:              <controls>
  69:                  <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  70:                  <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  71:              </controls>
  72:          </pages>
  73:          <authentication mode="Forms"/>
  74:          <httpHandlers>
  75:              <remove verb="*" path="*.asmx"/>
  76:              <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  77:              <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  78:              <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
  79:          </httpHandlers>
  80:          <httpModules>
  81:              <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
  82:          </httpModules>
  83:      </system.web>
  84:      <system.codedom>
  85:          <compilers>
  86:              <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  87:                  <providerOption name="CompilerVersion" value="v3.5"/>
  88:                  <providerOption name="WarnAsError" value="false"/>
  89:              </compiler>
  90:              <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" warningLevel="4" type="Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  91:                  <providerOption name="CompilerVersion" value="v3.5"/>
  92:                  <providerOption name="OptionInfer" value="true"/>
  93:                  <providerOption name="WarnAsError" value="false"/>
  94:              </compiler>
  95:          </compilers>
  96:      </system.codedom>
  97:      <!-- 
  98:          The system.webServer section is required for running ASP.NET AJAX under Internet
  99:          Information Services 7.0.  It is not necessary for previous version of IIS.
 100:      -->
 101:      <system.webServer>
 102:          <validation validateIntegratedModeConfiguration="false"/>
 103:          <modules>
 104:              <remove name="ScriptModule"/>
 105:              <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
 106:          </modules>
 107:          <handlers>
 108:              <remove name="WebServiceHandlerFactory-Integrated"/>
 109:              <remove name="ScriptHandlerFactory"/>
 110:              <remove name="ScriptHandlerFactoryAppServices"/>
 111:              <remove name="ScriptResource"/>
 112:              <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
 113:              <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
 114:              <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
 115:          </handlers>
 116:      </system.webServer>
 117:      <runtime>
 118:          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
 119:              <dependentAssembly>
 120:                  <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
 121:                  <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
 122:              </dependentAssembly>
 123:              <dependentAssembly>
 124:                  <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
 125:                  <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
 126:              </dependentAssembly>
 127:          </assemblyBinding>
 128:      </runtime>
 129:  </configuration>

Это совершенно стандартный конфиг ASP.NEt 3.5 за исключением параметров, которые я внес в секцию <appSettings> и параметров коннекта серверу MySQL - которые опять же совершенно понятны, возможно за исключением параметра Timeout=2, который означает время жизни SQL-запроса в сервере MySQL. Это достаточно важный параметр, если его не закрутить в минимум, то пул коннектов коннектов в MySQL (максимальное количество которых установлено в конфиге) мгновенно исчерпается.


Теперь перейдем к коду сайта. Он будет состоять из пяти компонентов, доступных пользователю и трех компонентов админки. Публичная часть сайта будет состоять из контрола для регистрации left.ascx, странички для регистрации Register.aspx, странички ожидания подтверждения регистрации Pending.aspx, странички активации логина ActivateLogin.aspx и странички напоминания пароля RestorePass.aspx.


Итак, в некотором месте моего проекта (в контроле, размещенном на master.page) лежил код разметки для логина в сайт (в данном случае это контрол left.ascx):


   1:              <asp:Panel ID="Panel1" runat="server">
   2:                  <table border="0" cellpadding="0" cellspacing="0" style="width: 250px; vertical-align: top;
   3:                      text-align: left">
   4:                      <tr>
   5:                          <td>
   6:                              <asp:TextBox ID="txLogin" runat="server" Width="150px"></asp:TextBox>
   7:                              <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ControlToValidate="txLogin"
   8:                                  ErrorMessage="*" ValidationGroup="Login"></asp:RequiredFieldValidator>
   9:                          </td>
  10:                          <td rowspan="2">
  11:                              <asp:ImageButton ID="btLogin" runat="server" ImageUrl="~/Image/Login.png" ValidationGroup="Login" />
  12:                              <asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
  13:                          </td>
  14:                      </tr>
  15:                      <tr>
  16:                          <td>
  17:                              <asp:TextBox ID="txPass" runat="server" Width="150px"></asp:TextBox>
  18:                              <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" ControlToValidate="txPass"
  19:                                  ErrorMessage="*" ValidationGroup="Login"></asp:RequiredFieldValidator>
  20:                          </td>
  21:                          <td>
  22:                          </td>
  23:                      </tr>
  24:                      <tr style="height: 10px">
  25:                          <td>
  26:                          </td>
  27:                          <td>
  28:                          </td>
  29:                      </tr>
  30:                      <tr>
  31:                          <td>
  32:                              <asp:HyperLink ID="ForgotPass" runat="server" ForeColor="White" Font-Names="Segoe UI"
  33:                                  Font-Size="12px" NavigateUrl="~/RestorePass.aspx">Forgot our password</asp:HyperLink>
  34:                          </td>
  35:                          <td>
  36:                          </td>
  37:                      </tr>
  38:                      <tr>
  39:                          <td>
  40:                              <asp:HyperLink ID="CreateAccount" runat="server" ForeColor="White" Font-Names="Segoe UI"
  41:                                  Font-Size="12px" NavigateUrl="~/Register.aspx">Create new account</asp:HyperLink>
  42:                          </td>
  43:                          <td>
  44:                          </td>
  45:                      </tr>
  46:                  </table>
  47:              </asp:Panel>
  48:              <asp:Panel ID="Panel2" runat="server">
  49:                     <asp:HyperLink ID="CabLink1" runat="server" ForeColor="White" Font-Names="Segoe UI"
  50:                     Font-Size="12px" ></asp:HyperLink>
  51:                  <br />
  52:                  <asp:LinkButton ID="LogoutButton1" runat="server" ForeColor="White" Font-Names="Segoe UI"
  53:                     Font-Size="12px">Logout</asp:LinkButton> &nbsp;&nbsp;
  54:                     
  55:                  <asp:LinkButton ID="AdminButton1" runat="server" ForeColor="White" Font-Names="Segoe UI"
  56:                     Font-Size="12px">Admin</asp:LinkButton>    
  57:                     
  58:                      <div style="height:63px"/>
  59:              </asp:Panel>

Как видите, контрол логина состоит из двух панелей, которые переключаются в зависимости от того, залогинен юзер или нет. А код контрола залогинивания выглядит вот так:


   1:  Partial Class Left
   2:      Inherits System.Web.UI.UserControl
   3:   
   4:      Protected Sub Left_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:              If HttpContext.Current.User.Identity.IsAuthenticated Then
   7:                  Panel1.Visible = False
   8:                  Panel2.Visible = True
   9:                  CabLink1.Text = CType(Me.Page, BasePage).User_UserName
  10:                  CabLink1.NavigateUrl = "Cab.aspx?user=" & CType(Me.Page, BasePage).User_id
  11:                  If CType(Me.Page, BasePage).User_IsAdmin Then
  12:                      AdminButton1.Visible = True
  13:                      AdminButton1.PostBackUrl = "http://" & System.Configuration.ConfigurationManager.AppSettings("AdminURL").ToString
  14:                  Else
  15:                      AdminButton1.Visible = False
  16:                  End If
  17:              Else
  18:                  Panel1.Visible = True
  19:                  Panel2.Visible = False
  20:              End If
  21:          End If
  22:      End Sub
  23:   
  24:   
  25:      Protected Sub btLogin_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btLogin.Click
  26:          Try
  27:              Dim GetOneUser As New ExecMySQL_RDR("UserName", txLogin.Text)
  28:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetOneUser.ExecMySQL("select * from releasebeat.aspnet_users where UserName=@UserName", Data.CommandType.Text)
  29:              If DR1.Read Then
  30:                  If DR1("Pass") = txPass.Text Then
  31:                      FormsAuthentication.SetAuthCookie(txLogin.Text, True)
  32:                      Panel1.Visible = False
  33:                      Panel2.Visible = True
  34:                      CabLink1.Text = DR1("UserName")
  35:                      CabLink1.NavigateUrl = "Cab.aspx?user=" & DR1("id")
  36:                      If DR1("IsAdmin") Then
  37:                          AdminButton1.Visible = True
  38:                          AdminButton1.PostBackUrl = "http://" & System.Configuration.ConfigurationManager.AppSettings("AdminURL").ToString
  39:                      Else
  40:                          AdminButton1.Visible = False
  41:                      End If
  42:                      If Not DR1("IsActivate") Then
  43:                          Panel1.Visible = False
  44:                          Panel2.Visible = True
  45:                          Response.Redirect("Pending.aspx")
  46:                      End If
  47:                  End If
  48:              End If
  49:              Lerr1.Text = ""
  50:          Catch ex As Exception
  51:              Lerr1.Text = ex.Message
  52:          End Try
  53:      End Sub
  54:   
  55:      Protected Sub LinkButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LogoutButton1.Click
  56:          FormsAuthentication.SignOut()
  57:          Panel1.Visible = True
  58:          Panel2.Visible = False
  59:      End Sub
  60:   
  61:  End Class

Как видите, это совершенно тривиальный код обращения в базу и проверки - есть ли там нужный нам юзер. Обратите внимание, что обращение в базу производится с помощью моей ADO.NET обвязка для работы с MySQL в ASP.NET-сайтах под Windows.

Как я уже говорил, я провожу границу стандартного и нестандартного кода каждого сайта не там, где ее проводит микрософт. Для меня это обязательно капча при регистрации и письмо об активации. Для микрософта это что-то совершенно иное - тмпо их убогих активационных контролов. Поэтому мой следующий фрагмент стандартного ASP-NET сайта - это страничка регистрации Register.aspx, высылающая активационные письма. Ссылка на эту страничку стоит в контроле залогинивания, а в страничке регистрации есть фрагмент с полями, которые должен заполнить юзер, главное из которых его Email-адрес:


   1:          <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
   2:              <tr>
   3:                  <td>
   4:                      <asp:Label ID="lblNewError" runat="server" Visible="false" CssClass="error" Text="You have entered incorrect login or password."></asp:Label>
   5:                      <br />
   6:                      <div class="form">
   7:                          Please fill in the form to create a new account.<br />
   8:                           <span>First Name:</span>
   9:                          <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" 
  10:              ErrorMessage="*" ControlToValidate="tbxFirstName" ValidationGroup="Create1"></asp:RequiredFieldValidator>
  11:                          <asp:TextBox ID="tbxFirstName" runat="server"></asp:TextBox><br />
  12:                          <br />
  13:                          <span>Last Name:</span>
  14:                          <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" 
  15:              ErrorMessage="*" ControlToValidate="tbxLastName" ValidationGroup="Create1"></asp:RequiredFieldValidator>
  16:                          <asp:TextBox ID="tbxLastName" runat="server"></asp:TextBox><br />
  17:                          <br />
  18:                          <span>Login:</span>
  19:                          <asp:RequiredFieldValidator ID="RequiredFieldValidator3" runat="server" 
  20:              ErrorMessage="*" ControlToValidate="tbxNewLogin" ValidationGroup="Create1"></asp:RequiredFieldValidator>
  21:                          <asp:TextBox ID="tbxNewLogin" runat="server"></asp:TextBox><br />
  22:                          <br />
  23:                          <span>Password:</span>
  24:                          <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" 
  25:              ErrorMessage="*" ControlToValidate="tbxNewPassword" ValidationGroup="Create1"></asp:RequiredFieldValidator>
  26:                          <asp:TextBox ID="tbxNewPassword" runat="server" TextMode="Password"></asp:TextBox><br />
  27:                          <br />
  28:                          <span>Email:</span>
  29:                          <asp:RequiredFieldValidator ID="RequiredFieldValidator5" runat="server" 
  30:              ErrorMessage="*" ControlToValidate="tbxNewEmail" ValidationGroup="Create1"></asp:RequiredFieldValidator>
  31:                          <asp:TextBox ID="tbxNewEmail" runat="server"></asp:TextBox><br />
  32:                          <br />
  33:                          <span>I agree with the terms<asp:CheckBox ID="cbxAgree" runat="server"></asp:CheckBox></span><br />
  34:                          <br />
  35:                          <div class="agreement">
  36:                              According to author's right all materials which presented on <b>releasebeat.ru</b>
  37:                              website are presented for advertising and acquaintance purposes and shouldn't be
  38:                              used for further coping public presentation. Otherwise you should take personal
  39:                              responsibility for illegal coping of materials. After downloading mp-3 files you
  40:                              must buy the licensed product of the author you prefer.<br />
  41:                              <br />
  42:                          </div>
  43:                          * all fields are obligatory<br />
  44:                          <br />
  45:                      </div>
  46:                      <asp:Button ID="btnCreate" runat="server" CssClass="button" Text="Create"  ValidationGroup="Create1" />
  47:                  </td>
  48:              </tr>
  49:          </table>

Как я уже говорил, моя капча в ее нынешнем виде не является OpenSource-кодом - это элемент защиты сайта от взлома и такие вещи, которые могут нанести ущерб моим партнерам и заказчикам - я не публикую. Поэтому этот OpenSource-код побликуется без капчи - хотя в нормальном сайте регисрации без кампчи конечно быть не может. (моя капча входит в состав моего решения AspNet_UserManager - компонент сайта для управления пользователями).

Код странички регистрации выглядит вот так:


   1:  Partial Class Register
   2:      Inherits BasePage
   3:   
   4:      Protected Sub CreateCommand(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCreate.Click
   5:          Dim UserID As String, ActivateID As String
   6:          Try
   7:              CreateUser.SelectParameters("Email").DefaultValue = tbxNewEmail.Text
   8:              CreateUser.SelectParameters("Pass").DefaultValue = tbxNewPassword.Text
   9:              CreateUser.SelectParameters("UserName").DefaultValue = tbxNewLogin.Text
  10:              CreateUser.SelectParameters("Name1").DefaultValue = tbxFirstName.Text
  11:              CreateUser.SelectParameters("Name2").DefaultValue = tbxLastName.Text
  12:              CreateUser.SelectParameters("IP").DefaultValue = HttpContext.Current.Request.UserHostAddress
  13:              Dim DV1 As Data.DataView = CreateUser.Select(New DataSourceSelectArguments)
  14:              If DV1 IsNot Nothing Then
  15:                  If DV1.Count > 0 Then
  16:                      UserID = DV1(0)("ID")
  17:                      ActivateID = DV1(0)("ActivateID")
  18:                  Else
  19:                      lblNewError.Visible = True
  20:                      lblNewError.Text = "CreateUser Error 1"
  21:                      Exit Sub
  22:                  End If
  23:              Else
  24:                  lblNewError.Visible = True
  25:                  lblNewError.Text = "CreateUser Error 2"
  26:                  Exit Sub
  27:              End If
  28:          Catch ex1 As MySql.Data.MySqlClient.MySqlException
  29:              If ex1.Message.StartsWith("Duplicate entry") Then
  30:                  lblNewError.Visible = True
  31:                  lblNewError.Text = "Такой пользователь уже зарегистрирован"
  32:                  Exit Sub
  33:              Else
  34:                  lblNewError.Visible = True
  35:                  lblNewError.Text = "CreateUser Error" & vbCrLf & ex1.Message
  36:                  Exit Sub
  37:              End If
  38:          Catch ex As Exception
  39:              lblNewError.Visible = True
  40:              lblNewError.Text = "CreateUser Error" & vbCrLf & ex.Message
  41:              Exit Sub
  42:          End Try
  43:          '
  44:          Try
  45:              FormsAuthentication.SetAuthCookie(tbxNewEmail.Text, True)
  46:              '
  47:              'признак аутентификации для клиентского скрипта
  48:              Dim AU_Cook As New HttpCookie("AU")
  49:              AU_Cook.Item("U") = 1
  50:          Catch ex As Exception
  51:              lblNewError.Visible = True
  52:              lblNewError.Text = "Cookie Error" & vbCrLf & ex.Message
  53:              Exit Sub
  54:          End Try
  55:          '
  56:          Try
  57:              'и отправляем мыло для активации логина
  58:              'тут тоже возможен баг - SendMail_Error: Mailbox unavailable. The server response was: non-local recipient verification failed
  59:              Mail1.SendMail(tbxNewEmail.Text, "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & tbxNewLogin.Text & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
  60:                   "<br><br><b>Логин:</b>" & tbxNewLogin.Text & _
  61:                   "<br><br><b>Пароль:</b> " & tbxNewPassword.Text & _
  62:                   "<br><br>Ваша учётная запись ещё не активна. Вы не сможете ей пользоваться, пока не перейдёте по следующей ссылке:" & _
  63:                   "<br><a href=""http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & UserID & "&j=" & ActivateID & """> http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & UserID & "&j=" & ActivateID & "</a><br>" & _
  64:                   "<br><br>Если указанная выше ссылка не открывается, скопируйте ее в буфер обмена, вставьте в адресную строку браузера и нажмите ввод." & _
  65:                   "<br><br>Желаем Вам удобного, приятного общения и хорошего отдыха!" & _
  66:                   "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его и все данные будут автоматически удалены." & _
  67:                   "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
  68:              System.Web.Security.FormsAuthentication.RedirectFromLoginPage(tbxNewEmail.Text, True)
  69:              Response.Redirect("Pending.aspx")
  70:          Catch ex As Exception
  71:              Response.Redirect("Pending.aspx?txt=" & "Ошибка, пользователь создан, но из-за почтовых проблем сообщение для активации не отправлено. Попробуйте повторно выслать письмо активации из кабинета пользователя." & ex.Message)
  72:          End Try
  73:      End Sub
  74:  End Class

Эта страничка рассылает вот такие письма об активации.




Теперь нам потребуется еще страничка ожидания Pending.aspx, куда юзер попадает после регистрации. Она тоже состоит из двух панелей (в зависимости есть кука залогиненного юзера или нет) и кнопки повторения посылки активационного письма:


   1:  <asp:Content ID="Content3" ContentPlaceHolderID="RightPlaceHolder2" runat="Server">
   2:      <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
   3:          <tr>
   4:              <td>
   5:                  <asp:Panel ID="Panel1" runat="server">
   6:                      <asp:Label ID="Label1" runat="server">Вам выслано письмо об активации.<br>
   7:                      Пока вы не активируете свой логин - работа с сайтом невозможна.<br />
   8:                      Вы можете выслать повторно письмо об активации, однако несколько одинаковых писем<br />
   9:                      могут привести к полной блокировке отправителя на вашем почтовом сервере.<br />
  10:                      Если письма об активации не доходят совершенно, попробуйте зарегистрироваться еще раз<br />
  11:                      с почтовым ящиков на другом почтовом сервере.</asp:Label>
  12:                      <br />
  13:                      <br />
  14:                      <asp:LinkButton ID="LinkButton1" runat="server">Выслать письмо для активации повторно</asp:LinkButton>
  15:                  </asp:Panel>
  16:                  <asp:Panel ID="Panel2" runat="server">
  17:                      <asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="Image/Logo.png" />
  18:                  </asp:Panel>
  19:                  <asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
  20:   
  21:              </td>
  22:          </tr>
  23:      </table>
  24:      <asp:SqlDataSource ID="GetOneUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  25:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  26:          SelectCommand="select * from releasebeat.aspnet_users where email=@Email;">
  27:          <SelectParameters>
  28:              <asp:Parameter Name="Email" Type="String" />
  29:          </SelectParameters>
  30:      </asp:SqlDataSource>
  31:  </asp:Content>

Код странички Pending.aspx такой:


   1:  Partial Class Pending
   2:      Inherits BasePage
   3:   
   4:      Protected Sub Pending_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:              If HttpContext.Current.User.Identity.IsAuthenticated Then
   7:                  Panel1.Visible = True
   8:                  Panel2.Visible = False
   9:              Else
  10:                  Panel1.Visible = False
  11:                  Panel2.Visible = True
  12:              End If
  13:          End If
  14:      End Sub
  15:   
  16:      Protected Sub LinkButton1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LinkButton1.Click
  17:          Try
  18:              GetOneUser.SelectParameters("Email").DefaultValue = "[email protected]" 'HttpContext.Current.User.Identity.Name"
  19:              Dim Dv1 As Data.DataView = GetOneUser.Select(New DataSourceSelectArguments)
  20:              If Dv1 IsNot Nothing Then
  21:                  If Dv1.Count > 0 Then
  22:                      Try
  23:                          Mail1.SendMail(Dv1(0)("Email"), "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & Dv1(0)("UserName") & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
  24:                          "<br><br><b>Логин:</b>" & Dv1(0)("UserName") & _
  25:                          "<br><br><b>Пароль:</b> " & Dv1(0)("Pass") & _
  26:                          "<br><br>Ваша учётная запись ещё не активна. Вы не сможете ей пользоваться, пока не перейдёте по следующей ссылке:" & _
  27:                          "<br><a href=""http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & Dv1(0)("id") & "&j=" & Dv1(0)("ActivateID") & """> http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "/ActivateLogin.aspx?i=" & Dv1(0)("id") & "&j=" & Dv1(0)("ActivateID") & "</a><br>" & _
  28:                          "<br><br>Если указанная выше ссылка не открывается, скопируйте ее в буфер обмена, вставьте в адресную строку браузера и нажмите ввод." & _
  29:                          "<br><br>Желаем Вам удобного, приятного общения и хорошего отдыха!" & _
  30:                          "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его и все данные будут автоматически удалены." & _
  31:                          "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
  32:                      Catch ex As Exception
  33:                          Lerr1.Text = "SendMail Error. " & vbCrLf & ex.Message
  34:                      End Try
  35:                  Else
  36:                      Lerr1.Text = "Error 1"
  37:                  End If
  38:              Else
  39:                  Lerr1.Text = "Error 2"
  40:              End If
  41:          Catch ex As Exception
  42:              Lerr1.Text = "Error. " & vbCrLf & ex.Message
  43:          End Try
  44:      End Sub
  45:   
  46:   
  47:  End Class

Эти странички рассылают письма с помощью вот такой небольшой обвязки вокруг класса MailClient, который ведет журнал рассылки активационных писем в базе MySQL:


   1:  Imports Microsoft.VisualBasic
   2:  Imports System, System.Web
   3:   
   4:  Public Class Mail1
   5:      Public Shared Sub SendMail(ByVal ToAddr As String, ByVal Subject As String, ByVal Body As String)
   6:          Dim SendedMailID As Integer
   7:          Dim AddMail As New ExecMySQL_RDR("ToAddr", ToAddr, "MailSubject", Subject, "Body", Body)
   8:          Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = AddMail.ExecMySQL("AddMail", Data.CommandType.StoredProcedure)
   9:          If DR1.Read Then
  10:              SendedMailID = DR1("MailId")
  11:          End If
  12:          Try
  13:              Dim Email As New System.Net.Mail.MailMessage(System.Configuration.ConfigurationManager.AppSettings("SMTP_FromAddr"), ToAddr, Subject, Body)
  14:              Email.IsBodyHtml = True           'для форматированной почты
  15:              'Email.Attachments.Add(New system.Net.Mail.Attachment(...)) 
  16:              Dim MailClient As New System.Net.Mail.SmtpClient()
  17:              Dim basicAuthenticationInfo As New System.Net.NetworkCredential(System.Configuration.ConfigurationManager.AppSettings("SMTP_Login"), System.Configuration.ConfigurationManager.AppSettings("SMTP_Pass"))
  18:              MailClient.Host = System.Configuration.ConfigurationManager.AppSettings("SMTP_Server")
  19:              MailClient.Port = System.Configuration.ConfigurationManager.AppSettings("SMTP_Port")
  20:              MailClient.UseDefaultCredentials = False
  21:              MailClient.Credentials = basicAuthenticationInfo
  22:              MailClient.Send(Email)
  23:          Catch ex As Exception
  24:              My.Log.WriteEntry(System.Configuration.ConfigurationManager.AppSettings("SMTP_FromAddr") & "->" & ToAddr & ":" & Subject & ":" & Body & vbCrLf & "SendMail_Error: " & ex.Message)
  25:              Dim AddMailError As New ExecMySQL_RDR("i1", SendedMailID, "SendError1", ex.Message)
  26:              AddMailError.ExecMySQL("AddMailError", Data.CommandType.StoredProcedure)
  27:          End Try
  28:      End Sub
  29:   
  30:  End Class

Обрабатывает активационные письма страничка ActivateLogin.aspx. Для разнообразия я сделал в ней обращения в MySQL Через SqlDataSource - хотя мой опыт показывает что работает он нестабильно - и даже когда у него все параметры сконфигурированы - он часто падает, ибо обращается к провайдеру MS SQL.

Поэтому, посмотрев на логику этой странички, вам лучше ее заменить на обращения к MySQL через мой более надежно работающий враппер ExecMySQL_RDR.


   1:  <asp:Content ID="Content3" ContentPlaceHolderID="RightPlaceHolder2" runat="Server">
   2:      <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
   3:          <tr>
   4:              <td>
   5:                  <asp:Literal ID="Literal1" runat="server"></asp:Literal>
   6:              </td>
   7:          </tr>
   8:      </table>
   9:      <asp:SqlDataSource ID="GetOneUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  10:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  11:          SelectCommand="select * from releasebeat.aspnet_users where id=@id;">
  12:          <SelectParameters>
  13:              <asp:Parameter Name="id" Type="String" />
  14:          </SelectParameters>
  15:      </asp:SqlDataSource>
  16:      
  17:      <asp:SqlDataSource ID="ActivateUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  18:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  19:          SelectCommand="Update releasebeat.aspnet_users Set IsActivate=True where id=@id;">
  20:          <SelectParameters>
  21:              <asp:Parameter Name="id" Type="String" />
  22:          </SelectParameters>
  23:      </asp:SqlDataSource>
  24:  </asp:Content>

Собственно код странички активации выглядит вот так:


   1:  Partial Class ActivateLogin
   2:      Inherits BasePage
   3:   
   4:      Protected Sub ActivateLogin_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:              If Context.Request.QueryString("i") <> "" And Context.Request.QueryString("j") <> "" Then
   7:                  Dim UserID As Guid
   8:                  Dim ActivateID As Guid
   9:                  Try
  10:                      UserID = New Guid(Context.Request.QueryString("i"))
  11:                      ActivateID = New Guid(Context.Request.QueryString("j"))
  12:                  Catch ex As Exception
  13:                      Throw New Exception("Указаны неверные параметры")
  14:                  End Try
  15:                  GetOneUser.SelectParameters("id").DefaultValue = UserID.ToString
  16:                  Dim DV1 As Data.DataView = GetOneUser.Select(New DataSourceSelectArguments)
  17:                  If DV1 IsNot Nothing Then
  18:                      Dim SavedGuid As String = DV1(0)("ActivateID")
  19:                      If SavedGuid = Context.Request.QueryString("j") Then
  20:                          If Not DV1(0)("IsActivate") Then
  21:                              Try
  22:                                  ActivateUser.SelectParameters("id").DefaultValue = UserID.ToString
  23:                                  ActivateUser.Select(New DataSourceSelectArguments)
  24:                              Catch ex As Exception
  25:                                  Throw New Exception("Ошибка." & ex.Message)
  26:                              End Try
  27:                              Literal1.Text = "Поздравляем!<br> Вы зарегистрированы в проекте  " & System.Configuration.ConfigurationManager.AppSettings("RealURL") & "<br>Желаем Вам приятного отдыха!<br><br>"
  28:                              Response.Redirect("Default.aspx")
  29:                          Else
  30:                              Literal1.Text = "Вы уже активированны в проекте  " & System.Configuration.ConfigurationManager.AppSettings("RealURL") & "<br>Желаем Вам удобного, приятного отдыха!<br><br>"
  31:                          End If
  32:                      Else
  33:                          Literal1.Text = "Неверный параметр активации."
  34:                      End If
  35:                  Else
  36:                      Literal1.Text = "Пользователя не существует."
  37:                  End If
  38:              Else
  39:                  Throw New Exception("Dos атака")
  40:              End If
  41:          End If
  42:   
  43:      End Sub
  44:   
  45:   
  46:  End Class

Все что нам нужно на внешней контактной поверхности сайта - это еще страничка напоминания пароля RestorePass.aspx (ссылка на которую тоже должны быть на залогинивающем контроле). Эта страничка может выглядеть так:


   1:  <asp:Content ID="Content3" ContentPlaceHolderID="RightPlaceHolder2" runat="Server">
   2:   
   3:      <table cellpadding="0" cellspacing="0" border="0" style="display: inline">
   4:          <tr>
   5:              <td>
   6:                  <asp:Label ID="lblMessage" runat="server" Visible="false" Text=""></asp:Label>
   7:                  <asp:Panel ID="pnlForgotPass" runat="server">
   8:                      <asp:Label ID="lblError" runat="server" Visible="false" CssClass="error" Text="You have entered incorrect login or password."></asp:Label>
   9:                      <br />
  10:                      Type your login or email if you want to restore your password.
  11:                      <div class="form">
  12:                          <br />
  13:                          <br />
  14:                          <span>Login:</span>
  15:                          <asp:TextBox ID="tbxForgotLogin" runat="server"></asp:TextBox><br />
  16:                          <br />
  17:                          OR<br />
  18:                          <br />
  19:                          <span>Email:</span>
  20:                          <asp:TextBox ID="tbxForgotEmail" runat="server"></asp:TextBox><br />
  21:                          <br />
  22:                      </div>
  23:                      <asp:Button ID="btnRemember" runat="server" CssClass="button" Text="REMEMBER" OnClick="RememberCommand" />
  24:                      <br /><asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
  25:                  </asp:Panel>
  26:              </td>
  27:          </tr>
  28:      </table>
  29:      
  30:      <asp:SqlDataSource ID="GetUserForName" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  31:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  32:          SelectCommand="select * from releasebeat.aspnet_users where UserName=@UserName;">
  33:          <SelectParameters>
  34:              <asp:Parameter Name="UserName" Type="String" />
  35:          </SelectParameters>
  36:      </asp:SqlDataSource>
  37:      
  38:      <asp:SqlDataSource ID="GetUserForMail" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  39:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  40:          SelectCommand="select * from releasebeat.aspnet_users where Email=@Email;">
  41:          <SelectParameters>
  42:              <asp:Parameter Name="Email" Type="String" />
  43:          </SelectParameters>
  44:      </asp:SqlDataSource>
  45:      
  46:  </asp:Content>

   1:  Partial Class RestorePass
   2:      Inherits BasePage
   3:   
   4:      Protected Sub RememberCommand(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnRemember.Click
   5:          Try
   6:              If tbxForgotEmail.Text <> "" Then
   7:                  GetUserForMail.SelectParameters("Email").DefaultValue = tbxForgotEmail.Text
   8:                  Dim DV1 As Data.DataView = GetUserForMail.Select(New DataSourceSelectArguments)
   9:                  If DV1 IsNot Nothing Then
  10:                      If DV1.Count > 0 Then
  11:                          If DV1(0)("IsActive") Then
  12:                              Mail1.SendMail(DV1(0)("Email"), "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & DV1(0)("UserName") & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
  13:                              "<br><br><b>Логин:</b>" & DV1(0)("UserName") & _
  14:                              "<br><br><b>Пароль:</b> " & DV1(0)("Pass") & _
  15:                              "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его." & _
  16:                              "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
  17:                          End If
  18:                      End If
  19:                  End If
  20:              ElseIf tbxForgotLogin.Text <> "" Then
  21:                  GetUserForName.SelectParameters("UserName").DefaultValue = tbxForgotLogin.Text
  22:                  Dim DV2 As Data.DataView = GetUserForName.Select(New DataSourceSelectArguments)
  23:                  If DV2 IsNot Nothing Then
  24:                      If DV2.Count > 0 Then
  25:                          If DV2(0)("IsActive") Then
  26:                              Mail1.SendMail(DV2(0)("Email"), "Активация логина " & System.Configuration.ConfigurationManager.AppSettings("NameURL"), "<html><body>Здравствуйте, " & DV2(0)("UserName") & " <br><br>Добро пожаловать на сайт " & System.Configuration.ConfigurationManager.AppSettings("NameURL") & " <br><br>Параметры вашей учётной записи таковы: " & _
  27:                              "<br><br><b>Логин:</b>" & DV2(0)("UserName") & _
  28:                              "<br><br><b>Пароль:</b> " & DV2(0)("Pass") & _
  29:                              "<br><br>Если данное письмо послано Вам ошибочно, то проигнорируйте его." & _
  30:                              "<br><br>___________________<br>C уважением,<br> Администрация <a href='http://" & System.Configuration.ConfigurationManager.AppSettings("HostingURL") & "'>" & System.Configuration.ConfigurationManager.AppSettings("NameURL") & "</a></body></html>")
  31:                          End If
  32:                      End If
  33:                  End If
  34:              End If
  35:              Response.Redirect("Default.aspx")
  36:          Catch ex As Exception
  37:              Lerr1.Text = ex.Message
  38:          End Try
  39:   
  40:      End Sub

Все что нам нужно еще в части управления пользователями - это смена пароля. Это можно сделать в кабинете пользователя наряду с другими специфическими параметрами профиля пользователя. С точки зрения управления пользователями - это простой Update в базу.




Теперь рассмотрим ту часть управления пользователями, которую видит только админ сайта. Как вы понимаете, админка - это совсем другой сайт. Например для сайта votpusk.ru админка выглядит вот так - Опыт видео-конвертации. Хотя во множестве проектов у меня нету выделенной админки - формы управления юзерами находятся в основном проекте. Если же есть выделенная админка в другом домене, то ее конфиг точно такой же, как конфиг основного сайта.

Для нашего OpenSource-проекта админка юзеров сайта будет состоять из трех небольших страничек admin_user_activate.aspx, admin_user_list.aspx, admin_clear_user.aspx.


Страничка admin_user_activate.aspx предназначена для активации пользователей вручную - в тех случаях когда они просят об этом по телефону из-за того, что активационное мыло до них не проходит спам-фильтры.


   1:  <%@ Page Language="VB" MasterPageFile="~/M1.master" AutoEventWireup="false" CodeFile="admin_user_activate.aspx.vb" Inherits="admin_user_activate"  %>
   2:   
   3:  <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
   4:  <h4>Активация пользователя</h4>
   5:   
   6:  <table>
   7:   
   8:  <tr><td colspan="2"><asp:Label ID="Label2" runat="server" Text="UserName"></asp:Label></td></tr>
   9:  <tr><td><asp:TextBox ID="TextBox1" runat="server" Width="300px"></asp:TextBox>
  10:  </td><td><asp:Button ID="Button1" runat="server" Text="Проверить" Width="100px" />
  11:          
  12:  </td></tr><tr><td><asp:Label ID="Label1" runat="server"></asp:Label>
  13:  </td><td><asp:Button ID="Button2" runat="server" Enabled="False" Text="Активировать" Width="100px" />
  14:  </td></tr></table>
  15:  <asp:Label ID="Lerr1" runat="server" ForeColor="Red"></asp:Label>
  16:   
  17:      <asp:SqlDataSource ID="GetOneUserByName" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  18:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  19:          SelectCommand="select * from releasebeat.aspnet_users where UserName=@UserName;">
  20:          <SelectParameters>
  21:              <asp:Parameter Name="UserName" Type="String" />
  22:          </SelectParameters>
  23:      </asp:SqlDataSource>
  24:   
  25:      <asp:SqlDataSource ID="GetOneUserByID" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  26:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  27:          SelectCommand="select * from releasebeat.aspnet_users where id=@id;">
  28:          <SelectParameters>
  29:              <asp:Parameter Name="id" Type="String" />
  30:          </SelectParameters>
  31:      </asp:SqlDataSource>
  32:   
  33:      
  34:      <asp:SqlDataSource ID="ActivateUser" runat="server" ConnectionString="<%$ ConnectionStrings:MySQLConnectionString %>"
  35:          ProviderName="<%$ ConnectionStrings:MySQLConnectionString.ProviderName %>" 
  36:          SelectCommand="Update releasebeat.aspnet_users Set IsActivate=True where id=@id;">
  37:          <SelectParameters>
  38:              <asp:Parameter Name="id" Type="String" />
  39:          </SelectParameters>
  40:      </asp:SqlDataSource>
  41:   
  42:  </asp:Content>

В сущности это просто запись однобитного флажка в базу MySQL:


   1:   
   2:  Partial Class admin_user_list
   3:      Inherits BasePage
   4:   
   5:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   6:          If Not IsPostBack Then
   7:              If Session("admin_user_list_filter") Is Nothing Then Session("admin_user_list_filter") = ""
   8:              FilterBox.Text = Session("admin_user_list_filter")
   9:              CurrentFields.Value = "UserName"
  10:              CurrentDirection.Value = WebControls.SortDirection.Ascending
  11:              Refresh()
  12:          End If
  13:      End Sub
  14:   
  15:      Sub Refresh()
  16:          Try
  17:              Dim Filter As String = Session("admin_user_list_filter")
  18:   
  19:              Dim DT As New Data.DataTable("Filtered_users")
  20:              DT.Columns.Add("i", GetType(System.Int32))
  21:              DT.Columns.Add("id", GetType(System.String))
  22:              DT.Columns.Add("Email", GetType(System.String))
  23:              DT.Columns.Add("Pass", GetType(System.String))
  24:              DT.Columns.Add("IsActivate", GetType(System.Boolean))
  25:              DT.Columns.Add("CrDate", GetType(System.DateTime))
  26:              DT.Columns.Add("UserName", GetType(System.String))
  27:              DT.Columns.Add("Name1", GetType(System.String))
  28:              DT.Columns.Add("Name2", GetType(System.String))
  29:              DT.Columns.Add("IP", GetType(System.String))
  30:              DT.Columns.Add("IsAdmin", GetType(System.Boolean))
  31:              DT.Columns.Add("IsBan", GetType(System.Boolean))
  32:   
  33:              Dim GetAllUsers2 As New ExecMySQL_RDR()
  34:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetAllUsers2.ExecMySQL("select * from releasebeat.aspnet_users order by i", Data.CommandType.Text)
  35:              While DR1.Read
  36:                  If Filter = "" Or DR1("UserName").Contains(Filter) Then
  37:                      Dim OneRow As System.Data.DataRow = DT.NewRow
  38:                      OneRow("i") = DR1("i")
  39:                      OneRow("id") = DR1("id")
  40:                      OneRow("Email") = DR1("Email")
  41:                      OneRow("Pass") = DR1("Pass")
  42:                      OneRow("IsActivate") = DR1("IsActivate")
  43:                      OneRow("CrDate") = DR1("CrDate")
  44:                      OneRow("UserName") = DR1("UserName")
  45:                      OneRow("Name1") = DR1("Name1")
  46:                      OneRow("Name2") = DR1("Name2")
  47:                      OneRow("IP") = DR1("IP")
  48:                      OneRow("IsAdmin") = DR1("IsAdmin")
  49:                      OneRow("IsBan") = DR1("IsBan")
  50:                      DT.Rows.Add(OneRow)
  51:                  End If
  52:              End While
  53:   
  54:              GridView1.AutoGenerateColumns = False
  55:              'Dim UserNameColumn As New ui.WebControls.HyperLinkField 'колонки можно выставить и в коде
  56:              Dim SortExpression As String
  57:              If CurrentDirection.Value = WebControls.SortDirection.Ascending Then
  58:                  SortExpression = CurrentFields.Value & " asc"
  59:              Else
  60:                  SortExpression = CurrentFields.Value & " desc"
  61:              End If
  62:              Dim DV1 As Data.DataView
  63:              If Filter = "" Then
  64:                  DV1 = New Data.DataView(DT, "UserName like '%*%'", SortExpression, Data.DataViewRowState.CurrentRows)
  65:              Else
  66:                  DV1 = New Data.DataView(DT, "UserName like '%" & Filter & "%'", SortExpression, Data.DataViewRowState.CurrentRows)
  67:              End If
  68:              GridView1.DataSource = DV1
  69:              GridView1.DataMember = "Filtered_users"
  70:              Dim KeyArr() As String = {"id"}
  71:              GridView1.DataKeyNames = KeyArr 'баг бейсика - запрет онлайнового обьявления массива
  72:              GridView1.DataBind()
  73:          Catch ex As Exception
  74:              Lerr1.Text = ex.Message
  75:          End Try
  76:   
  77:      End Sub
  78:   
  79:   
  80:      Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
  81:          GridView1.PageIndex = e.NewPageIndex
  82:          Refresh()
  83:      End Sub
  84:   
  85:      Protected Sub GridView1_Sorting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewSortEventArgs) Handles GridView1.Sorting
  86:          CurrentFields.Value = e.SortExpression
  87:          If CurrentDirection.Value = WebControls.SortDirection.Ascending Then
  88:              CurrentDirection.Value = WebControls.SortDirection.Descending
  89:          Else
  90:              CurrentDirection.Value = WebControls.SortDirection.Ascending
  91:          End If
  92:          Refresh()
  93:      End Sub
  94:   
  95:      Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
  96:          If e.Row.DataItem IsNot Nothing Then
  97:              Dim UnBan_Button1 As LinkButton = CType(e.Row.FindControl("UnBan_Button1"), LinkButton)
  98:              Dim Ban_Button1 As LinkButton = CType(e.Row.FindControl("Ban_Button1"), LinkButton)
  99:              If IsDBNull(e.Row.DataItem("IsBan")) Then
 100:                  Ban_Button1.Enabled = True
 101:                  UnBan_Button1.Enabled = False
 102:                  Ban_Button1.ForeColor = Drawing.Color.Red
 103:              Else
 104:                  If Not e.Row.DataItem("IsBan") Then
 105:                      Ban_Button1.Enabled = True
 106:                      UnBan_Button1.Enabled = False
 107:                      Ban_Button1.ForeColor = Drawing.Color.Red
 108:                  Else
 109:                      Ban_Button1.Enabled = False
 110:                      UnBan_Button1.Enabled = True
 111:                      UnBan_Button1.ForeColor = Drawing.Color.Red
 112:                  End If
 113:              End If
 114:   
 115:              Dim UserNameColumns As HyperLink = CType(e.Row.FindControl("UserNameColumns"), HyperLink)
 116:              UserNameColumns.NavigateUrl = "http://" & ConfigurationManager.AppSettings("HostingURL")
 117:          End If
 118:      End Sub
 119:   
 120:      Protected Sub Ban_Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
 121:          Try
 122:              Dim UserID As String = CType(sender, LinkButton).CommandArgument
 123:              Dim BanUser As New ExecMySQL_RDR("id", UserID)
 124:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = BanUser.ExecMySQL("Update releasebeat.aspnet_users set IsBan=True where id=@id", Data.CommandType.Text)
 125:              Refresh()
 126:          Catch ex As Exception
 127:              Lerr1.Text = ex.Message
 128:          End Try
 129:   
 130:      End Sub
 131:   
 132:      Protected Sub UnBan_Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
 133:          Try
 134:              Dim UserID As String = CType(sender, LinkButton).CommandArgument
 135:              Dim BanUser As New ExecMySQL_RDR("id", UserID)
 136:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = BanUser.ExecMySQL("Update releasebeat.aspnet_users set IsBan=NULL where id=@id", Data.CommandType.Text)
 137:              Refresh()
 138:          Catch ex As Exception
 139:              Lerr1.Text = ex.Message
 140:          End Try
 141:      End Sub
 142:   
 143:      Protected Sub SetFilter_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetFilter.Click
 144:          Session("admin_user_list_filter") = FilterBox.Text
 145:          Refresh()
 146:      End Sub
 147:   
 148:   
 149:  End Class

Следующая форма admin_user_list.aspx - это тоже в сущности запись одного бита в таблицу учета пользователей - только здесь есть еще сервис для отбора пользователей (когда их становятся тысячи и десятки тысяч):


   1:  <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
   2:   
   3:      <asp:HiddenField ID="CurrentFields" runat="server" />
   4:      <asp:HiddenField ID="CurrentDirection" runat="server" />
   5:     
   6:      <h4>Забанить/разбанить пользователя</h4>
   7:      <asp:TextBox ID="FilterBox" runat="server"></asp:TextBox>
   8:      <asp:Button ID="SetFilter"  runat="server" Text="Отфильтровать" />
   9:      <br><br>
  10:      <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" PageSize="25" Width="100%" CellPadding="5">
  11:          <Columns>
  12:           <asp:BoundField DataField="i" HeaderText="i" SortExpression="i"  />
  13:              <asp:TemplateField>
  14:                  <ItemTemplate>
  15:                      <asp:LinkButton ID="Ban_Button1" runat="server" 
  16:                          CommandArgument='<%# Eval("id")%>' CommandName="Ban" 
  17:                          onclick="Ban_Button1_Click" >Забанить</asp:LinkButton>
  18:                      <asp:LinkButton ID="UnBan_Button1" runat="server" 
  19:                          CommandArgument='<%# Eval("id")%>' CommandName="UnBan" 
  20:                          onclick="UnBan_Button1_Click" >Разбанить</asp:LinkButton>
  21:                  </ItemTemplate>
  22:              </asp:TemplateField>
  23:              <asp:TemplateField HeaderText="UserName" SortExpression="UserName">
  24:                  <ItemTemplate>
  25:                      <asp:HyperLink ID="UserNameColumns" runat="server" Text='<%# Eval("UserName") %>' ></asp:HyperLink>
  26:                  </ItemTemplate>
  27:              </asp:TemplateField>
  28:              <asp:CheckBoxField DataField="IsActivate" HeaderText="IsActivate" SortExpression="IsActivate" />
  29:              <asp:CheckBoxField DataField="IsAdmin" HeaderText="IsAdmin" SortExpression="IsAdmin" />
  30:              <asp:CheckBoxField DataField="IsBan" HeaderText="IsBan" SortExpression="IsBan" />
  31:              <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email"  />
  32:              <asp:BoundField DataField="IP" HeaderText="IP" SortExpression="IP"  />
  33:              <asp:BoundField DataField="CrDate" HeaderText="CrDate" SortExpression="CrDate" DataFormatString="{0:dd/MM/yyyy}" HtmlEncode="False" />
  34:          </Columns>
  35:      </asp:GridView>
  36:      <asp:Label ID="Lerr1" runat="server" ForeColor="#CC3300" Text=""></asp:Label>
  37:   
  38:      
  39:  </asp:Content>
  40:   

   1:  Partial Class admin_audio_ban
   2:      Inherits BasePage
   3:   
   4:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:              Refresh()
   7:          End If
   8:      End Sub
   9:   
  10:      Sub Refresh()
  11:          Try
  12:              Dim CreateAudio As New ExecMySQL_RDR()
  13:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = CreateAudio.ExecMySQL("select  * from releasebeat.audio", Data.CommandType.Text)
  14:              Dim DT1 As New Data.DataTable("Track")
  15:              DT1.Load(DR1)
  16:              GridView1.DataSource = DT1
  17:              GridView1.DataBind()
  18:          Catch ex As Exception
  19:              Lerr1.Text = ex.Message
  20:          End Try
  21:      End Sub
  22:   
  23:      Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
  24:          GridView1.PageIndex = e.NewPageIndex
  25:          Refresh()
  26:      End Sub
  27:   
  28:   
  29:      Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
  30:          If e.Row.DataItem IsNot Nothing Then
  31:              Dim UnBan_Button1 As LinkButton = CType(e.Row.FindControl("UnBanButton"), LinkButton)
  32:              Dim Ban_Button1 As LinkButton = CType(e.Row.FindControl("BanButton"), LinkButton)
  33:              If IsDBNull(e.Row.DataItem("IsBan")) Then
  34:                  Ban_Button1.Enabled = True
  35:                  UnBan_Button1.Enabled = False
  36:                  Ban_Button1.ForeColor = Drawing.Color.Red
  37:              Else
  38:                  If Not e.Row.DataItem("IsBan") Then
  39:                      Ban_Button1.Enabled = True
  40:                      UnBan_Button1.Enabled = False
  41:                      Ban_Button1.ForeColor = Drawing.Color.Red
  42:                  Else
  43:                      Ban_Button1.Enabled = False
  44:                      UnBan_Button1.Enabled = True
  45:                      UnBan_Button1.ForeColor = Drawing.Color.Red
  46:                  End If
  47:              End If
  48:          End If
  49:      End Sub
  50:   
  51:      Protected Sub BanButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  52:          Dim ID As String = CType(sender, LinkButton).CommandArgument
  53:          Try
  54:              Dim DeleteAudio As New ExecMySQL_RDR("id1", ID)
  55:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = DeleteAudio.ExecMySQL("update releasebeat.audio set IsBan=True where id=@id1", Data.CommandType.Text)
  56:              Refresh()
  57:          Catch ex As Exception
  58:              Lerr1.Text = ex.Message
  59:          End Try
  60:      End Sub
  61:   
  62:      Protected Sub UnBanButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  63:          Dim ID As String = CType(sender, LinkButton).CommandArgument
  64:          Try
  65:              Dim DeleteAudio As New ExecMySQL_RDR("id1", ID)
  66:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = DeleteAudio.ExecMySQL("update releasebeat.audio set IsBan=NULL  where id=@id1", Data.CommandType.Text)
  67:              Refresh()
  68:          Catch ex As Exception
  69:              Lerr1.Text = ex.Message
  70:          End Try
  71:      End Sub
  72:   
  73:  End Class

И, наконец, последняя форма админки, которую я опишу в этом OpenSource-коплекте для работы с MySQL в ASP-NET - это форма admin_clear_user.aspx, предназначенная для полной очистки базы от данных пользователя:


   1:  <%@ Page Language="VB" MasterPageFile="~/M1.master" AutoEventWireup="false" CodeFile="admin_clear_user.aspx.vb" Inherits="admin_clear_user"  %>
   2:   
   3:  <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
   4:  <h4>Полная очистка базы от всех данных пользователя</h4>
   5:   
   6:      <asp:TextBox ID="FilterBox" runat="server"></asp:TextBox>
   7:      <asp:Button ID="SetFilter"  runat="server" Text="Отфильтровать" />
   8:      
   9:      <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 
  10:          AutoGenerateColumns="False" DataKeyNames="Id" PageSize="20">
  11:          <Columns>
  12:              <asp:TemplateField HeaderText="UserId" SortExpression="Id">
  13:                  <EditItemTemplate>
  14:                      <asp:Label ID="Label1" runat="server" Text='<%# Eval("Id") %>'></asp:Label>
  15:                  </EditItemTemplate>
  16:                  <ItemTemplate>
  17:                      <asp:LinkButton ID="LinkClear" runat="server" onclick="LinkClear_Click">Очистить базу</asp:LinkButton>
  18:                      <asp:HiddenField ID="HiddenField1" runat="server" />
  19:                  </ItemTemplate>
  20:              </asp:TemplateField>
  21:              <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
  22:              <asp:BoundField DataField="UserName" HeaderText="UserName" 
  23:                  SortExpression="UserName" />
  24:              <asp:BoundField DataField="CrDate" HeaderText="Создан" 
  25:                  SortExpression="CrDate" />
  26:              <asp:BoundField DataField="Name1" HeaderText="Name1" 
  27:                  SortExpression="Name1" />
  28:              <asp:BoundField DataField="Name2" HeaderText="Name2" 
  29:                  SortExpression="Name2" />
  30:          </Columns>
  31:      </asp:GridView>
  32:       <asp:Label ID="Lerr1" runat="server" ForeColor="#CC3300" Text=""></asp:Label>
  33:   
  34:   
  35:  </asp:Content>
  36:   

В сущности это тоже вызов одной MySQL-процедуры, которая и должна в соответствии со структурой контрейнсов почистить базу. На этой форме тоже реализован сервис йильтрации юзеров.


   1:   
   2:  Partial Class admin_clear_user
   3:      Inherits BasePage
   4:   
   5:   
   6:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   7:          If Not IsPostBack Then
   8:              If Session("admin_clear_user_filter") Is Nothing Then Session("admin_clear_user_filter") = ""
   9:              FilterBox.Text = Session("admin_clear_user_filter")
  10:              GridView1_DataBind()
  11:          End If
  12:      End Sub
  13:   
  14:      Sub GridView1_DataBind()
  15:          Try
  16:              Dim Filter As String = Session("admin_clear_user_filter")
  17:              Dim DV1 As Data.DataView '= GetAllUsers1.Select(New DataSourceSelectArguments)
  18:              Dim GetAllUsers2 As New ExecMySQL_RDR()
  19:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetAllUsers2.ExecMySQL("select * from releasebeat.aspnet_users order by i", Data.CommandType.Text)
  20:              Dim DT1 As New Data.DataTable("aspnet_users")
  21:              DT1.Load(DR1)
  22:              DV1 = DT1.DefaultView
  23:              If Filter <> "" Then
  24:                  DV1.RowFilter = "UserName like '*" & Filter & "*'"
  25:              End If
  26:              GridView1.DataSource = DV1
  27:              GridView1.DataBind()
  28:          Catch ex As Exception
  29:              Lerr1.Text = ex.Message
  30:          End Try
  31:   
  32:      End Sub
  33:   
  34:      Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
  35:          GridView1.PageIndex = e.NewPageIndex
  36:          GridView1_DataBind()
  37:      End Sub
  38:   
  39:      Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound
  40:          If e.Row.DataItem IsNot Nothing Then
  41:              Dim LinkClear As LinkButton = CType(e.Row.FindControl("LinkClear"), LinkButton)
  42:              Dim UserGuid As String = CType(e.Row.DataItem, Data.DataRowView)("Id").ToString
  43:              Dim HiddenField1 As HiddenField = CType(e.Row.FindControl("HiddenField1"), HiddenField)
  44:              HiddenField1.Value = UserGuid.ToString
  45:              If CType(e.Row.DataItem, Data.DataRowView)("UserName") = ConfigurationManager.AppSettings("Admin_Login").ToString Then
  46:                  LinkClear.Enabled = False
  47:              End If
  48:          End If
  49:      End Sub
  50:   
  51:      Protected Sub LinkClear_Click(ByVal sender As Object, ByVal e As System.EventArgs)
  52:          Dim LinkClear As LinkButton = CType(sender, LinkButton)
  53:          Dim HiddenFields1 As HiddenField = CType(LinkClear.Parent.FindControl("HiddenField1"), HiddenField)
  54:          Dim DV1 As Data.DataView
  55:          Try
  56:              'ClearAllUserInfo.SelectParameters("Id1").DefaultValue = HiddenFields1.Value
  57:              'DV1 = ClearAllUserInfo.Select(New DataSourceSelectArguments)
  58:              Dim ClearAllUserInfo2 As New ExecMySQL_RDR("Id1", HiddenFields1.Value)
  59:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = ClearAllUserInfo2.ExecMySQL("ClearAllUserInfo", Data.CommandType.StoredProcedure)
  60:   
  61:          Catch X As System.Exception
  62:              If DV1 IsNot Nothing Then
  63:                  If DV1.Count > 0 Then
  64:                      Lerr1.Text = X.Message & vbCrLf & DV1(0)("ErrorMessage")
  65:                  Else
  66:                      Lerr1.Text = X.Message
  67:                  End If
  68:              Else
  69:                  Lerr1.Text = X.Message
  70:              End If
  71:              Exit Sub
  72:          End Try
  73:          lerr1.text = ""
  74:          GridView1_DataBind()
  75:      End Sub
  76:   
  77:      Protected Sub SetFilter_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SetFilter.Click
  78:          Session("admin_clear_user_filter") = FilterBox.Text
  79:          GridView1_DataBind()
  80:      End Sub
  81:   
  82:   
  83:  End Class



Теперь рассмотрим еще пару общих компонентов управления пользователями любого ASP.NET-сайта. Это задание для удаления неактивированных логинов, базовая страничка и общие потоки проекта от global.asax для создания неудаляемого админа и других общих задач.

К счастью, MySQL является более развитым, чем MS SQL - в частности задания SQL JOB у него входят в бесплатную комплектацию, а не стоят 7 тысяч долларов, как у билогейтсовского сервера. Поэтому вы можете просто сконфигурировать SqlJob непосредственно в оснастке управления MySQL и удалять там неактивированные логины. Все это уже неоднократно и достаточно подробно разжевано у мня на сайте - Выполнение периодических задач в ASP.NET.

Базовые странички у меня тоже разжеваны до предела на моем сайте - читайте например Базовые странички ASP.NET. Ну а для этого OpenSource-шаблона я покажу какую-нибудь самую простую базовую страничку, которая в найпростейшем варианте может выглядеть вот так:


   1:  Imports Microsoft.VisualBasic
   2:   
   3:  Public Class BasePage
   4:      Inherits System.Web.UI.Page
   5:   
   6:      'i INT(12) NOT NULL AUTO_INCREMENT,
   7:      'id VARCHAR(36),
   8:      'Email VARCHAR(50) NOT NULL,
   9:      'Pass VARCHAR(50) NOT NULL,
  10:      'ActivateID VARCHAR(36) NOT NULL,
  11:      'IsActivate TINYINT(1) DEFAULT NULL,
  12:      'CrDate DATETIME NOT NULL,
  13:      'UserName VARCHAR(50) NOT NULL,
  14:      'Name1 VARCHAR(50) DEFAULT NULL,
  15:      'Name2 VARCHAR(50) DEFAULT NULL,
  16:      'IP VARCHAR(16) NOT NULL,
  17:      'IsAdmin TINYINT(1) DEFAULT NULL,
  18:   
  19:      Dim _User_I As Integer
  20:      Public ReadOnly Property User_I() As Integer
  21:          Get
  22:              Return _User_I
  23:          End Get
  24:      End Property
  25:   
  26:      Dim _User_id As String
  27:      Public ReadOnly Property User_id() As String
  28:          Get
  29:              Return _User_id
  30:          End Get
  31:      End Property
  32:   
  33:      Dim _User_Email As String
  34:      Public ReadOnly Property User_Email() As String
  35:          Get
  36:              Return _User_Email
  37:          End Get
  38:      End Property
  39:   
  40:      Dim _User_IsActivate As Boolean
  41:      Public ReadOnly Property User_IsActivate() As Boolean
  42:          Get
  43:              Return _User_IsActivate
  44:          End Get
  45:      End Property
  46:   
  47:      Dim _User_UserName As String
  48:      Public ReadOnly Property User_UserName() As String
  49:          Get
  50:              Return _User_UserName
  51:          End Get
  52:      End Property
  53:   
  54:      Dim _User_IsAdmin As Boolean
  55:      Public ReadOnly Property User_IsAdmin() As Boolean
  56:          Get
  57:              Return _User_IsAdmin
  58:          End Get
  59:      End Property
  60:   
  61:      Dim _User_Pass As String
  62:      Public ReadOnly Property User_Pass() As String
  63:          Get
  64:              Return _User_Pass
  65:          End Get
  66:      End Property
  67:   
  68:      Private Sub BasePage_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  69:   
  70:          If HttpContext.Current.User.Identity.IsAuthenticated Then
  71:              'If Session("UserPropertyExists") Is Nothing Then
  72:              'аутенфицированный юзер, но свойства его еще не загружены в контекст странички
  73:              Dim GetOneUser As New ExecMySQL_RDR("Email", HttpContext.Current.User.Identity.Name)
  74:              Dim DR1 As MySql.Data.MySqlClient.MySqlDataReader = GetOneUser.ExecMySQL("select * from releasebeat.aspnet_users where email=@email", Data.CommandType.Text)
  75:              If DR1.Read Then
  76:                  Session("UserPropertyExists") = "OK"
  77:                  _User_I = DR1("I")
  78:                  _User_id = DR1("id")
  79:                  _User_Email = DR1("Email")
  80:                  _User_UserName = DR1("UserName")
  81:                  _User_Pass = DR1("Pass")
  82:                  _User_IsActivate = DR1("IsActivate")
  83:                  _User_IsAdmin = DR1("IsAdmin")
  84:   
  85:              End If
  86:              'End If
  87:          End If
  88:      End Sub
  89:   
  90:  End Class

Все странички проекта наследуются от базовой странички вот так:


   1:  Partial Class Cab
   2:      Inherits BasePage
   3:   
   4:      Protected Sub Cab_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          Try
   6:              'тут код странички
   7:          Catch ex As Exception
   8:              Lerr1.Text = ex.Message
   9:          End Try
  10:   
  11:   
  12:      End Sub
  13:  End Class

И тогда на каждой страничке проекта автоматически видно - в залогиненном ли контексте она вызывается (и кем именно) или в анонимном.



Comments ( )
Link to this page: //www.vb-net.com/MySQL_ASPNET_Users/index.htm
< THANKS ME>