Cайтік з web-сервісом, специфічнім membership-провайдером та даними Excel.
У минулому році я виконав безліч проєктів, двадцять з яких я описав тут Опис двадцяти моїх дрібних фрілансерских проєктів 2016-го року, у новому 2017-му року - не меньше, частину з яких я описав ось тут 2017, а на цій сторінці я опищу це один невеличкий сайтік, фактично зроблений за один день. Цей сайтік має три компонента, які можуть кого-небудь зацікавити:
- 1. Специфічний membership-провайдер, який працює без SQL-серверу, а саме по логинам у конфигу.
- 2. Доступ до даних зі сторінки Excel.
- 3. Трекінг почтових відправлень.
1. Спеціфічний membership-провайдер, який працює без SQL-серверу, а саме по логинам у конфигу.
З точки зору авторизації у цьому конфигу задані три важливі речі:
- Перш за все я задав для свого сайта ось такий конфіг, у якому у стрічці 20 я задав, що авторізацію юзерів буде виконувати класс WebConfigMembershipProvider.
- По-друге, у конфигі у стрічці 18 я задав, що до доступу до смислової частини сайту потрібна авторизаці.
- По-трете, у стрічках 10-11 я задав, що сайт буде використовувати звичайну для интернету авторизацію FORMS, і виконувати вхід буде форма Login.
- Ну і далі, у стрічці 13 я задав вже сам логін.
1: <configuration>
2: .....
3: <system.web>
4: <customErrors mode="Off"/>
5: <compilation debug="true" strict="false" explicit="true" targetFramework="4.0">
6: <assemblies>
7: <add assembly="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
8: </assemblies>
9: </compilation>
10: <authentication mode="Forms">
11: <forms loginUrl="~/Account/Login.aspx" timeout="2880">
12: <credentials passwordFormat="Clear">
13: <user name="admin" password="N%nYhyEP~T{v6m" />
14: </credentials>
15: </forms>
16: </authentication>
17: <authorization>
18: <deny users="?" />
19: </authorization>
20: <membership defaultProvider="WebConfigMembershipProvider">
21: <providers >
22: <clear/>
23: <add name="WebConfigMembershipProvider" type="WebConfigMembershipProvider"/>
24: </providers>
25: </membership>
26: <profile>
27: <providers>
28: <clear/>
29: <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
30: </providers>
31: </profile>
32: <roleManager enabled="false">
33: <providers>
34: <clear/>
35: <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/"/>
36: <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/"/>
37: </providers>
38: </roleManager>
39: </system.web>
40: <system.webServer>
41: <modules runAllManagedModulesForAllRequests="true"/>
42: </system.webServer>
43: ....
44: </configuration>
Таким чином перша форма для незалогіненого юзера буде виглядати ось так:
Для новачків може бути питання, а звідки з'явилося щось взагалі у каталозі Account, зокрема форма Login? Справа в тому, що ця форма утворюється автоматично при утворенні ASP.NET проєкту:
Зверніть увагу, що папка Account має свій власний конфіг, який дозволяє неаутентфікованому юзеру заходити до форми Register.
1: <?xml version="1.0"?>
2: <configuration>
3:
4: <location path="Register.aspx">
5: <system.web>
6: <authorization>
7: <allow users="*"/>
8: </authorization>
9: </system.web>
10: </location>
11:
12: <system.web>
13: <authorization>
14: <deny users="?"/>
15: </authorization>
16: </system.web>
17:
18: </configuration>
Але мій сайт (з точки зору безпеки) не має можливості реєстрації нових юзерів, він працює лише по тим самим логінам, які я сам задав йому у конфігі. Тому і сам клас провайдера, до якого звертається вбудований у ASP.NET контрол на формі Login, виглядає дуже просто, я заповнив в ньому лише деякі методи.
1: Imports Microsoft.VisualBasic
2: Imports System.Configuration
3: Imports System.Web.Configuration
4: Imports System.Web.Security
5:
6: Public Class WebConfigMembershipProvider
7: Inherits MembershipProvider
8:
9: Private _users As FormsAuthenticationUserCollection = Nothing
10: Private _passwordFormat As FormsAuthPasswordFormat
11:
12: Public Overloads Overrides Sub Initialize(name As String, config As System.Collections.Specialized.NameValueCollection)
13: MyBase.Initialize(name, config)
14: _passwordFormat = getPasswordFormat()
15: End Sub
16:
17: Public Overloads Overrides Function ValidateUser(username As String, password As String) As Boolean
18: Dim user = getUsers()(username)
19: If user Is Nothing Then
20: Return False
21: End If
22:
23: If _passwordFormat = FormsAuthPasswordFormat.Clear Then
24: If user.Password = password Then
25: Return True
26: End If
27: Else
28: If user.Password = FormsAuthentication.HashPasswordForStoringInConfigFile(password, _passwordFormat.ToString()) Then
29: Return True
30: End If
31: End If
32:
33: Return False
34: End Function
35:
36: Protected Function getUsers() As FormsAuthenticationUserCollection
37: If _users Is Nothing Then
38: Dim section As AuthenticationSection = getAuthenticationSection()
39: Dim creds As FormsAuthenticationCredentials = section.Forms.Credentials
40: _users = section.Forms.Credentials.Users
41: End If
42: Return _users
43: End Function
44:
45: Protected Function getAuthenticationSection() As AuthenticationSection
46: Dim config As Configuration = WebConfigurationManager.OpenWebConfiguration("~")
47: Return DirectCast(config.GetSection("system.web/authentication"), AuthenticationSection)
48: End Function
49:
50: Protected Function getPasswordFormat() As FormsAuthPasswordFormat
51: Return getAuthenticationSection().Forms.Credentials.PasswordFormat
52: End Function
53:
54: Public Overrides Property ApplicationName As String
55: Get
56:
57: End Get
58: Set(value As String)
59:
60: End Set
61: End Property
62:
63: Public Overrides Function ChangePassword(username As String, oldPassword As String, newPassword As String) As Boolean
64:
65: End Function
66:
67: Public Overrides Function ChangePasswordQuestionAndAnswer(username As String, password As String, newPasswordQuestion As String, newPasswordAnswer As String) As Boolean
68:
69: End Function
70:
71: Public Overrides Function CreateUser(username As String, password As String, email As String, passwordQuestion As String, passwordAnswer As String, isApproved As Boolean, providerUserKey As Object, ByRef status As System.Web.Security.MembershipCreateStatus) As System.Web.Security.MembershipUser
72:
73: End Function
74:
75: Public Overrides Function DeleteUser(username As String, deleteAllRelatedData As Boolean) As Boolean
76:
77: End Function
78:
79: Public Overrides ReadOnly Property EnablePasswordReset As Boolean
80: Get
81:
82: End Get
83: End Property
84:
85: Public Overrides ReadOnly Property EnablePasswordRetrieval As Boolean
86: Get
87:
88: End Get
89: End Property
90:
91: Public Overrides Function FindUsersByEmail(emailToMatch As String, pageIndex As Integer, pageSize As Integer, ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
92:
93: End Function
94:
95: Public Overrides Function FindUsersByName(usernameToMatch As String, pageIndex As Integer, pageSize As Integer, ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
96:
97: End Function
98:
99: Public Overrides Function GetAllUsers(pageIndex As Integer, pageSize As Integer, ByRef totalRecords As Integer) As System.Web.Security.MembershipUserCollection
100:
101: End Function
102:
103: Public Overrides Function GetNumberOfUsersOnline() As Integer
104:
105: End Function
106:
107: Public Overrides Function GetPassword(username As String, answer As String) As String
108:
109: End Function
110:
111: Public Overloads Overrides Function GetUser(providerUserKey As Object, userIsOnline As Boolean) As System.Web.Security.MembershipUser
112:
113: End Function
114:
115: Public Overloads Overrides Function GetUser(username As String, userIsOnline As Boolean) As System.Web.Security.MembershipUser
116:
117: End Function
118:
119: Public Overrides Function GetUserNameByEmail(email As String) As String
120:
121: End Function
122:
123: Public Overrides ReadOnly Property MaxInvalidPasswordAttempts As Integer
124: Get
125:
126: End Get
127: End Property
128:
129: Public Overrides ReadOnly Property MinRequiredNonAlphanumericCharacters As Integer
130: Get
131:
132: End Get
133: End Property
134:
135: Public Overrides ReadOnly Property MinRequiredPasswordLength As Integer
136: Get
137:
138: End Get
139: End Property
140:
141: Public Overrides ReadOnly Property PasswordAttemptWindow As Integer
142: Get
143:
144: End Get
145: End Property
146:
147: Public Overrides ReadOnly Property PasswordFormat As System.Web.Security.MembershipPasswordFormat
148: Get
149:
150: End Get
151: End Property
152:
153: Public Overrides ReadOnly Property PasswordStrengthRegularExpression As String
154: Get
155:
156: End Get
157: End Property
158:
159: Public Overrides ReadOnly Property RequiresQuestionAndAnswer As Boolean
160: Get
161:
162: End Get
163: End Property
164:
165: Public Overrides ReadOnly Property RequiresUniqueEmail As Boolean
166: Get
167:
168: End Get
169: End Property
170:
171: Public Overrides Function ResetPassword(username As String, answer As String) As String
172:
173: End Function
174:
175: Public Overrides Function UnlockUser(userName As String) As Boolean
176:
177: End Function
178:
179: Public Overrides Sub UpdateUser(user As System.Web.Security.MembershipUser)
180:
181: End Sub
182: End Class
Методи пусті, бо утворюються вони самі, як тільки вводиш Public Overloads Overrides Sub Initialize і клацаєш Enter, всі необхідні методи студія утворить самостійно. А щоб написати ці декілька дуже важливих стрічок у цьому класі, я подивився у дебагері порядок виклику методів, та що до них приходить у параметрах, коли вони викликаються з середовища ASP.NET.
2. Доступ до даних зі сторінки Excel.
Сайтік, який я зробив, потребує доступа до даних на сторінці Excel. Для того, щоб досягнути це у середовище ASP.NET потрібно зробити наступні кроки:
- Поставити на машину MDAC, тобто на web-сервері повинні бути зареєстровані бібліотеки Microsoft.Jet.OLEDB.4.0 та Microsoft.ACE.OLEDB.12.0
- Прописати ці бібліотеки у конфіг таким чином:
- Ну и, звичайно, зробити якийсь код обробки SQL.
1: <?xml version="1.0"?>
2: <configuration>
3: ...
4: <connectionStrings>
5: <add name="Excel03ConString" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}; Extended Properties='Excel 8.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text'"/>
6: <add name="Excel07ConString" connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; Extended Properties='Excel 8.0;IMEX=1;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text'"/>
7: ...
8: </connectionStrings>
9: ...
Я зробив цей сайт таким чином, на першій формі лише завантажуються всі дані з листа Excel та зберігаються у Session. Тобто форма має лише три контрола.
Код форми набагато цікавіший, у ньому ви можете побачити весь механізм запросу до сторінок Excel за допомогою провайдерів Microsoft.Jet.OLEDB.4.0 та Microsoft.ACE.OLEDB.12.0.
1: Partial Class _Default
2: Inherits System.Web.UI.Page
3:
4: Public SessionName As String
5: Dim DT As Data.DataTable
6:
7: Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
8: If Not IsPostBack Then
9: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
10: Dim DT As Data.DataTable = DirectCast(Session("DT"), Data.DataTable)
11: GridView1.DataSource = DT
12: GridView1.DataBind()
13: End If
14: End If
15: End Sub
16:
17:
18: Protected Sub btnUpload_Click(sender As Object, e As System.EventArgs) Handles btnUpload.Click
19: If FileUpload1.HasFile Then
20: Try
21: SessionName = Guid.NewGuid.ToString
22: Dim FileName As String = SessionName
23: Dim Extension As String = IO.Path.GetExtension(FileUpload1.PostedFile.FileName)
24: Dim FolderPath As String = ConfigurationManager.AppSettings("FolderPath")
25: Dim FilePath As String = Server.MapPath(FolderPath + FileName)
26: FileUpload1.SaveAs(FilePath)
27: Import_To_Grid(FilePath, Extension)
28: Catch ex As Exception
29: lErr1.Text = ex.Message
30: End Try
31: End If
32: End Sub
33:
34: Private Sub Import_To_Grid(ByVal FilePath As String, ByVal Extension As String)
35: Dim conStr As String = ""
36: Select Case Extension
37: Case ".xls"
38: 'Excel 97-03
39: conStr = ConfigurationManager.ConnectionStrings("Excel03ConString").ConnectionString()
40: Case ".xlsx"
41: 'Excel 07
42: conStr = ConfigurationManager.ConnectionStrings("Excel07ConString").ConnectionString()
43: End Select
44: conStr = String.Format(conStr, FilePath)
45: Dim connExcel As New Data.OleDb.OleDbConnection(conStr)
46: Dim cmdExcel As New Data.OleDb.OleDbCommand()
47: cmdExcel.Connection = connExcel
48: 'Get the name of First Sheet
49: connExcel.Open()
50: Dim dtExcelSchema As Data.DataTable
51: dtExcelSchema = connExcel.GetOleDbSchemaTable(Data.OleDb.OleDbSchemaGuid.Tables, Nothing)
52: Dim SheetName As String = dtExcelSchema.Rows(0)("TABLE_NAME").ToString()
53: connExcel.Close()
54: 'Read Data from First Sheet
55: connExcel.Open()
56: cmdExcel.CommandText = "SELECT * From [" & SheetName & "]"
57: 'fill data to DataAdapter
58: Dim DA As New Data.OleDb.OleDbDataAdapter
59: DT = New Data.DataTable
60: DA.SelectCommand = cmdExcel
61: DT.Columns.Add("Num")
62: DA.Fill(DT)
63: connExcel.Close()
64: DT.Columns.Add("Result")
65: DT.Columns.Add("ResultDate")
66: '
67: For i As Integer = 0 To DT.Rows.Count - 1
68: DT.Rows(i)(0) = i
69: Next
70: 'Bind Data to GridView
71: 'GridView1.Caption = IO.Path.GetFileName(FilePath)
72: GridView1.DataSource = DT
73: GridView1.DataBind()
74: '
75: Session("SessionName") = SessionName
76: Session("DT") = DT
77: End Sub
78:
79: Protected Sub PageIndexChanging(ByVal sender As Object, ByVal e As GridViewPageEventArgs)
80: Dim FolderPath As String = ConfigurationManager.AppSettings("FolderPath")
81: Dim FileName As String = GridView1.Caption
82: Dim Extension As String = IO.Path.GetExtension(FileName)
83: Dim FilePath As String = Server.MapPath(FolderPath + FileName)
84: Import_To_Grid(FilePath, Extension)
85: GridView1.PageIndex = e.NewPageIndex
86: GridView1.DataBind()
87: End Sub
88:
89:
90: End Class
На цьому скрині DataTable можна побачити, що дані прочитались досить коректно, якщо не рахувати першу колонку, яку провайдер вважає за назву колонки.
А ось у зворотному напрямку - зі свого сайта в Excel я роблю звичайно через CSV:
1:
2: Partial Class Result
3: Inherits System.Web.UI.Page
4:
5: Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
6: If Not IsPostBack Then
7: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
8: lId.Text = Session("SessionName")
9: lRow.Text = DirectCast(Session("DT"), Data.DataTable).Rows.Count - 1
10: Else
11: Response.Redirect("Default.aspx")
12: End If
13: End If
14: End Sub
15:
16: Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click
17: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
18: Dim DT As Data.DataTable = DirectCast(Session("DT"), Data.DataTable)
19: Dim SessionName As String = Session("SessionName")
20: Dim Fname As String = "Report_" & Now.ToString("yyMMdd_HHmm", Globalization.CultureInfo.InvariantCulture)
21: '
22: Dim SB = New StringBuilder()
23: For Each OneRow As Data.DataRow In DT.Rows
24: SB.AppendLine(OneLineFromRow(OneRow))
25: Next
26: '
27: HttpContext.Current.Response.Clear()
28: HttpContext.Current.Response.ClearHeaders()
29: HttpContext.Current.Response.ClearContent()
30: HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" & Fname & ".csv")
31: HttpContext.Current.Response.ContentType = "text/csv"
32: HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding("Windows-1251")
33: HttpContext.Current.Response.Write(SB.ToString())
34: HttpContext.Current.Response.Flush()
35: HttpContext.Current.Response.End()
36: End If
37: End Sub
38:
39: Function OneLineFromRow(OneRow As Data.DataRow) As String
40: Dim CsvRow As New StringBuilder()
41: For j As Integer = 0 To OneRow.Table.Columns.Count - 1
42: If j <> 0 Then
43: CsvRow.Append(",")
44: End If
45: Dim ColumnValue As Object = OneRow(j)
46: If ColumnValue Is Nothing Then
47: CsvRow.Append("")
48: Else
49: Dim ColumnStringValue As String = ColumnValue.ToString()
50: Dim CleanedColumnValue As String = CleanCSVString(ColumnStringValue)
51: If ColumnValue.[GetType]() = GetType(String) AndAlso Not columnStringValue.Contains(",") Then
52: ' Prevents a number stored in a string from being shown as 8888E+24 in Excel. Example use is the AccountNum field in CI that looks like a number but is really a string.
53: CleanedColumnValue = CleanedColumnValue
54: End If
55: CsvRow.Append(cleanedColumnValue)
56: End If
57: Next
58: Return CsvRow.ToString
59: End Function
60:
61: Function CleanCSVString(input As String) As String
62: Return """" + input.Replace("""", """""").Replace(vbCr & vbLf, " ").Replace(vbCr, " ").Replace(vbLf, "") + """"
63: End Function
64: End Class
3. Трекінг почтових відправлень.
Ну й останнє питання цього невеличкого сайтіку, яким чином законектитися до сервісу трекінга почтових відправлень і як з ним працювати. Зверніть увагу, що це загальні засоби, точно таким чином можна працювати, наприклад, і з UPS World Wide.
По-перше, я поставив у своєї програмі лінк на зовнішні сервіс трекінга і отримав опис зовнішнього web-сервісу.
Подруге, я подивився на дані, яки мені видає сервіс.
А далі вже зробив ось таку форму, яка дозволяє оператору побачити корректність завантаження Excel-Файла та почати роботу з якогось місяця.
Самє код цієї форми звертається до почтового web-сервісу і робить трекінг почтових відправлень. Результат трекінгу код цієї форми вписує у заздалегідь підготовану колонку.
1:
2: Partial Class Result
3: Inherits System.Web.UI.Page
4:
5: Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
6: If Not IsPostBack Then
7: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
8: lId.Text = Session("SessionName")
9: lRow.Text = DirectCast(Session("DT"), Data.DataTable).Rows.Count - 1
10: Else
11: Response.Redirect("Default.aspx")
12: End If
13: End If
14: End Sub
15:
16: Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click
17: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
18: Dim DT As Data.DataTable = DirectCast(Session("DT"), Data.DataTable)
19: Dim SessionName As String = Session("SessionName")
20: Dim Fname As String = "Report_" & Now.ToString("yyMMdd_HHmm", Globalization.CultureInfo.InvariantCulture)
21: '
22: Dim SB = New StringBuilder()
23: For Each OneRow As Data.DataRow In DT.Rows
24: SB.AppendLine(OneLineFromRow(OneRow))
25: Next
26: '
27: HttpContext.Current.Response.Clear()
28: HttpContext.Current.Response.ClearHeaders()
29: HttpContext.Current.Response.ClearContent()
30: HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" & Fname & ".csv")
31: HttpContext.Current.Response.ContentType = "text/csv"
32: HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding("Windows-1251")
33: HttpContext.Current.Response.Write(SB.ToString())
34: HttpContext.Current.Response.Flush()
35: HttpContext.Current.Response.End()
36: End If
37: End Sub
38:
39: Function OneLineFromRow(OneRow As Data.DataRow) As String
40: Dim CsvRow As New StringBuilder()
41: For j As Integer = 0 To OneRow.Table.Columns.Count - 1
42: If j <> 0 Then
43: CsvRow.Append(",")
44: End If
45: Dim ColumnValue As Object = OneRow(j)
46: If ColumnValue Is Nothing Then
47: CsvRow.Append("")
48: Else
49: Dim ColumnStringValue As String = ColumnValue.ToString()
50: Dim CleanedColumnValue As String = CleanCSVString(ColumnStringValue)
51: If ColumnValue.[GetType]() = GetType(String) AndAlso Not columnStringValue.Contains(",") Then
52: ' Prevents a number stored in a string from being shown as 8888E+24 in Excel. Example use is the AccountNum field in CI that looks like a number but is really a string.
53: CleanedColumnValue = CleanedColumnValue
54: End If
55: CsvRow.Append(cleanedColumnValue)
56: End If
57: Partial Class Process
58: Inherits System.Web.UI.Page
59:
60: Public SessionName As String
61: Dim DT As Data.DataTable
62:
63: Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
64: If Not IsPostBack Then
65: SrvLogin.Text = System.Configuration.ConfigurationManager.AppSettings("ServiceLogin").ToString
66: SrvPass.Text = System.Configuration.ConfigurationManager.AppSettings("ServicetPass").ToString
67: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
68: SessionName = Session("SessionName")
69: lId.Text = SessionName
70: DT = DirectCast(Session("DT"), Data.DataTable)
71: lRow.Text = DT.Rows.Count - 1
72: ToRow.Text = 10
73: For j As Integer = 0 To DT.Columns.Count - 1
74: Dim ColumnValue1 As Object = DT.Rows(1)(j)
75: Dim ColumnValue2 As Object = DT.Rows(2)(j)
76: Dim ColumnValue3 As Object = DT.Rows(3)(j)
77: Dim ColumnStringValue1 As String = ColumnValue1.ToString()
78: Dim ColumnStringValue2 As String = ColumnValue2.ToString()
79: Dim ColumnStringValue3 As String = ColumnValue3.ToString()
80: If ColumnStringValue1.Length = 14 And ColumnStringValue2.Length = 14 And ColumnStringValue3.Length = 14 Then
81: ColumnNum.Text = j
82: ColumnNum.Enabled = False
83: End If
84: Next
85: Else
86: Response.Redirect("Default.aspx")
87: End If
88: End If
89: End Sub
90:
91: Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click
92: If Session("SessionName") IsNot Nothing And Session("DT") IsNot Nothing Then
93: DT = DirectCast(Session("DT"), Data.DataTable)
94: lErr1.Text = ""
95: Try
96: '
97: Dim X As New PostTrackingSingle.OperationHistory12Client
98: Dim PostRequest As New PostTrackingSingle.OperationHistoryRequest
99: Dim PostHeader As New PostTrackingSingle.AuthorizationHeader
100: PostHeader.login = SrvLogin.Text
101: PostHeader.password = SrvPass.Text
102: For i As Integer = CInt(FromRow.Text) To Math.Min(DT.Rows.Count - 1, CInt(ToRow.Text))
103: PostRequest.Barcode = DT.Rows(i)(CInt(ColumnNum.Text))
104: Try
105: Dim Y As PostTrackingSingle.OperationHistoryRecord() = X.getOperationHistory(PostRequest, PostHeader)
106: If Y IsNot Nothing Then
107: If Y.Count > 0 Then
108: Dim LastOper As PostTrackingSingle.OperationParameters = Y(Y.Count - 1).OperationParameters
109: If LastOper.OperType.Name = "Вручение" Then
110: DT.Rows(i)(DT.Columns.Count - 2) = "Вручение"
111: DT.Rows(i)(DT.Columns.Count - 1) = LastOper.OperDate.ToString(Globalization.CultureInfo.GetCultureInfo("RU-ru"))
112: Else
113: DT.Rows(i)(DT.Columns.Count - 2) = LastOper.OperType.Name
114: DT.Rows(i)(DT.Columns.Count - 1) = LastOper.OperDate.ToString(Globalization.CultureInfo.GetCultureInfo("RU-ru"))
115: End If
116: End If
117: End If
118: Catch ex As System.ServiceModel.FaultException
119: lErr1.Text = lErr1.Text & "<br>" & PostRequest.Barcode & ":" & ex.Message
120: End Try
121: 'PostRequest.Barcode = "14001207332324"
122: System.Threading.Thread.Sleep(CInt(Delay.Text) * 100)
123: Next
124: Catch ex As Exception
125: lErr1.Text = ex.Message
126: End Try
127: '
128: GridView1.DataSource = DT
129: GridView1.DataBind()
130: Else
131: lErr1.Text = lErr1.Text & "session experied"
132: End If
133:
134: End Sub
135:
136: Protected Sub PageIndexChanging(ByVal sender As Object, ByVal e As GridViewPageEventArgs)
137: GridView1.DataSource = DirectCast(Session("DT"), Data.DataTable)
138: GridView1.PageIndex = e.NewPageIndex
139: GridView1.DataBind()
140: End Sub
141: End Class
142:
143: Next
144: Return CsvRow.ToString
145: End Function
146:
147: Function CleanCSVString(input As String) As String
148: Return """" + input.Replace("""", """""").Replace(vbCr & vbLf, " ").Replace(vbCr, " ").Replace(vbLf, "") + """"
149: End Function
150: End Class
Цей код потім декілька разів поліпшувався, але це не важливо, принципова основа (1) роботи з сервісами, (2) з провайдером, та (3) з Excel, яку ви бачите на цієї сторінці, була зроблена за один день і вже більше не змінювалася.