четверг, 25 октября 2012 г.

6."Пейджинг" в ASP.NET из БД Oracle (Подготовка слоя пользовательского интерфейса).

Создаем страничку Default.aspx, и следующую аспх разметку:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Paging.Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div> 
     <asp:DropDownList runat="server"
                       ID="DropJobs"
                       Width="631px"
                       DataSourceID="JobsObjectDatasource"
                       DataValueField="jobId"
                       DataTextField="jobNm"
                       AutoPostBack="true" >
</asp:DropDownList>
<br />
<br />
<asp:GridView runat="server"
              ID="ListEmployees"
              DataSourceID="EmployeesObjectDatasource"
              AllowPaging="true"
              AllowSorting="true"
              AutoGenerateColumns="False"
              DataKeyNames="empId"
              Width="636px"
              AutoGenerateEditButton="true">
</asp:GridView>



<asp:ObjectDataSource runat="server"
                      ID="JobsObjectDatasource"
                      TypeName="Paging.BLLJobs"
                      SelectMethod="GetJobs" >
</asp:ObjectDataSource>

<asp:ObjectDataSource runat="server" ID="EmployeesObjectDatasource"
                      SortParameterName="EmployeesSort"
                      TypeName="Paging.BLLEmployees"
                      SelectMethod="GetEmployees"
                      SelectCountMethod="GetEmployeesCount"
                      UpdateMethod="UpdateEmployee"
                      EnablePaging="true">

<SelectParameters>
    <asp:ControlParameter  ControlID="DropJobs"
                           Name="jobId"
                           PropertyName="SelectedValue"
                           Type="Int32" />  
</SelectParameters>
<UpdateParameters>
    <asp:Parameter Name="empId"  Type="Int32"/>
    <asp:Parameter Name="Salary" Type="Double" />
</UpdateParameters>
</asp:ObjectDataSource>

    </div>
    </form>
</body>
</html>

Тут ничего особенного - всего лишь DropDownList и ObjectDataSource, на который он настроен. Для ObjectDataSource прописан SelectMethod="GetJobs" - т.е. при загрузке страницы стартует процесс извлечения данных из БД.
"ListEmployees" и "EmployeesObjectDatasource"  формируют таблицу с данными для Employees. Тут прописаны SelectMethod="GetEmployees" , SelectCountMethod="GetEmployeesCount" ,   EnablePaging="true"(нужны для пейджинга) и UpdateMethod="UpdateEmployee" для изменения записи в БД.


А в code behind нашей страницы Default.aspx пропишем настройки для колонок ListEmployees


 private BoundField empId;
   private BoundField fullName;
   private BoundField Salary;

    protected void Page_Init(object sender, EventArgs e)
    {
        empId = new BoundField();
        fullName = new BoundField();
        Salary = new BoundField();
     
        empId.DataField = "empId";
        empId.HeaderText = "ID";
        empId.Visible = false;
        ListEmployees.Columns.Add(empId);

     
        fullName.DataField = "fullName";
        fullName.HeaderText = "FullName";
        fullName.ReadOnly = true;
        fullName.SortExpression = fullName.DataField;
        ListEmployees.Columns.Add(fullName);

     
        Salary.DataField = "SALARY";
        Salary.HeaderText = "Salary";
        Salary.SortExpression = Salary.DataField;
        ListEmployees.Columns.Add(Salary);

    }

 protected void Page_Load(object sender, EventArgs e)
        {
         
        }

Вот, вроде бы и все...все вопросы пишите мне на andrtur@gmail.com




5."Пейджинг" в ASP.NET из БД OПодготовка слоя бизнес логики).racle (

После подготовки слоя доступа к данным, пришло время слоя бизнес логики.
В классе BLLJobs производится подключение к DAL слою (вот тут и пригодился инстанс, сконфигурированный в JobsProvider) извлечение DAL объектов, упаковка их в BLL объекты и предоставление пользовательскому интерфейсу.

using System;
using System.Collections.Generic;
using System.Linq;

namespace Paging
{
    /// <summary>
    /// //Реализуем BLL
    /// </summary>
    public class BLLJobs
    {
        public BLLJobs()
        {
            JobNm = String.Empty;
            JobId = 0;
        }

        public BLLJobs(String jobNm)
        {
            JobId = 0;
            JobNm = jobNm;
        }

        public BLLJobs(Int32 jobId, String jobNm)
        {
            JobId = jobId;
            JobNm = jobNm;
        }

        public int JobId { get; set; }
        public string JobNm { get; set; }

        //Упаковка объекта из DAL слоя в объект BLL слоя
        private static BLLJobs GetJobFromDalJobs(JobDetails record)
        {
            if (record == null)
                return null;
            var bllJob = new BLLJobs(record.JobId, record.JobNm);
            return bllJob;
 
        }
        //Получение списка BLL объектов
        private static List<BLLJobs> GetListJobsFromDalJobs(List<JobDetails> recordset)
        {
            return recordset.Select(record => GetJobFromDalJobs(record)).ToList();
        }

        //Метод для ObjectDataSource
        public static List<BLLJobs> GetJobs()
        {
            var daLjobscoll = JobsProvider.Instance.GetJobs();
            var blLjobscoll = GetListJobsFromDalJobs(daLjobscoll);
            return blLjobscoll;
        }
        //Метод для ObjectDataSource
        public static BLLJobs GetJobById(Int32 jobId)
        {
            var job = JobsProvider.Instance.GetJobById(jobId);
            var blljob = GetJobFromDalJobs(job);
            return blljob; 
        }
    }
}

Есть некоторое отличие в BLL классе BLLEmployees - придется добавить метод для пейджинга:GetPageIndex, который рассчитывает индекс страницы. в обоих классах BLL слоя совмещены функционал и создание свойств - оберток объекта DAL слоя. Разумно было бы разнести эти моменты в разные классы - но в небольшом демонстрационном проектике все таки внимание больше заострено на самом пейджинге, нежели на проектировании архитектуры. Итак класс BLLEmployees содержит методы, позволяющие подключиться к DAL слою через инстанс (методы GetEmployeeFromDalEmployees и GetListEmployeesFromDalEmployees ), получить данные, упаковать их в BLL объекты и предоставить объекту ObjectdataSource для последующей визуализации.


using System;
using System.Collections.Generic;
using System.Linq;

namespace Paging
{
    /// <summary>
    /// //Реализуем BLL
    /// </summary>
    public class BLLEmployees
    {
        public BLLEmployees()
        {
            LastName = "";
            FirstName = "";
            JobId = 0;
            EmpId = 0;
        }

        public BLLEmployees(Int32 empId, Int32 jobId, String firstName, String lastName, Double salary)
        {
            EmpId = empId;
            JobId = jobId;
            FirstName = firstName;
            LastName = lastName;
            Salary = salary; 
        }

        public int EmpId { get; set; }

        public int JobId { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public double Salary { get; set; }
       
        public String FullName
        {
            get {return LastName + "  " + FirstName;}
           
 
        }

        //Упаковка объекта из DAL слоя в объект BLL слоя
        private static BLLEmployees GetEmployeeFromDalEmployees(EmployeeDetails record)
        {
            if (record == null)     
                return null;

            var BLLEmployee =
                new BLLEmployees(record.EmpId, record.JobId, record.FirstName, record.LastName, record.Salary);
     
            return BLLEmployee;
 
        }
        //Получение списка BLL объектов
        private static List<BLLEmployees> GetListEmployeesFromDalEmployees(List<EmployeeDetails> recordset)
        {
            if (recordset == null)
                return null;
            return recordset.Select(record => GetEmployeeFromDalEmployees(record)).ToList();
        }

        //Метод для ObjectDataSource
        public static List<BLLEmployees> GetEmployees(int jobId, int startRowIndex, int maximumRows, String employeesSort)
        {     
            List<BLLEmployees> listEmployees;
            var recordset =                 EmployeesProvider.Instance.GetEmployees(jobId,GetPageIndex(startRowIndex,maximumRows),maximumRows,employeesSort);
            listEmployees = GetListEmployeesFromDalEmployees(recordset);
            return listEmployees; 
        }


        //Метод для ObjectDataSource
        public static Int32 GetEmployeesCount(Int32 jobId)
        {
            int employeesCount = EmployeesProvider.Instance.GetEmployeesCount(jobId);
            return employeesCount;
        }

        //Расчет индекса страницы для пейджинга
        protected static int GetPageIndex(int startRowIndex, int maximumRows)
        {
            if (maximumRows <= 0)
                return 0;           
                return (int)Math.Floor(startRowIndex / (double)maximumRows);
        }

        //Обновление колонки "Salary"
        public static bool UpdateEmployee(Int32 empId,Double salary)
        {
            var employee = new EmployeeDetails(empId,0, "", "", salary);
            var ret =  EmployeesProvider.Instance.UpdateEmployee(employee);
            return ret;  
        } 
    }
}

В следующем разделе создадим объекты пользовательского интерфейса и настроим их на соответствующие классы BLL.

4."Пейджинг" в ASP.NET из БД Oracle (Подготовка слоя доступа к данным ч.3)


Создаем класс OracleEmployeeProvider, который наследуется от EmployeesProvider. В нем реализовано три функции: GetEmployees, GetEmployeesCount и UpdateEmployee - мы переопределили прописанные в абстрактном классе EmployeesProvider функции для работы с таблицей Employees БД.


using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OracleClient;
using Paging;

    /// <summary>
    /// Класс - провайдер для доступа к таблице Employees
    /// </summary>
    public class OracleEmployeeProvider: EmployeesProvider
    {
        //Получение списка записей из БД
        public override List<EmployeeDetails> GetEmployees(int jobId, int pageIndex, int pageSize, String employeesSort)
        {
            using (var connection = new OracleConnection(OracleConnectionString))
            {
                switch (employeesSort)
                {
                    case "":
                        employeesSort = "empId";
                        break;
                    case "fullName":
                        employeesSort = "LASTNAME";
                        break;
                    case "fullName DESC":
                        employeesSort = "LASTNAME DESC";
                        break;
                }

                var cmd =
                    new OracleCommand("Select EMP_ID as empId,JOB_ID as jobId,FIRST_NAME as firstName,LAST_NAME as lastName,Salary FROM (SELECT a.*, ROWNUM r FROM (SELECT * FROM EMPLOYEES WHERE JOB_ID = :pJOB_ID)a where rownum <= :HigerBound) where r >= :LowerBound order by " + employeesSort, connection)
                        {CommandType = CommandType.Text};
                var lowerBound = pageIndex * pageSize + 1;
                var higerBound = (pageIndex + 1) * pageSize;
                cmd.Parameters.Add(new OracleParameter("pJOB_ID", jobId));
                cmd.Parameters.Add(new OracleParameter("HigerBound", higerBound));
                cmd.Parameters.Add(new OracleParameter("LowerBound", lowerBound));
           
                connection.Open();
                IDataReader reader = ExecuteReader(cmd, CommandBehavior.SingleRow);
                if (reader.Read())
                {
                    return GetEmployeeListFromReader(reader);
                }             
                    return null;
            }
        }


        //Получение количества записей из БД
        public override int GetEmployeesCount(int jobId)
        {
            using (var connect = new OracleConnection(OracleConnectionString))
            {
                var command = new OracleCommand("SELECT COUNT(*) FROM EMPLOYEES WHERE JOB_ID= :PJOB_ID", connect);
                command.CommandType = CommandType.Text;
                command.Parameters.Add("PJOB_ID", OracleType.Int32).Value = jobId;
                connect.Open();
                return Convert.ToInt32(ExecuteScalar(command));
            }
        }


        //Обновление записей
        public override bool UpdateEmployee(EmployeeDetails employee)
        {
            using (var connect = new OracleConnection(OracleConnectionString))
            {
                var command = new OracleCommand("UPDATE EMPLOYEES SET SALARY = :PSALARY WHERE EMP_ID = :PEMP_ID",connect);
                command.CommandType = CommandType.Text;
                command.Parameters.Add("PSALARY", OracleType.Double).Value = employee.Salary;
                command.Parameters.Add("PEMP_ID", OracleType.Int32).Value = employee.EmpId;
                connect.Open();
                Int32 ret = ExecuteNonQuery(command);
                return (ret == 1);     
            } 
        }
    }

Создаем класс OracleJobProvider, который наследуется от JobsProvider. В нем переопределены функции: GetJobs() и GetJobById() - мы переопределили прописанные в абстрактном классе JobsProvider функции для работы с таблицей Jobs БД.

На этом рассмотрение слоя DAL закончено. В следующей статье рассмотрим слой бизнес логики, в котором реализована группа классов, преобразующая информацию полученную из БД в объектный вид и передающая ее "наверх" в слой пользовательского интерфейса (UI).

3."Пейджинг" в ASP.NET из БД Oracle (Подготовка слоя доступа к данным ч.2)


Код класса TestSection, который наследуем от класса ConfigurationSection и используем для упаковки и хранения настроек web.config. В основном, кажется, тут все понятно.

using System.Configuration;
using System.Web.Configuration;

namespace Paging
{
    /// <summary>
    /// Считывание настроек Web.config
    /// </summary>
    public class TestSection:ConfigurationSection
    {
        public readonly static TestSection Section =
            (TestSection)WebConfigurationManager.GetSection("TestSection");


        [ConfigurationProperty("jobs")]
        public JobsElement Jobs
        {
            get { return (JobsElement)base["jobs"]; }
        }

        [ConfigurationProperty("Employees")]
        public EmployeesElement Employees
        {
            get { return (EmployeesElement)base["Employees"]; }
        }
    }

    public class JobsElement : ConfigurationElement
    {
 
        [ConfigurationProperty("providerType", DefaultValue = "OracleJobProvider")]
        public string ProviderType
        {
            get { return (string)base["providerType"]; }
            set { base["providerType"] = value; }
        }
    }

    public class EmployeesElement : ConfigurationElement
    {
 
        [ConfigurationProperty("providerType", DefaultValue = "OracleEmployeeProvider")]
        public string ProviderType
        {
            get { return (string)base["providerType"]; }
            set { base["providerType"] = value; }
        }
    }
}

В этом классе мы прописываем два провайдера данных OracleJobProvider и OracleEmployeeProvider. При создании instance  в классах JobsProvider и EmployeesProvider необходимый провайдер данных будет извлекаться из TestSection. Таким образом BLL слой нашего приложения передает вызовы DAL слою.

Классы - обертки для таблиц БД:

Класс - обертка для таблицы jobs:


using System;

namespace Paging
{
    /// <summary>
    /// Класс контейнер служит для упаковки полученных значений
    /// </summary>
    public class JobDetails
    {
        public JobDetails()
        {
            JobNm = String.Empty;
        }

        public JobDetails(String jobNm)
        {
            JobNm = jobNm;
        }

        public JobDetails(Int32 jobId, String jobNm)
        {
            JobId = jobId;
            JobNm = jobNm;
        }

        public int JobId { get; set; }
        public string JobNm { get; set; }
    }
}



Класс - обертка для таблицы Employees:


using System;

namespace Paging
{
   /// <summary>
    /// Класс контейнер служит для упаковки полученных значений
    /// </summary>
    public class EmployeeDetails
    {
        public EmployeeDetails()
        {

        }

        public EmployeeDetails(Int32 empId,Int32 jobId, String firstName, String lastName,Double salary)
        {
            EmpId = empId;
            JobId = jobId;
            FirstName = firstName;
            LastName = lastName;
            Salary = salary;
        }

        public int EmpId { get; set; }

        public int JobId { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public double Salary { get; set; }
    }
}

Свойства, созданные в классах, полностью соответствуют таблицам которые мы создавали в БД в первой части. В следующей части рассмотрим сами классы - провайдеры. Именно в них реализован механизм подключения к БД и извлечения данных.


понедельник, 15 октября 2012 г.

2."Пейджинг" в ASP.NET из БД Oracle (Подготовка слоя доступа к данным)


          Для доступа к данным, находящимся в БД, подготовим группу классов. Классы доступа к БД, извлечения данных и упаковки их в объектное представление разделены на так называемые "слой доступа к данным" (Data Access Layer - DAL) и "слой бизнес - логики" (Business Logic Layer - BLL) . На диаграмме показаны взаимоотношения слоев:

        Рассмотрим слой DAL:
        Его задача - это подключение к БД, извлечение данных и передача их наверх. Не особо заботясь ни о том кто инициировал его работу, ни что произойдет с извлеченными данными далее, слой DAL просто подключается к БД и получает информацию. При проектировании DAL создается абстрактный базовый класс BaseDal:


using System;
using System.Data;
using System.Data.Common;

namespace Paging
{
    /// <summary>
    /// Класс для реализации всех общих задач  приложения
    /// </summary>
    public abstract class BaseDal
    {
 

        //строка подключения к БД

        public BaseDal()
        {
            OracleConnectionString = String.Empty;
        }

        protected string OracleConnectionString { get; set; }

     
        //Для обновления

        protected int ExecuteNonQuery(DbCommand cmd)
        {
            return cmd.ExecuteNonQuery();
        }

        //Для выборки данных
        protected IDataReader ExecuteReader(DbCommand cmd, CommandBehavior behavior)
        {
            return cmd.ExecuteReader(behavior);
        }

        protected IDataReader ExecuteReader(DbCommand cmd)
        {
            return ExecuteReader(cmd, CommandBehavior.Default);
        }

        protected object ExecuteScalar(DbCommand cmd)
        {
            return cmd.ExecuteScalar();
        }

 
    }
}

           В этом классе представлено свойство OracleConnectionString и методы - упаковщики базовых методов объекта DbCommand, который может быть и OracleCommand и SqlCommand. таким образом в этом классе реализованы методы ExecuteNonQuery,ExecuteReader,ExecuteScalar осуществляющие конкретные действия, при чем даже про тип БД разговор пока не ведется.
         Далее создадим класс - наследник BaseDal:


using System;
using System.Collections.Generic;
using System.Web.Configuration;
using System.Data;

namespace Paging
{
    /// <summary>
    /// Сводное описание для OracleProvider
    /// </summary>
    public abstract class JobsProvider: BaseDal
    {
 
        private static JobsProvider _instance;
        public static JobsProvider Instance
        {
            get {
                if(_instance == null)
                {
                    _instance =                        (JobsProvider)Activator.CreateInstance(Type.GetType(TestSection.Section.Jobs.ProviderType));
                    return _instance;
                }
                return _instance;
             
            }
        }

        protected JobsProvider()
        {
            //ссылка на web.config извлекаем строку
             OracleConnectionString = WebConfigurationManager.ConnectionStrings["LocalOracleServer"].ConnectionString;

        }

        protected JobDetails GetJobFromReader(IDataReader reader)
        {
            var job = new JobDetails(
                Convert.ToInt32(reader["JOBID"]),
                reader["JOBNM"].ToString());
            return job; 
        }


        protected List<JobDetails> GetJobListFromReader(IDataReader reader)
        {
            var jobsArr = new List<JobDetails>();
            while (reader.Read())
            {
                jobsArr.Add(GetJobFromReader(reader));
     
            }

            return jobsArr;
        }
        //оболочки SQL команд
        public  abstract List<JobDetails> GetJobs();
        public abstract JobDetails GetJobById(Int32 jobId);

    }
}


Класс JobsProvider несколько конкретизирует направление, которым необходимо заниматься при извлечении данных. Он имеет ссылки на два вспомогательных класса: TestSection и JobDetails. Первый наследуется от ConfigurationSection и является своеобразным упаковщиком настроек, которые должны содержаться в web.config. JobDetails -обыкновенный класс - обертка для полей таблицы Jobs. На обоих этих классах остановимся позднее и я приведу их полное содержимое. А пока остановимся на содержимом класса JobsProvider:
В нем реализовано свойство Instance, т. е. экземпляр класса, который с помощью Type.GetType()
в момент исполнения кода указывает на провайдер данных, указанный в TestSection. Это реализовано для того чтобы ослабить связь между BLL слоем и DAL слоем и исключить создание DAL объектов в BLL слое.
protected JobDetails GetJobFromReader(IDataReader reader) - этот метод "упаковывает" извлеченную из БД строку данных в объект класса JobDetails.
 protected List<JobDetails> GetJobListFromReader - укладывает упакованные объекты в список. тут, я думаю, понятно.
В следующей статье приведу код классов JobDetails и TestSection, чтоб стало понятнее, откуда что берется, а затем рассмотрим класс - поставщик данных.





пятница, 12 октября 2012 г.

Как развернуть ASP MVC приложение на Somee.com


В этой статье мы рассмотрим способ разворачивания веб сайта, реализованного с помощью технологии ASP.NET MVC и Framework 4.0 на бесплатном ASP.NET хостинге somee.com.


         Переходим по ссылке “Control panel”  на форму следующего вида:



Перед регистрацией хозяева хостинга настоятельно просят нас посетить их онлайн магазин и заказать пакет услуг. Без этого в форму регистрации не попадешь. Но в их магазине есть бесплатный пакет – правда с ним удастся создать лишь один сайт на хостинге (то что нужно для начала).
 Идем по ссылке “Visit our store” и выбираем бесплатный пакет, как показано красной стрелкой :



И после этого нам доступна форма регистрации, которую необходимо заполнить:

После регистрации соглашаемся с условиями использования (ставим галочки) и жмем“Continiue”:


Теперь нам доступна веб админка:



 В админке переходим по ссылке “WebSites”, и жмем "Create" – создать сайт.








 Далее конфигурируем наш веб сайт, заполняем поле “Site name”, выбираем ОС и веб сервер, и версию ASP.NET. Жмем “Create website”.







Именно здесь и начнем процесс разворачивания нашего ASP MVC приложения. Для успешного его окончания надо внести несколько изменений в проект нашего веб сайта в Microsoft Visual Studio. Я использовал Microsoft Visual Studio 2010. Необходимо в разделе “Ссылки” вашего ASP MVC проекта выставить опцию "Копировать локально” в true для следующих сборок:

 EntityFramework.dll

System.Web.Helpers.dll
System.Web.Mvc.dll
System.Web.WebPages.dll
И произвести build вашего приложения.


В дальнейшем по мере развития проекта, возможно, придется копировать локально некоторые другие сборки аналогичным способом.

Создаем папки проекта, в которые в последующем будет заливать файлы сборок и конфигурации нашего веб сайта.




После создания всех папок получается следующая структура проекта:


Внутренняя структура каждой папке в этом списке должна строго соответствовать структуре папок вашего проекта. К примеру папка Views содержит:





Рассмотрим на примере, каким образом заливать файлы сборок в папку “bin” после нажатия на кнопку “upload”. Заливаем все файлы с расширением “dll” в папку “bin”:


Теперь рассмотрим момент, связанный с локальной БД MS SQL. Файл БД расположен

в папке App_Data проекта. Для того чтобы перенести его на хостинг, создадим там БД:

Жмем “Databases” и “Create” в админке:





Затем создаем БД, даем ей название, выбираем версию сервера БД и жмем “Create empty database”:



Если создание БД прошло успешно, появляется сообщение с предложением перейти к администрированию созданной БД( “Click here to manage database”).





1 - это сформированная строка связи с БД (она понадобится позднее);
2 – опция для прикрепления локального файла БД, который на данный момент находится в папке App_Data нашего веб проекта (имеется в виду папка App_Data на хостинге, куда вы, надеюсь, залили файл ASPNETDB.MDF).
Жмем “Attach database”:


  1. Выбираем веб проект;
  2. Выбираем месторасположение файла БД;
  3. Выбираем сам файл БД;
  4. Жмем “Attach” и прикрепляем БД; 

Далее необходимо прописать строку связи с нашей БД в файл Web.config.
Копируем строку связи в буфер.


И затем через file manager (1) открываем Web.config (2) для редактирования:



Меняем строку связи на нашу:



Добавим следующие строки в раздел System.web Web.config:


<pages

         pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"

         pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"

         userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">





Нажимаем “Save” в верхнем правом углу редактируемого файла web.config. 
Пришло время проверить, как работает наш веб сайт на хостинге.
Жмем (1), затем (2) для просмотра.



Видим, что все работает:







Можно регистрироваться, логиниться и выходить. 
Всем спасибо за внимание!