ASP NET, NET Framework, MONO, SQL, Visual Studio | Professional Programming | Viacheslav Eremin
(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
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>  <MAIL ME>  <ABOUT ME>  < THANKS ME>
g2019507">