| Viacheslav Eremin | Professional Programming, Visual Studio, Visual Basic, Vb.Net, C#, Sql Server, Asp, Asp Net Classic, Asp Net Mvc, Asp Net Core, Blazor .Net, Dot Net, Net Framework, Net Core
(MVC) MVC (2011 год)

Курс валют на сайте

Практически на всех сайтах сегодня надо показывать курс валют. В сущности, в стране, которую чекистская военная хунта сделала сырьевым придатком мировой экономики - ничего кроме сырья (и уголовных дел) не производится воовсе. И как всегда, в очередном моем сайте - все расчеты завязаны на курсе валют.

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


ШАГ1. Для начала создадим вот такую табличку и индекс к ней:


   1:  CREATE TABLE [dbo].[Curs](
   2:      [i] [int] IDENTITY(1,1) NOT NULL,
   3:      [CrDate] [datetime] NOT NULL,
   4:      [SetDate] [datetime] NOT NULL,
   5:      [Vname] [nvarchar](100) NOT NULL,
   6:      [Vnom] [int] NOT NULL,
   7:      [Vcurs] [money] NOT NULL,
   8:      [Vcode] [int] NOT NULL,
   9:      [VchCode] [nvarchar](3) NOT NULL
  10:  ) ON [PRIMARY]
  11:   
  12:  GO
  13:   
  14:  CREATE NONCLUSTERED INDEX [IX_Curs] ON [dbo].[Curs] 
  15:  (
  16:      [i] ASC
  17:  )
  18:  WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) 
  19:  ON [PRIMARY]
  20:   
  21:  GO 

Как вы понимаете, это биголейтсовский SQL-сервер. В данном сайте применение этого сервера вызвано не моей глубокой любовью к Биллу Гейтсу или неумением использовать SQLite, PostgreSQL, MySQL и другие сервера, а требованиями заказчика к сайту.

Итак, создадим процедурку для записи курса в табличку. Здесь может быть две политики - накапливть курс по дням и не накапливать. Люди, которые ничего не понимают в практическом удобстве эксплуатации сайтов - создают накопительную табличку с курсами по дням. Но этот детский сад давно прошел - и в моих сайтах таблички не разрастаются со временем. Поэтому вот такая процедура прогоняется ровно один раз:


   1:  ALTER procedure [dbo].[SetCurs]
   2:  @SetDate  datetime,
   3:  @Vname  nvarchar(100),
   4:  @Vnom  money,
   5:  @Vcurs  money,
   6:  @Vcode  integer,
   7:  @VchCode nvarchar(3)
   8:  as
   9:  INSERT INTO [FlySeason].[dbo].[Curs]
  10:             ([CrDate]
  11:             ,[SetDate]
  12:             ,[Vname]
  13:             ,[Vnom]
  14:             ,[Vcurs]
  15:             ,[Vcode]
  16:             ,[VchCode])
  17:       VALUES
  18:             (GETDATE()
  19:             ,@SetDate
  20:             ,@Vname
  21:             ,cast(@Vnom as integer)
  22:             ,@Vcurs
  23:             ,@Vcode 
  24:             ,@VchCode)
  25:  GO 

А после первого прогона эта процедура становится вот такой:


   1:  ALTER procedure [dbo].[SetCurs]
   2:  @SetDate  datetime,
   3:  @Vname  nvarchar(100),
   4:  @Vnom  money,
   5:  @Vcurs  money,
   6:  @Vcode  integer,
   7:  @VchCode nvarchar(3)
   8:  as
   9:  --INSERT INTO [FlySeason].[dbo].[Curs]
  10:  --           ([CrDate]
  11:  --           ,[SetDate]
  12:  --           ,[Vname]
  13:  --           ,[Vnom]
  14:  --           ,[Vcurs]
  15:  --           ,[Vcode]
  16:  --           ,[VchCode])
  17:  --     VALUES
  18:  --           (GETDATE()
  19:  --           ,@SetDate
  20:  --           ,@Vname
  21:  --           ,cast(@Vnom as integer)
  22:  --           ,@Vcurs
  23:  --           ,@Vcode 
  24:  --           ,@VchCode)
  25:  UPDATE [FlySeason].[dbo].[Curs]
  26:     SET [CrDate]  = GETDATE()
  27:        ,[SetDate] = @SetDate
  28:        ,[Vcurs]   = @Vcurs
  29:  WHERE  [VchCode] = @VchCode
  30:  GO

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


   1:  CREATE procedure [dbo].[GetCurs]
   2:  @Code nvarchar(3)
   3:  as
   4:  select top(1) * from [dbo].[Curs] 
   5:  where VchCode=@Code
   6:  order by i desc

Это все что нам нужно на уровне SQL. Там у нас будут данные, которые вы видите на табличке ниже и мы можем их читать процедурой GetCurs и обновлять процедурой SetCurs.



ШАГ2.Теперь нужно выбрать метд доступа к базе. Ну в принципе я практикую множество методов, самый на мой взгляд полезный - моя собственная универсальная обвязка, позволяющая обращаться к любому SQL-серверу, минуя сервисы, предоставляемые Биллом Гейтсом - вот она для MySQL. Впрочем я иногда пользуюсь LINQ и другими чудо-сервисами, написанными индусами по заказу Билла Гейтса. В этом проекте я уже начал все делать на LINQ TO SQL.

Итак, делаю два клика мышкой и перетаскиваю обе процы (GetCurs и SetCurs) на панель Linq to sql. Студия вычитывает типы параметров этих процедур и создает враппер, который будет мне давать в подсказке точные типы параметров для вызова этих процедур.



ШАГ3.Теперь создадим клиента к любому web-сервису, который транслирует в интернет курс валют. О клиентах к веб-сервисам у меня на сайте много написано, есть и мой собственный альтернативный микрософтовскому клиент. У меня на сайте немало написано и как самому создать такой же web-сервис, какой работает на сервере центробанка. Но в данном случае - это простейший коммерческий сайт и задача состоит в том, чтобы решить всю эту проблему за минимальное количество кликов мышкой. Получится за сто кликов - отлично. А если за пятьдесят - еще лучше.

Поэтому тыкаем в студии добавление ссылки на Web-сервис центробанка РФ.



И делаем тестик в одну строку.



Упс, все работает. Теперь ШАГ4. - делаем наш основной метод на 10 строчек, который будет сохранять курс в базу.


   1:  Public Class ReadCurs
   2:      Public Sub GO()
   3:          Dim DB2 As New FlySeasonDataContext
   4:          Try
   5:              Dim Curs As New CursValut.DailyInfoSoapClient
   6:              Dim LatestDateTime As Date = Curs.GetLatestDateTime
   7:              Dim X As Data.DataSet = Curs.GetCursOnDate(Now)
   8:              Dim DB1 As New FlySeasonDataContext
   9:              For Each One As Data.DataRow In X.Tables(0).Rows
  10:                  DB1.SetCurs(LatestDateTime, One(0).ToString.TrimEnd, One(1), One(2), One(3), One(4).ToString.TrimEnd)
  11:              Next
  12:          Catch ex As Exception
  13:              DB2.SaveLoadError("Curs " & ex.Message)
  14:          End Try
  15:      End Sub
  16:  End Class

ШАГ5. Теперь надо вызывать обновление курса валют периодически (не реже одного раза в сутки - лучше раз в час). Как делаются периодические задачки - я описывал на своем сайте множество раз, например вот так Реализация таймаута на динамически создаваемых SQL JOB, вызывающих SQL CLR сборку. Но в этом сайте заморачиваться нет необходимости - создаем периодическую задачу в самом найпростейшем варианте. Добавляем к проекту Global.ASAX и вносим в него вот такой копеечный код на 10 строчек:


   1:  <%@ Application Language="VB" %>
   2:   
   3:  <script runat="server">
   4:   
   5:      Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
   6:          ' Code that runs on application startup
   7:          Dim GetCursThread As System.Threading.Thread = New System.Threading.Thread(AddressOf GetCursSub)
   8:          GetCursThread.Name = "GetCursThread (Started " & Now.ToString & ")"
   9:          Application("GetCursThread") = GetCursThread
  10:          Application("GetCursInterval") = System.Configuration.ConfigurationManager.AppSettings("GetCursInterval")
  11:          If System.Configuration.ConfigurationManager.AppSettings("GetCursThread") Then GetCursThread.Start()
  12:      End Sub
  13:      
  14:      Sub GetCursSub()
  15:          Dim X As New ReadCurs
  16:          Dim DB1 As New FlySeasonDataContext
  17:          While True
  18:              System.Threading.Thread.Sleep(CInt(Application("GetCursInterval")) * 3600000)
  19:              'диагностика фонового процесса
  20:              Dim ClearJobThread As System.Threading.Thread = CType(Application("GetCursThread"), System.Threading.Thread)
  21:              DB1.SaveLoadError(ClearJobThread.Name & " started at " & Now.ToString)
  22:              X.GO()
  23:          End While
  24:      End Sub
  25:      
  26:  </script>

В конфиге поведением этого потока управляет два параметра:


   1:  <configuration>
   2:      <appSettings>
   3:          <!-- Чтение курса валют -->
   4:          <add key="GetCursThread" value="True"/>
   5:          <!-- интервал перезапуска задачи чтение курса валют 1час -->
   6:          <add key="GetCursInterval" value="1"/>
   7:  ...

Вот протокол почасового считывания курса:



И наконец, последний ШАГ6 - используем данные о курсе валют. Понятно, что само по себе использование курса валют в разнообразных платежных шлюзах, да и вообще в банковских операциях - это тема совершенно необьятная. Поэтому я покажу самое минимально возможное использование полученного курса - просто отображение его на форме.

Для этого находим нужный контрол и вносим в него вот такой копеечный код на три строчки:


   1:  Partial Class Kurs
   2:      Inherits System.Web.UI.UserControl
   3:   
   4:      Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   5:          If Not IsPostBack Then
   6:              Dim DB1 As New FlySeasonDataContext
   7:              Dim EUR As Decimal = DB1.GetCurs("EUR")(0).Vcurs
   8:              Dim USD As Decimal = DB1.GetCurs("USD")(0).Vcurs
   9:              l_EUR.Text = EUR.ToString("N2")
  10:              l_USD.Text = USD.ToString("N2")
  11:          End If
  12:      End Sub
  13:  End Class



Ну вот собственно и все. Похоже в этом рецепте, как и во многих других своих других рецептах - уложился в сто кликов мышкой.



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21
Link to this page: http://www.vb-net.com/Curs/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>
g2019507">