В качестве примера рассмотрим простое приложение - справочник контактов, с поддержкой функции добавления, изменения и удаления.
Прежде всего создадим проект "AzureTableExample", необходимый для данной лабораторной работы.
(рис 17.1) Для демонстраци возможностей приложения, использующего в качестве хранилища данных WindowsAzure Table нам понадобится только веб - роль, добавьте ее решению.
В свойствах веб - роли определим строку подключения к эмулятору хранилища Azure.
(рис 17.2) Добавим следующие ссылки:
using Microsoft.WindowsAzure.StorageClient;
Контакт будет содержать следующую информацию:
Добавим C# класс нашей рабочей роли - Contact.cs и зададим необходимые свойства, унаследовав его от Microsoft.WindowsAzure.StorageClient.TableServiceEntity :
class Contact : Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
}
Определим требуемые свойства для класса контактов. И в конечном итоге, наш класс будет выглядеть следующим образом:
class Contact : Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String TelNumber { get; set; }
public String Email { get; set; }
}
Нам понадобятся следующие ссылки:
using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient; using System.Data.Services.Client;
Создадим соответствующий C# - класс, унаследуем его от TableServiceContext и определим конструктор:
class ContactContext : TableServiceContext
{
public ContactContext (Uri baseAddress, StorageCredentials credentials): base(baseAddress.AbsoluteUri, credentials) {}
}
Добавим свойство для возвращения data service - запроса для таблицы Contacts.
public IQueryable<Contact> ContactData
{
get
{
return this.CreateQuery<Contact>("Contacts");
}
}
Последним шагом по созданию класса - контекста является создание метода для добавления строки в таблицу. В итоге, класс должен выглядеть следующим образом 5.1:
class ContactContext : TableServiceContext
{
public IQueryable<Contact> ContactData
{
get
{
return this.CreateQuery<Contact>("Contacts");
}
}
public ContactContext (Uri baseAddress, StorageCredentials credentials): base(baseAddress.AbsoluteUri, credentials) {}
public void Add(Contact cntct)
{
this.AddObject("Contacts", cntct);
this.SaveChanges();
}
}
Создадим веб - форму для работы с нашим контакт - листом.
Внешний вид веб формы
(рис 17.3) В обозревателе решений найдите файл Global.asax.cs. В метод Application_Start необходимо добавить код создания таблицы, в случае если она не была создана до этого:
void Application_Start(object sender, EventArgs e)
{
CloudStorageAccount.SetConfigurationSettingPublisher(
(configName, configSettingPublisher) =>
{
var connectionString =
RoleEnvironment.GetConfigurationSettingValue(configName);
configSettingPublisher(connectionString);
}
);
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
//создание таблицы Windows Azure Table
CloudTableClient _tc = null;
_tc = account.CreateCloudTableClient();
_tc.CreateTableIfNotExist("Contacts");
}
Далее в обработчике события нажатия кнопки "AddContact" необходимо создать аккаунт для подключения к хранилищу, используя параметр строки подключения "DataConnection String" . После этого, для непосредственного добавления данных в таблицу нам понадобится экземпляр класса - контекса. Вызвав метод "Add" данного класса (листинг 17.1) мы добавим строку в таблицу, передав в качестве параметра экземпляр класса "Contact" . Обратите внимание, в классе Contact мы не описывали необходимые параметры для добавления строки в таблицу (ключ секции и ключ строки), класс унаследовал их от родителя. В качестве значения ключа секции зададим произвольную строку, в качестве ключа строки будем использовать сочетание "Last Name + First Name" .
protected void btn_add_Click(object sender, EventArgs e)
{
var statusMessage = String.Empty;
try
{
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var context = new ContactContext(account.TableEndpoint, account.Credentials);
context.Add(new Contact { PartitionKey = "MyContacts",
RowKey = this.tb_lastname.Text + " " + this.tb_firstname.Text,
FirstName = tb_firstname.Text, LastName = tb_lastname.Text,
TelNumber = tb_telnum.Text, Email = tb_email.Text });
}
catch (DataServiceRequestException ex)
{
statusMessage = "Unable to connect to the table storage server. Please check that the service is running.<br>"
+ ex.Message;
}
lb_status.Text = statusMessage;
}
Запустив отладку приложения, введем необходимые данные в появившуюся веб - форму и нажмем кнопку "Add Contact".
asp - код веб - формы данной задачи:
<%@ Page Language="C#"
AutoEventWireup="true" CodeBehind="AzureTable.aspx.cs" Inherits="WebRole1.AzureTable" %>
<!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>
<style type="text/css">
.style1
{
width: 169px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="NameOfExample" runat="server" Font-Bold="True"
Font-Italic="False" Font-Size="Larger" Font-Strikeout="False"
Font-Underline="False" Text="My Contact List - Windows Azure Table Example"></asp:Label>
<br />
<br />
<asp:Label ID="ContactLabel" runat="server" Text="Contact:"></asp:Label>
<br />
<table style="width:100%;">
<tr>
<td class="style1">
</td>
<td>
</td>
</tr>
<tr>
<td class="style1">
<asp:Label ID="lb_firstname" runat="server" Text="First Name"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_firstname" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style1">
<asp:Label ID="lb_lastname" runat="server" Text="Last Name"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_lastname" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style1">
<asp:Label ID="lb_telnum" runat="server" Text="Telephone Number"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_telnum" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style1">
<asp:Label ID="lb_email" runat="server" Text="E-mail"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_email" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style1">
</td>
<td>
</td>
</tr>
<tr>
<td class="style1">
</td>
<td>
<asp:Button ID="btn_add" runat="server" Height="20px" Text="Add Contact" />
</td>
</tr>
<tr>
<td class="style1">
<asp:Label ID="lb_status" runat="server"></asp:Label>
</td>
<td>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Форма создана. Классы сформированы. Осталось понять добавилось ли что-либо в наше хранилище. Открыв обозреватель серверов и раскрыв последовательно вкладки "Хранилище Windows Azure", "Разработка" и "Таблицы", мы увидем созданную таблицу "Contacts".
(рис 17.4) Щелкнув правой кнопкой мыши на нашей таблице и выбрав "Просмотреть таблицу", получив следующее:
(рис 17.5) Как видно, данные успешно добавлены.
Но нас интересует отображение списка контактов в рамках нашего приложения.
Для этого добавим на веб - форму элемент управления GridView с ID = contactGV , который мы будем использовать для отображения текущих данных таблицы.
(рис 17.6) asp - код для
<asp:GridView ID="contactGV" runat="server" CellPadding="4" ForeColor="#333333"
GridLines="None" onrowdeleting="contactGV_RowDeleting"
onselectedindexchanged="contactGV_SelectedIndexChanged">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:CommandField ButtonType="Button" SelectText="Изменить"
ShowSelectButton="True" />
<asp:CommandField ButtonType="Button" ShowDeleteButton="True" />
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#EFF3FB" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView>
Определим переменные учетной записи и контекста, до метода Page_Load:
private CloudStorageAccount account = null; private ContactContext context = null;
В метод Page_Load нашей страницы добавим следующий код, для привязки GridView к источнику данных:
account= CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
context = new ContactContext(account.TableEndpoint, account.Credentials);
contactGV.DataSource = context.ContactData;
contactGV.DataBind();
Также в методе btn_add_Click добавим следующую строку:
contactGV.DataBind();
Запустив приложение, получим следующее:
(рис 17.7) Как видно, при загрузке страницы мы сразу получаем и текущий список контактов. Если добавить новый контакт, то (см. 5.2) список дополнится еще одной записью.
(рис 17.8) По своей сути задачи редактирование и удаления сущностей конкретной таблицы весьма проста. Достаточно вызвать соответствующие методы класса - контекста. Однако, в качестве параметров методов выступают изменяемые сущности. Таким образом, все сводится к выделению конкретной сущности из таблицы по ее ключам секции и строки, которые, напомним, являются частями уникального ключа сущности.
Поскольку нашей целью является демонстрация работы с Windows Azure Table, мы пойдем по самому простому пути.
Для начала добавим на форму кнопку btn_change, невидимую при загрузке страницы.
Данные между методами формы будем передавать при помощи сессий.
Первая и главная задача сводится к тому, чтобы определить ключи строки и секции редактируемой сущности. Учитывая, что структура таблицы и названия параметров могут быть произвольны, за одним исключением - как раз параметров Partition Key и Row Key , добавим в метод Page_Load следующее:
int i = 0;
foreach (TableCell cell in contactGV.HeaderRow.Cells)
{
if (cell.Text == "PartitionKey") { Session["pkindex"] = i; }
if (cell.Text == "RowKey") { Session["rkindex"] = i; }
i++;
}
Теперь, вне зависимости от структуры таблицы, сессии pkindex и rkindex будут содержать номера столбцов contactGV , в которых находятся параметры ключей секции и строки.
Полностью метод Page_Load для данного задания должен быть следующим:
protected void Page_Load(object sender, EventArgs e)
{
btn_change.Visible = false;
account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
context = new ContactContext(account.TableEndpoint, account.Credentials);
contactGV.DataSource = context.ContactData;
contactGV.DataBind();
int i = 0;
foreach (TableCell cell in contactGV.HeaderRow.Cells)
{
if (cell.Text == "PartitionKey") { Session["pkindex"] = i; }
if (cell.Text == "RowKey") { Session["rkindex"] = i; }
i++;
}
}
Также добавим в класс ContactContext методы для обновления и удаления сущностей - Update и Delete соответственно:
public void Delete(Contact cnt)
{
this.DeleteObject(cnt);
this.SaveChanges();
}
public void Update(Contact cnt)
{
this.UpdateObject(cnt);
this.SaveChanges();
}
Добавим метод, обрабатывающий нажатие кнопки "Удалить" элемента contactGV.
protected void contactGV_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
GridView g = (GridView)sender;
try
{
Contact c = (from contact in context.CreateQuery<Contact>("Contacts")
where contact.PartitionKey == g.Rows[e.RowIndex].
Cells[Convert.ToInt32(Session["pkindex"].ToString())].Text
contact.RowKey == g.Rows[e.RowIndex].Cells[Convert.ToInt32
(Session["rkindex"].ToString())].Text
select contact).FirstOrDefault();
context.Delete(c);
}
catch(DataServiceRequestException ex)
{
lb_status.Text = ex.Message;
}
g.DataBind();
}
Обратим ваше внимание на то, что сущность для удаления мы получаем при помощи linq - запроса, указывая значения параметров PartitionKey и RowKey . Значения же параметров мы получаем из contactGV , указывая значения соответствующих ячеек.
Реализация удаления сущности на этом закончена.
Для начала напишем обработчик события изменения индекса выбранной строки contactGV , инициируемое нажатием кнопки "Изменить" . При нажатии этой кнопки должен становиться видимым элемент управления btn_change, а соответствующие текстовые поля заполняться значениями параметров редактируемой строки.
protected void contactGV_SelectedIndexChanged(object sender, EventArgs e)
{
GridView g = (GridView)sender;
int index = g.SelectedIndex;
Contact c = (from contact in context.CreateQuery<Contact>("Contacts")
where contact.PartitionKey == g.Rows[index].
Cells[Convert.ToInt32(Session["pkindex"].ToString())].Text
contact.RowKey == g.Rows[index].
Cells[Convert.ToInt32(Session["rkindex"].ToString())].Text
select contact).FirstOrDefault();
tb_firstname.Text = c.FirstName;
tb_lastname.Text = c.LastName;
tb_email.Text = c.Email;
tb_telnum.Text = c.TelNumber;
Session["index"] = index;
btn_change.Visible = true;
}
Здесь стоит обратить внимание разве что на формирование еще одной сессии, в которой мы будем хранить номер редактируемой строки в contactGV.
Вот, что должно получиться при нажатии кнопки "Изменить" напротив второй строки списка контактов:
(рис 17.9) Как видим, значения текстовых полей стали соответствовать значениям параметров редактируемой строки.
Осталось только написать метод обрабатывающий событие нажатия кнопки btn_change.
Он будет выглядеть следующим образом:
protected void btn_change_Click(object sender, EventArgs e)
{
int index = Convert.ToInt32(Session["index"].ToString());
try
{
Contact c = (from contact in context.CreateQuery<Contact>("Contacts")
where contact.PartitionKey == contactGV.Rows[index].
Cells[Convert.ToInt32(Session["pkindex"].ToString())].Text
contact.RowKey == contactGV.Rows[index].
Cells[Convert.ToInt32(Session["rkindex"].ToString())].Text
select contact).FirstOrDefault();
c.FirstName = tb_firstname.Text;
c.LastName = tb_lastname.Text;
c.Email = tb_email.Text;
c.TelNumber = tb_telnum.Text;
context.Update(c);
}
catch (DataServiceRequestException a)
{
lb_status.Text = a.Message;
}
contactGV.DataBind();
}
Номер изменяемой строки мы получаем из сессии "index" , остальное уже не должно вызывать вопросов.
Запустите приложение еще раз и измените произвольным образом любой из параметров, либо насколько из них какой - либо строки. Мы изменили Email на tableentitychange@mail.test . Нажмите кнопку "Change".
Мы получили следующее:
(рис 17.10) Еще раз обратим ваше внимание на то, что демонстрируемое приложение является не более, чем примером способов работы с Windows Azure Storage, поэтому мы пренебрегли обработкой исключительных ситуаций и проверкой правильности и целостности введенных данных. Оставляем это на ваше усмотрение.
В случае, если выполнение задания вызвало сложности и затруднения, в приложениях к данной практической работе вы найдете итоговый программный код в том виде, в котором он необходим для Задания№3.
Работа с Windows Azure Table
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AzureTable.aspx.cs" Inherits="WebRole1.AzureTable" %>
<!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>
<style type="text/css">
.style1
{
}
.style2
{
width: 149px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="NameOfExample" runat="server" Font-Bold="True"
Font-Italic="False" Font-Size="Larger" Font-Strikeout="False"
Font-Underline="False" Text="My Contact List - Windows Azure Table Example"></asp:Label>
<br />
<br />
<asp:Label ID="ContactLabel" runat="server" Text="Contact:"></asp:Label>
<br />
<table style="width:100%;">
<tr>
<td class="style2">
</td>
<td>
</td>
</tr>
<tr>
<td class="style2">
<asp:Label ID="lb_firstname" runat="server" Text="First Name"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_firstname" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style2">
<asp:Label ID="lb_lastname" runat="server" Text="Last Name"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_lastname" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style2">
<asp:Label ID="lb_telnum" runat="server" Text="Telephone Number"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_telnum" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style2">
<asp:Label ID="lb_email" runat="server" Text="E-mail"></asp:Label>
</td>
<td>
<asp:TextBox ID="tb_email" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td class="style2">
</td>
<td>
</td>
</tr>
<tr>
<td class="style2">
<asp:Button ID="btn_change" runat="server" onclick="btn_change_Click"
Text="Change" Width="105px" />
</td>
<td>
<asp:Button ID="btn_add" runat="server" Height="20px" onclick="btn_add_Click"
Text="Add Contact" />
</td>
</tr>
<tr>
<td class="style2">
<asp:Label ID="lb_status" runat="server"></asp:Label>
</td>
<td>
</td>
</tr>
<tr>
<td class="style2">
</td>
<td>
</td>
</tr>
<tr>
<td class="style1" colspan="2">
<asp:GridView ID="contactGV" runat="server" CellPadding="4" ForeColor="#333333"
GridLines="None" onrowdeleting="contactGV_RowDeleting"
onselectedindexchanged="contactGV_SelectedIndexChanged">
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:CommandField ButtonType="Button" SelectText="Изменить"
ShowSelectButton="True" />
<asp:CommandField ButtonType="Button" ShowDeleteButton="True" />
</Columns>
<EditRowStyle BackColor="#2461BF" />
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#EFF3FB" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#F5F7FB" />
<SortedAscendingHeaderStyle BackColor="#6D95E1" />
<SortedDescendingCellStyle BackColor="#E9EBEF" />
<SortedDescendingHeaderStyle BackColor="#4870BE" />
</asp:GridView></td>
</tr>
</table>
</div>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebRole1
{
class Contact : Microsoft.WindowsAzure.StorageClient.TableServiceEntity
{
public String FirstName { get; set; }
public String LastName { get; set; }
public String TelNumber { get; set; }
public String Email { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Data.Services.Client;
namespace WebRole1
{
class ContactContext : TableServiceContext
{
public IQueryable<Contact> ContactData
{
get
{
return this.CreateQuery<Contact>("Contacts");
}
}
public ContactContext(Uri baseAddress, StorageCredentials credentials) : base(baseAddress.AbsoluteUri, credentials) { }
public void Add(Contact cnt)
{
this.AddObject("Contacts", cnt);
this.SaveChanges();
}
public void Delete(Contact cnt)
{
this.DeleteObject(cnt);
this.SaveChanges();
}
public void Update(Contact cnt)
{
this.UpdateObject(cnt);
this.SaveChanges();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using System.Data.Services.Client;
using Microsoft.WindowsAzure.ServiceRuntime;
namespace WebRole1
{
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
CloudStorageAccount.SetConfigurationSettingPublisher(
(configName, configSettingPublisher) =>
{
var connectionString =
RoleEnvironment.GetConfigurationSettingValue(configName);
configSettingPublisher(connectionString);
}
);
var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
CloudTableClient _tc = null;
_tc = account.CreateCloudTableClient();
_tc.CreateTableIfNotExist("Contacts");
}
void Application_End(object sender, EventArgs e)
{
}
void Application_Error(object sender, EventArgs e)
{
}
void Session_Start(object sender, EventArgs e)
{
}
void Session_End(object sender, EventArgs e)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Services.Client;
using Microsoft.WindowsAzure;
namespace WebRole1
{
public partial class AzureTable : System.Web.UI.Page
{
private CloudStorageAccount account = null;
private ContactContext context = null;
protected void Page_Load(object sender, EventArgs e)
{
btn_change.Visible = false;
account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
context = new ContactContext(account.TableEndpoint, account.Credentials);
contactGV.DataSource = context.ContactData;
contactGV.DataBind();
int i = 0;
foreach (TableCell cell in contactGV.HeaderRow.Cells)
{
if (cell.Text == "PartitionKey") { Session["pkindex"] = i; }
if (cell.Text == "RowKey") { Session["rkindex"] = i; }
i++;
}
}
protected void btn_add_Click(object sender, EventArgs e)
{
var statusMessage = String.Empty;
try
{
context.Add(new Contact { PartitionKey = "MyContacts",
RowKey = this.tb_lastname.Text + " " + this.tb_firstname.Text,
FirstName = tb_firstname.Text, LastName = tb_lastname.Text,
TelNumber = tb_telnum.Text, Email = tb_email.Text });
}
catch (DataServiceRequestException ex)
{
statusMessage = "Unable to connect to the table storage server. Please check that the service is running.<br>"
+ ex.Message;
}
lb_status.Text = statusMessage;
contactGV.DataBind();
}
protected void contactGV_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
GridView g = (GridView)sender;
try
{
Contact c = (from contact in context.CreateQuery<Contact>("Contacts")
where contact.PartitionKey == g.Rows[e.RowIndex].
Cells[Convert.ToInt32(Session["pkindex"].ToString())].Text
contact.RowKey == g.Rows[e.RowIndex].
.Cells[Convert.ToInt32(Session["rkindex"].ToString())].Text
select contact).FirstOrDefault();
context.Delete(c);
}
catch(DataServiceRequestException ex)
{
lb_status.Text = ex.Message;
}
g.DataBind();
}
protected void contactGV_SelectedIndexChanged(object sender, EventArgs e)
{
GridView g = (GridView)sender;
int index = g.SelectedIndex;
Contact c = (from contact in context.CreateQuery<Contact>("Contacts")
where contact.PartitionKey == g.Rows[index].Cells[Convert.ToInt32(Session["pkindex"].ToString())].Text
contact.RowKey == g.Rows[index].Cells[Convert.ToInt32(Session["rkindex"].ToString())].Text
select contact).FirstOrDefault();
tb_firstname.Text = c.FirstName;
tb_lastname.Text = c.LastName;
tb_email.Text = c.Email;
tb_telnum.Text = c.TelNumber;
Session["index"] = index;
btn_change.Visible = true;
}
protected void btn_change_Click(object sender, EventArgs e)
{
int index = Convert.ToInt32(Session["index"].ToString());
try
{
Contact c = (from contact in context.CreateQuery<Contact>("Contacts")
where contact.PartitionKey == contactGV.Rows[index].
Cells[Convert.ToInt32(Session["pkindex"].ToString())].Text
contact.RowKey == contactGV.Rows[index].
Cells[Convert.ToInt32(Session["rkindex"].ToString())].Text
select contact).FirstOrDefault();
c.FirstName = tb_firstname.Text;
c.LastName = tb_lastname.Text;
c.Email = tb_email.Text;
c.TelNumber = tb_telnum.Text;
context.Update(c);
}
catch (DataServiceRequestException a)
{
lb_status.Text = a.Message;
}
contactGV.DataBind();
}
}
}
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.