(MVC) MVC (2014)

<< назад    Сайт с Google-maps API, имперсонализацией и Dynamic LINQ Expression.



Этот мой сайт работает по следующему принципу. Фирма Форт-Нокс имеет постоянный прайс-лист на построенные обьекты и еженедельно рассылает по мылу предложения для риэлтеров в виде Word-таблички с хорошими скидками. Весь прайс лист (относительно редко) и горячие предложения со сниженными ценами, которые рассылают менеджеры в виде WORD-таблички, моими загрузчиками-конвертерами импортируются в базу. Владелец этого бизнеса также заключил множество договорв с другим фирмами-застройщиками и они высылали мне данные точно в формате ФортНокса и эти предложения тоже импортировались в общую базу.

Далее все обьекты отображаются на карте Google-maps, а также поисковый блок справа правильно формирует возможности поиска. То есть, например если проимпортированы все квартиры в подвальных помещениях, то границы поиска будут только минус первый этаж и этот комбобокс будет вообще недоступен. То есть границы работы поисковика формируютс по реально загруженным данным:



   1:    ALTER procedure[dbo].[GetPriceBound] 
   2:    @Complex as integer as
   3:   (
   4:    select 
   5:    MIN (Area) as Min_Area, MAX(Area) as Max_Area ,
   6:    MIN (TotalArea) as Min_TotalArea, MAX(TotalArea) as Max_TotalArea ,
   7:    MIN (EURO) as Min_EURO, MAX(EURO) as Max_EURO ,
   8:    MIN ([Floor]) as Min_Floor, MAX([Floor]) as Max_Floor ,
   9:    MIN (Rooms) as Min_Rooms, MAX(Rooms) as Max_Rooms 
  10:    from [FortNoks].[dbo].[Price]
  11:    Where ToComplex=@Complex
  12:    )


Соответственно, Application_Start вызывает это формирование границ поисковика:



   1:      Public Shared Sub GetGlobals()
   2:          Dim db1 As New FortNoksDataContext
   3:          HttpContext.Current.Application("PriceBound") = (From X In db1.PriceBounds Select X).First
   4:          HttpContext.Current.Application("PriceNotes") = (From X In db1.PriceNotes Select X).ToList
   5:          HttpContext.Current.Application("PriceViews") = (From X In db1.PriceViews Select X).ToList
   6:          HttpContext.Current.Application("SpecialPrice") = (From X In db1.Special1s Select X).ToList
   7:      End Sub

Качественный поиск и сортировка по разным параметрам - былы главной поставленной мне заказчиком задачей. Потому что на сайтах застройщиков, например Форт-Нокса, вообще ничего толком найти нельзя. Поэтому качественную динамическую сортировку в этом сайте я сделал в этом сайте на динамических выражениях LINQ:



   1:  Imports System.Linq.Dynamic
   2:  Imports System.Linq.Expressions
   3:   
   4:  Public Class Common
   5:   
   6:    Public Shared Function GetPrice(ByVal PRM As FormCollection, PageSize As Integer, PageNum As Integer) As System.Collections.Generic.List(Of Price1)
   7:          'Max_Area
   8:          'Max_EURO
   9:          'Max_Floor
  10:          'Max_Rooms
  11:          'Max_TotalArea
  12:          'Min_Area
  13:          'Min_EURO
  14:          'Min_Floor
  15:          'Min_Rooms
  16:          'Min_TotalArea
  17:          'PriceNotes
  18:          'PriceViews
  19:          'Sort1
  20:          'Sort4
  21:          Dim Filter As String = GetFilter(PRM)
  22:   
  23:          Dim db1 As New FortNoksDataContext
  24:          Dim Query = db1.Price1s.Where(Filter).OrderBy(PRM("Sort1") & "," & PRM("Sort4") & ",i").Skip(PageNum * PageSize).Take(PageSize)
  25:          'Response.Write(db1.GetCommand(Query))
  26:          Dim List = (From X In Query Select X).ToList
  27:          Return List
  28:      End Function
  29:   
  30:      Public Shared Function GetFilter(ByVal PRM As FormCollection) As String
  31:          Dim Filter As String = ""
  32:          If PRM IsNot Nothing Then
  33:              If PRM("ID") IsNot Nothing Then
  34:                  Filter &= "ToComplex=" & PRM("ID")
  35:              End If
  36:              If PRM("PriceViews") <> "-" Then
  37:                  If Filter <> "" Then
  38:                      Filter = Filter & " and "
  39:                  End If
  40:                  Filter &= "Views=""" & PRM("PriceViews") & """"
  41:              End If
  42:              If PRM("PriceNotes") <> "-" Then
  43:                  If Filter <> "" Then
  44:                      Filter = Filter & " and "
  45:                  End If
  46:                  Filter &= "Notes=""" & PRM("PriceNotes") & """"
  47:              End If
  48:              If PRM("Max_Area") <> "" Then
  49:                  If Filter <> "" Then
  50:                      Filter = Filter & " and "
  51:                  End If
  52:                  Filter &= "Area<=" & PRM("Max_Area")
  53:              End If
  54:              If PRM("Max_EURO") <> "" Then
  55:                  If Filter <> "" Then
  56:                      Filter = Filter & " and "
  57:                  End If
  58:                  Filter &= "EURO<=" & PRM("Max_EURO")
  59:              End If
  60:              If PRM("Max_Floor") <> "" Then
  61:                  If Filter <> "" Then
  62:                      Filter = Filter & " and "
  63:                  End If
  64:                  Filter &= "Floor<=" & PRM("Max_Floor")
  65:              End If
  66:              If PRM("Max_Rooms") <> "" Then
  67:                  If Filter <> "" Then
  68:                      Filter = Filter & " and "
  69:                  End If
  70:                  Filter &= "Rooms<=" & PRM("Max_Rooms")
  71:              End If
  72:              If PRM("Max_TotalArea") <> "" Then
  73:                  If Filter <> "" Then
  74:                      Filter = Filter & " and "
  75:                  End If
  76:                  Filter &= "TotalArea<=" & PRM("Max_TotalArea")
  77:              End If
  78:              If PRM("Min_Area") <> "" Then
  79:                  If Filter <> "" Then
  80:                      Filter = Filter & " and "
  81:                  End If
  82:                  Filter &= "Area>=" & PRM("Min_Area")
  83:              End If
  84:              If PRM("Min_EURO") <> "" Then
  85:                  If Filter <> "" Then
  86:                      Filter = Filter & " and "
  87:                  End If
  88:                  Filter &= "EURO>=" & PRM("Min_EURO")
  89:              End If
  90:              If PRM("Min_Floor") <> "" Then
  91:                  If Filter <> "" Then
  92:                      Filter = Filter & " and "
  93:                  End If
  94:                  Filter &= "Floor>=" & PRM("Min_Floor")
  95:              End If
  96:              If PRM("Min_Rooms") <> "" Then
  97:                  If Filter <> "" Then
  98:                      Filter = Filter & " and "
  99:                  End If
 100:                  Filter &= "Rooms>=" & PRM("Min_Rooms")
 101:              End If
 102:              If PRM("Min_TotalArea") <> "" Then
 103:                  If Filter <> "" Then
 104:                      Filter = Filter & " and "
 105:                  End If
 106:                  Filter &= "TotalArea>=" & PRM("Min_TotalArea")
 107:              End If
 108:          End If
 109:          If Filter = "" Then Filter = "1=1"
 110:          Return Filter
 111:      End Function


Кроме того, сайт имеет гигабайтную базу фотографий построенных апартаментов, которая конечно же не может уместиться непосредственно на WEB-сервере. Поэтому для доступа к фотографиям требуется имперсонализация учетной записи. Таким образом, сайт содеожит несколько небольших фрагментов кода, о которые есть смысл сказать хоть что-то. Импортер WORD-таблички со спецпредложениями, описанный здесь, код имперсонализации для доступа к удаленному от WEB-сервера рисурсу для того, чтобы забрать оттуда фотографии и отдать их потоку браузера. И код использующий GOGLE MAPS API, который мы рассмотрим чуть подробнее.


Контрол MAP.ascx, в котором содержится DIV map_canvas, вместо которого бужет вставлен фрейм с Google-картой, выглядит вот так:



   1:  <%@ Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl" %>
   2:   
   3:  <style type="text/css">
   4:  .poputMap {
   5:      height:500px;
   6:      position:relative;
   7:      z-index:1;
   8:      margin-top:-4px;
   9:      }
  10:   
  11:  </style>
  12:  <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
  13:  <div id="map_canvas" class="poputMap">
  14:  </div>
  15:  <script type="text/javascript" src="../../map.js" ></script>


Эта страничка содержит вызов библиотеки Google и моего нижеследующего скрипта, который вычитывает с сервера координаты загруженных в базу комплексов (домов) с обьектами продаваемой недвижимости (квартирыми).



   1:  var MyMap;
   2:   
   3:  function addmarker(id, city, name, geo1, geo2) {
   4:      var pos = new google.maps.LatLng(geo1, geo2);
   5:      var marker = new google.maps.Marker({
   6:          position: pos,
   7:          map: MyMap,
   8:          title: name + ' (' + city + ')'
   9:      });
  10:      google.maps.event.addListener(marker, 'click', function () {
  11:          window.location.href = '/Complex/Index/' + id;
  12:      });
  13:   
  14:  }
  15:   
  16:  function kurort_result(json_array) {
  17:      if (json_array.length) {
  18:          $.each(json_array, function (index, term) {
  19:              addmarker(term.ID, term.City, term.Name, term.Geo1, term.Geo2);
  20:          });
  21:      }
  22:  };
  23:   
  24:  function fill_kurort() {
  25:      $.ajax({
  26:          'url': '/GetComplex.ashx',
  27:          'dataType': 'json',
  28:          'type': 'GET',
  29:          'success': kurort_result
  30:      });
  31:  };
  32:   
  33:  function initialize() {
  34:      var myLatlng = new google.maps.LatLng(42.706407, 27.751808);
  35:      var myOptions = {
  36:          zoom: 13,
  37:          center: myLatlng,
  38:          mapTypeId: google.maps.MapTypeId.HYBRID
  39:      }
  40:      MyMap = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  41:   
  42:      fill_kurort();
  43:   
  44:  }
  45:   
  46:  google.maps.event.addDomListener(window, 'load', initialize);


Как видите, в этом jQuery-скрипте вообще ничего такого особенного нет, обыкновенный AJAX-вызов серверного хандлера GetComplex.ashx, содержащие координаты маркера. Маркер Гугловой карты формируется в строке 5, в строке 10 формируется URL сайта для перехода по клику на маркере.

А код хандлера GetComplex.ashx содержит просто обращение к базе и формирвоание JSON:



   1:  Imports System.Web
   2:  Imports System.Web.Services
   3:   
   4:  Public Class GetComplex
   5:      Implements System.Web.IHttpHandler
   6:   
   7:   
   8:      Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
   9:          'проверка JSON-форматирования 
  10:          'context.Response.ContentType = "application/json"
  11:          'context.Response.Charset = "utf-8"
  12:          'context.Response.Write("[""a"",""b"",""c""]")
  13:          'Exit Sub
  14:          '
  15:          Try
  16:              Dim DB1 As New FortNoksDataContext
  17:              Dim Result As New StringBuilder("")
  18:              Dim AllRecords = (From X In DB1.Complex1s Select X).ToList()
  19:              If AllRecords.Count > 0 Then
  20:                  Result.Append("[")
  21:                  For i As Integer = 0 To AllRecords.Count - 1
  22:                      Result.Append("{""")
  23:                      Result.Append("ID"":""")
  24:                      Result.Append(AllRecords(i).ID)
  25:                      Result.Append(""",""")
  26:                      Result.Append("City"":""")
  27:                      Result.Append(AllRecords(i).City_Name)
  28:                      Result.Append(""",""")
  29:                      Result.Append("Name"":""")
  30:                      Result.Append(AllRecords(i).Name.Trim)
  31:                      Result.Append(""",""")
  32:                      Result.Append("Geo1"":""")
  33:                      If AllRecords(i).Latitude Is Nothing Then
  34:                          Result.Append("0")
  35:                      Else
  36:                          Result.Append(AllRecords(i).Latitude.Trim)
  37:                      End If
  38:                      Result.Append(""",""")
  39:                      Result.Append("Geo2"":""")
  40:                      If AllRecords(i).Longitude Is Nothing Then
  41:                          Result.Append("0")
  42:                      Else
  43:                          Result.Append(AllRecords(i).Longitude.Trim)
  44:                      End If
  45:                      Result.Append("""},")
  46:                      Result.AppendLine()
  47:                  Next
  48:                  Result.Remove(Result.Length - 3, 3)
  49:                  Result.Append("]")
  50:              End If
  51:              context.Response.ContentType = "application/json"
  52:              context.Response.Charset = "utf-8"
  53:              context.Response.Write(Result.ToString)
  54:          Catch ex As Exception
  55:              context.Response.ContentType = "text/plain"
  56:              context.Response.Write(ex.Message)
  57:          End Try
  58:      End Sub
  59:   
  60:   
  61:      ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
  62:          Get
  63:              Return False
  64:          End Get
  65:      End Property
  66:   
  67:  End Class


Вот таким простым способом координаты из базы попадают на Гугловую карту. Аналогичным способом я делаю все свои сайты с Гугловыми картами, например вот этот:



Проекты нового вотпуска

Жаль, что этот интересный проект не развивался дальше. При разработке этого проекта качество поиска было и отображение на карте было первостепенной задачей, а улучшить дизайн предполагалось позднее (тем более сайт написан на MVC и это сделать совсем просто), но к сожалению, заказчик этого сайта бесследно пропал и развитие проекта было прекращено.




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/2014/pbg2010-site.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <MAIL ME>  <ABOUT ME>  < THANKS ME>