Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. Show all posts

Tuesday, June 28, 2011

Будущее Silverlight

Очень странно наблюдать поднявшуюся в последний месяц истерию по поводу того, что Microsoft якобы “разочаровался в WPF/Silverlight” и планирует смену курса в сторону набирающего популярность HTML5. Тема вовсю обсуждается на форумах MSDN, в комментариях серьезных блоггеров, на Хабре и даже в твиттере. Несмотря на явную невозможность нативной разработки под Windows при помощи ыHTML5/JS, у этой истерии, безусловно, есть корни. Осенью прошлого года официальные лица Microsoft уже обронили несколько фраз о переосмыслении стратегии развития Silverlight, а в начале июня подлили масла в огонь, показав Windows 8 с возможностью разработки на HTML5/JS и ни словом не обмолвившись о Silverlight. Если погуглить по фразе “Windows 8 silverlight”, то можно найти кучу криков о смерти Silverlight и плач тысяч разработчиков, которые выбрали Silverlight своей основной платформой для разработки и теперь считают себя брошенными на произвол судьбы. Добил фанов технологии .NET Community Manager Pete Brown, который высказался ясно и в то же время очень неопределенно:

“You all saw a very small technology demo of Windows 8, and a brief press release. We’re all being quiet right now because we can’t comment on this. It’s not because we don’t care, aren’t listening, have given up, or are agreeing or disagreeing with you on something. All I can say for now is to please wait until September. If we say more before then, that will be great, but there are no promises (and I’m not aware of any plans) to say more right now. I’m very sorry that there’s nothing else to share at the moment. I know that answer is terrible, but it’s all that we can say right now. Seriously.”

Сентябрь, о котором идет речь – это конференция Build, на которой ожидается релиз Silverlight 5, Windows Phone 7 Mango, а также первые настоящие презентации Windows 8 с объяснениями дальнейшей стратегии компании.

Безусловно, можно подождать еще 2.5 месяца и узнать, какую роль Microsoft отводит для Silverlight в своей новой концепции. Но ждать еще долго, а некоторые решения нужно принимать уже сейчас. Попробуем разобраться сами.

Итак, что у нас есть из не очень хорошего:

  1. Microsoft, безусловно, немного разочарована скоростью распространения Silverlight и его положением на рынке. И хотя процент установки Silverlight в браузерах уже достаточно высок (на данный момент около 75%, http://www.riastats.com/), но он все равно еще недостаточен и не дает технологии стать по-настоящему популярной.
  2. Другая проблема Silverlight – его неполная кроссплатформенность. Поддержка Windows и Mac – это, конечно, где-то 90-95% рынка десктопов (а, может, и больше, если верить http://gs.statcounter.com/#os-ww-monthly-201005-201105), но с точки зрения разработки широкопользовательских веб-приложений остается непокрытым весь Linux’овый зоопарк. Не добавляет очков и слабая поддержка SEO.
  3. На мобильных платформах подержка Silverlight вообще стремится к нулю. Ни iOS, ни Blackberry, ни Android не поддерживают Silverlight и вряд ли будут стремиться к этому. Единственная платформа, где он поддерживается – это WP7, правда, не в браузере. Но доля WP7 на рынке мобильных устройств (http://itc.ua/news/gartner_android_yavlyaetsya_samoj_populyarnoj_os_dlya_smartfonov_53536) и количество заказов на разработку WP7 приложений пока настолько малы, что серьезно раздумывать о карьере разработчика мобильных приложений пока не получается.

В то же время несмотря на все эти недостатки Silverlight уже занял свою определенную нишу, где он очень силен, в первую очередь благодаря скорости разработки и возможностям, недоступным стандартному HTML/JS клиенту:

  1. Enterprise и LOB RIA приложения (нивелируются проблемы слабой кроссплатформенности и распространенности)
  2. веб-приложения, в которых пользователи готовы установить плагин ради получения доступа к продвинутым возможностям, а не уйти к конкурентам (не e-commerce)
  3. мультимедиа-приложения с красивой и сложной анимацией, поддержкой video streaming
  4. кроме того, Silverlight пока остается основной платформой для разработки под Windows Phone 7

С чем же связано то, что Microsoft, вложившая 4 года и миллионы долларов в разработку и продвижение кроссплатформенной .NET-технологии, потихоньку смотрит в сторону HTML5/JS? И что же все-таки будет с Silverlight дальше?

Во-первых, любой компании, которая производит ОС, важно привлекать как можно большее количество разработчиков на свою сторону. Silverlight и WPF требуют от не .NET-разработчиков изучения слишком многого. А возможность сделать пусть и простое, но все же приложение под Windows 8 на HTML5/JS – это шанс. Тем более, что Windows 8 позиционируется и как операционка для планшетов – а это очень перспективный рынок. Уверен на 99%, что в сентябре на Build будет сказано о полной поддержке WPF (а куда ж он денется?), а также Silverlight как минимум на уровне разработки таких же приложений, которые будут разрабатываться на HTML5/JS.

Во-вторых, есть ощущение, что Microsoft пойдет на еще один непопулярный, но очень важный с точки зрения развития своей мобильной платформы шаг – даст возможность разрабатывать нативные приложения на HTML5/JS в Windows Phone. Думаю, начиная с восьмой версии, чтобы поддержать версионирование, но, может, и в Mango (7.5) добавят. Криков о помощи будет еще больше, но Microsoft нужно догонять убегающие iOS и Android. Разработчики мобильных приложений под iOS и Android не торопятся переносить свои приложения под WP7 в том числе и потому, что это требует совсем других навыков. Если бы у Microsoft было хотя бы 40% рынка, они могли бы закрыть глаза на простоту разработки, но с текущими 6% им некуда деваться.

В-третьих, Silverlight никуда не уйдет из web’а в ближайшие 3-5 лет. Его доля будет по-прежнему неуклонно расти, приложения будут разрабатываться, но вот из своей ниши он вряд ли выйдет. Этому будет мешать развитие HTML5 и рост рынка веб-приложений под мобильные устройства. Конечно, Microsoft может попробовать разработать Silverlight-плагины для мобильных операционных систем и браузеров, но это огромные деньги, а эффекта практически не будет.

В поддержку Silverlight на нативном уровне верится еще меньше. Такое возможно лишь на Android, и то лишь благодаря Mono, который и сам находится в непонятном статусе. Еще возможно продвижение Silverlight на Symbian, благо с Nokia есть договор, но какой смысл? Ведь есть готовый WP7, который можно ставить на устройства. На фоне же прогнозов о росте использования мобильных веб-приложений и снижения нативной разработки (это банально намного проще и дешевле!) смысла вкладываться в эту сферу вообще нет.

Ну, и в-четвертых, отдельно стоит сказать пару слов о Silverlight vs. HTML5, вернее даже plugins (Flash/Silverlight) vs. HTML5 (это отдельная фишка: под угрозой HTML5 сейчас объединяются даже ранее враждовавшие разработчики Flash/Flex и Silverlight :)). На эту тему сломано уже очень много копий (почитайте отдельно, если вам интересно), но ясно одно: HTML5 не покрывает всех возможностей Silverlight и Flash/Flex, поэтому их рано списывать со счетов. Кроме того, как все правильно отмечают, плагины пополняются новой функциональностью быстрее, чем развивается HTML и обновляются версии браузеров. Если же отвечать на вопрос: что лучше использовать в качестве клиента в каждый конкретный момент времени, то советую почитать два отличных поста:

Лично я себя намного комфортнее чувствую в разработке обычных ASP.NET MVC приложений, чем Silverlight, но это не значит, что нет приложений, для которых использование Silverlight будет более выгодным или дешевым. Особенно если мы говорим о портировании WPF-приложений в веб.

А вы что думаете по всему этому поводу?

Sunday, March 13, 2011

Bing Maps на Windows Phone 7. Полные исходники

Я планировал сделать целую серию заметок о создании простого Bing Maps приложения на Windows Phone 7, но жизнь вносит свои коррективы. Большое количество работы, сдача сертификации Microsoft, а также планирование отпуска отбирают все свободное время. К тому же, судя по отсутствию комментариев, эта тема никого особо не трогает. Поэтому эта серия останется незавершенной, но я все-таки хочу выложить все исходники проекта – может, кому-то пригодятся для самостоятельного изучения.

Исходники лежат на Google Code. Вот ссылка на папку Downloads проекта: http://code.google.com/p/wp7-wikimapia-client/downloads/list.

Если будут вопросы по коду или теме в целом – обращайтесь.

Tuesday, February 1, 2011

Bing Maps на Windows Phone 7. Часть 2. Масштабирование карты

Первая часть серии была посвящена созданию простейшего Bing Maps приложения для Windows Phone 7. Во второй части мы рассмотрим улучшение контролов изменения масштаба карты (zoom) и коснемся интерфейса INotifyPropertyChanged.

Изменение ViewModel

Может быть, вы заметили, что в прошлой части мы установили свойству ZoomBarVisibility значение Visible. Стандартный Zoom Bar выглядит достаточно грубо, кроме того, отображается в нижней части карты, что не очень удобно. Поэтому мы его заменим на наш собственный.

Для начала устанавливаем свойству ZoomBarVisibility значение Collapsed (или просто удаляем его из списка свойств).

Далее нам нужно расширить наш MapViewModel, добавив туда свойство Zoom, которое будет источником данных для свойства ZoomLevel у контрола Map. Добавляем в MapViewModel свойство и некоторые константы для удобства:

private const double DefaultZoomLevel = 4.0;
private const double MaxZoomLevel = 21.0;
private const double MinZoomLevel = 3.0;
public double Zoom
{
    get { return zoom; }
    set
    {
        var coercedZoom = Math.Max(MinZoomLevel, Math.Min(MaxZoomLevel, value));
        if (zoom != coercedZoom)
        {
            zoom = value;
            NotifyPropertyChanged("Zoom");
        }
    }
}

Здесь вроде бы все понятно за исключением NotifyPropertyChanged. NotifyPropertyChanged – это метод-реализация интерфейса INotifyPropertyChanged. Этот интерфейс используется для оповещения классов, которые привязываются (binding) к источнику данных, об изменениях в этом источнике. В нашем случае контрол Map нашей View будет таким образом оповещаться об изменениях в свойстве Zoom.

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

Добавляем в папку ViewModel проекта новый класс BaseViewModel, который будет выглядеть следующим образом:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null && !String.IsNullOrEmpty(propertyName))
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

И наследуем класс MapViewModel от BaseViewModel:

public class MapViewModel : BaseViewModel

Работа с представлением

Теперь нам нужно перейти во View и привязать свойство ZoomLevel контрола Map к свойству Zoom модели представления:

ZoomLevel="{Binding Zoom, Mode=TwoWay}"

Добавляем кнопки для масштабирования карты внутрь <canvas>:

<Button x:Name="ButtonZoomIn" 
    BorderThickness="0" Margin="8,200,0,0" Padding="0"
    HorizontalAlignment="Left" VerticalAlignment="Top" 
    Width="72" Height="72"
    Click="ButtonZoomIn_Click">
        <Image Source="Images/Menu/ZoomIn_White.png" />
</Button>
<Button x:Name="ButtonZoomOut" 
    BorderThickness="0" Margin="8,280,0,0" Padding="0"
    HorizontalAlignment="Left" VerticalAlignment="Top" 
    Height="72" Width="72"
    Click="ButtonZoomOut_Click">
        <Image Source="Images/Menu/ZoomOut_White.png" />
</Button>

Соединяем все вместе

Теперь нжуно реализовать обработку нажатий на кнопки. Для этого добавляем обработчики событий для кнопок, которые будут изменять свойство Zoom модели представления, в code-behind файл MainPage.xaml.cs:

private void ButtonZoomIn_Click(object sender, RoutedEventArgs e)
{
    Model.Zoom++;
}

private void ButtonZoomOut_Click(object sender, RoutedEventArgs e)
{
    Model.Zoom--;
}

Добавляем свойство Model в тот же code-behind файл:

protected MapViewModel Model
{
    get { return (MapViewModel)Resources["ViewModel"]; }
}

Это свойство сделано для удобства доступа к ViewModel, которая зарегистрирована как ресурс представления. Таким образом мы можем вызывать какие-нибудь методы или устанавливать свойства ViewModel.

Если говорить строго, то написание логики представления (а в нашем случае это обработка событий и устновка свойства Zoom) – это уже отход от правильной реализации паттерна MVVM. Но в то же время, code-behind страницы – это все еще View, поэтому мы можем сами решать, как оповещать наш ViewModel о событиях UI. Поэтому для начальной реализации приложения мы будем использовать code-behind страницы как прокси к ViewModel для упрощения реализации. В реальном же приложении нам нужно было бы использовать т.н. команды для привязки событий ко View, а не обычные обработчики. Но поскольку Silverlight до сих пор не обзавелся официальной поддержкой команд (за исключением интерфейса ICommand), а писать свои с нуля мы еще не готовы, то пока что отложим этот вопрос на будущее. Если кому-то интересно узнать больше уже сейчас, вот несколько ссылок:

http://weblogs.asp.net/nmarun/archive/2009/12/02/using-icommand-silverlight-4.aspx
http://johnpapa.net/silverlight/5-simple-steps-to-commanding-in-silverlight/
http://blogs.southworks.net/jdominguez/2008/08/icommand-for-silverlight-with-attached-behaviors/
http://houseofbilz.com/archives/2009/05/22/adventures-in-mvvm-commands-in-silverlight/

Добавляем картинки

Итак, логика готова. Нам осталось лишь добавить картинки для кнопок. Для этого создаем папку Images\Menu в проекте и добавляем туда файлы ZoomIn_White.png и ZoomOut_White.png. Скачать все файлы картинок, включая эти две, можно отсюда. Напоследок нам нужно открыть окно Properties для каждой из этих картинок и установить там свойство Build Action в Content вместо Resource. Этим мы убиваем двух зайцев: уменьшаем размер сборки, тем самым сокращая время загрузки приложения, и упрощаем доступ к файлам из приложения.

Запускаем приложение и видим, что у нас появились кнопки масштабирования. Их можно покликать – они работают :)

В следующей части мы реализуем получение нашего положения в пространстве при помощи GeoLocation API и научимся центрировать карту в это положение.

Вся серия:

Часть 1. Введение
Часть 2. Масштабирование карты
Часть 3. Полные исходники

Sunday, January 30, 2011

Bing Maps на Windows Phone 7. Часть 1. Введение

Эта статья содержит примеры кода, подсвеченные с помощью JS SyntaxHighlighter, который почему-то не отрабатывает в Google Reader, а возможно и в других RSS ридерах. Чтобы нормально увидеть код, вам придется перейти в блог. Извините за неудобство.

Недавно я делал code session на встрече харьковской UNETA на тему создания картографического приложения для Windows Phone 7. По моим субъективным ощущениям все прошло неплохо, слушатели помогали мне в написании кода, активно задавали вопросы и поправляли меня, когда я где-нибудь лажал :), а также стойко терпели технические проблемы, связанные со взаимной нелюбовью моего ноутбука и местного проектора, за что им отдельное спасибо. Так как тема программирования под Windows Phone сейчас интересна многим людям, хотелось бы также выложить материалы этого code session в блог.

Этой статьей я начинаю серию, посвященную созданию простенького картографического приложения на Silverlight с использованием Bing Maps. В процессе написания приложения я иногда буду уходить в теорию, чтобы пояснить те или иные детали. Итак, приступим.

Требования

Прежде чем начинать писать приложение, необходимо определиться что мы, собственно говоря, хотим написать. Наше приложение будет отображать текущее местонахождение человека, а также показывать положение различных объектов вокруг него: кафе, гостиниц, магазинов, банков, туристических мест, ночных клубов и прочего добра. По идее, оно должно помогать людям ориентироваться в малознакомом или даже родном городе. Если собрать все требования в кучку, то мы получим следующий набор функций приложения:

  1. отображение карты
  2. определение текущего местоположения, центрирование карты
  3. отображение различных объектов вокруг текущего местоположения
  4. отображение деталей объекта при клике на нем
  5. фильтрация объектов по типам

При этом мы попытаемся реализовать приложение в более-менее правильном стиле, с использованием паттерна MVVM.

Начнем с создания проекта и отображения простой карты.

Создание проекта

Перед тем, как начать программировать для Windows Phone 7, вам нужно убедиться, что у вас есть вся инфраструктура:

  • Visual Studio 2010 (есть бесплатная версия VS2010 Express for Windows Phone)
  • Windows Phone Developer Tools (Silverlight for Windows Phone, эмулятор, библиотеки и т.д.)
  • Bing Maps Silverlight control for Windows Phone
  • (опционально) XNA Game Studio 4.0
  • (опционально) Expression Blend (есть бесплатная версия Blend for Windows Phone)

Все это добро бесплатно и его можно скачать с сайта http://create.msdn.com/en-us/home/getting_started. После того, как установите основной пакет, не забудьте также установить October 2010 update to the Windows Phone Developer Tools.

Вообще, конечно, радует, что Microsoft решила сделать все инструменты для разработки WP7 приложений бесплатными. Но это не подарок на Новый год, а простой маркетинг: нужно привлекать программистов на новую платформу, чтобы догнать уходящий поезд, на котором дружно едут iOS и Android.

Немного о платформе разработки

Как вы уже догадались, писать мы будем на Silverlight. Только не на обычном Silverlight 4, а на т.н. Silverlight for Windows Phone. Эта версия SL отличается от своего настольного брата немного урезанными возможностями и оптимизированной производительностью. В общем-то производительность для телефона – это все, потому что по сравнению с native-приложениями у нас и сам .NET довольно прожорливый, и тем более Silverlight.

Кроме программирования бизнес-приложений (и в более редких случаях игр) на SL, у нас также есть возможность программировать игры (и в более редких случаях бизнес-приложения) на XNA. XNA – это платформа и набор инструментов для разработки игр для Windows, Xbox, Zune и вот теперь еще Windows Phone 7.

image

Поддержка XNA в Windows Phone – это очень полезная вещь, т.к. разработчики игр под Xbox теперь могут использовать привычные инструменты и модель разработки для программирования игр под мобильную платформу, а также с меньшими трудозатратами перенести существующие игры на WP7.

Отображение карты

Вернемся к практике. После установки необходимых дополнений в Visual Studio появятся новые типы проектов. Поэтому идем в File -> New -> Project и создаем Windows Phone Application проект.

Начнем мы с отображения карты. Здесь все просто. Сначала добавим в проект reference на сборку Microsoft.Phone.Controls.Maps. Затем добавим namespace для Bing Maps контрола, а также сам контрол в XAML главной страницы приложения, попутно заменив основной Grid на Canvas, чтобы нам было проще позиционировать элементы в будущем:

xmlns:maps="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
<!--LayoutRoot is the root grid where all page content is placed-->
<Canvas x:Name="LayoutRoot">
    <Grid Background="Transparent" Height="768" Width="480">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <TextBlock x:Name="ApplicationTitle" Grid.Row="0"  Text="My Places" Style="{StaticResource PhoneTextNormalStyle}"/>

	<maps:Map Grid.Row="1" Name="mapPlace" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
            ScaleVisibility="Visible"
            ZoomBarVisibility="Visible"
            CopyrightVisibility="Collapsed">

            <maps:Map.Mode>
                <maps:AerialMode ShouldDisplayLabels="True" />
            </maps:Map.Mode>

        </maps:Map>

    </Grid>
</Canvas>

Свойства контрола ScaleVisibility, ZoomBarVisibility и CopyrightVisibility определяют видимость соответствующих стандартных элементов карты. Надо отметить, что стандартный Zoom Bar располагается снизу (что не всегда удобно) + выглядит очень плохо, поэтому немного позже мы его улучшим.

Запустим приложение в эмуляторе. Как видите, приложение показывает карту:

image

Если присмотреться, то можно заметить, что посередине экрана белым шрифтом написан следующий текст:

Invalid Credentials. Sign up for for a developer account.

Этот текст обозначает, что нам нужно получить Bing Maps Developer Account и сообщить о нем контролу карты. Для этого идем на http://www.bingmapsportal.com/, логинимся туда при помощи Live ID (или сначала регистрируем его), и затем создаем ключ при помощи пункта меню Create or view keys.

Для того, чтобы карта заработала, достаточно установить свойство CredentialsProvider контрола:

CredentialsProvider="AoYOaLG9nor0LXJzvYrL18U8URccNTyacL-qfGUMBdvFseoLbF384hct4JxGVvI9"

Напомню, что ключ у вас должен быть свой. Это не важно для тестового проекта, но не уверен, что не будет проблем в случае публикации вашего приложения на MarketPlace.

Однако мы же пытаемся все делать правильно, используя паттерн MVVM, не так ли? Поэтому данный способ не совсем для нас. Этот ключ – данные, а данные должны связываться с View (представление, наша страница) через ViewModel (модель представления), специальный объект, содержащий весь набор данных, необходимых View для работы, а также логику представления. Выглядеть это должно где-то так:

image

Дополнительную информацию по паттерну MVVM и его примеры для Silverlight можно прочитать на страничке MSDN и в статье в MSDN Magazine.

Итак, нам нужно сделать ViewModel класс и как-то привязать его к View. Создадим в проекте папку ViewModel, в которой будут лежать все модели представления, а следом класс MapViewModel, который будет связываться с представлением нашей главной страницы). На данном этапе класс будет выглядеть следующим образом:

public class MapViewModel
{
    private const string Id = "AoYOaLG9nor0LXJzvYrL18U8URccNTyacL-qfGUMBdvFseoLbF384hct4JxGVvI9";
    private readonly CredentialsProvider credentialsProvider = new ApplicationIdCredentialsProvider(Id);

    public CredentialsProvider CredentialsProvider
    {
        get { return credentialsProvider; }
    }
}

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

Далее привязываем MapsViewModel к представлению в XAML файле страницы. Добавляем namespace:

xmlns:model="clr-namespace:WP7Test.ViewModel"

Говорим нашей View, что ее ViewModel будем класс MapsViewModel, установив свойство PhoneApplicationPage.Resources (перед началом тега Canvas):

<phone:PhoneApplicationPage.Resources>
    <model:MapViewModel x:Key="ViewModel" />
</phone:PhoneApplicationPage.Resources>

Устанавливаем свойство DataContext у Canvas:

<Canvas x:Name="LayoutRoot" DataContext="{StaticResource ViewModel}">

Теперь, когда ViewModel привязан к представлению, можно связать установить свойство CredentialsProvider контрола Map через стандартный data binding:

CredentialsProvider="{Binding ViewModel.CredentialsProvider}"

Вот и все. Запускаем, и видим, что наше приложение больше не показывает белую строчку.

В следующей части мы рассмотрим кастомизацию Zoom Bar.

Вся серия:

Часть 1. Введение
Часть 2. Масштабирование карты
Часть 3. Полные исходники

Saturday, January 15, 2011

Создание картографического приложения на Silverlight для Windows Phone 7

В четверг, 20 января, буду делать доклад на встрече харьковской UNETA на вышеприведенную тему. Хотя это будет даже не доклад, а скорее code session с минимумом теории и максимумом программирования. Постараюсь за 40 минут показать, как создать картографическое приложение на Silverlight для Windows Phone 7. Приложение будет брать данные об объектах из Wikimapia по различным категориям и отображать их на карте (Bing Maps). Покажу как работать с geolocation services, обрабатывать различные состояния приложения, и многое другое. Постараюсь, чтобы все было true MVVM. Ну, или около того :) Отвечу на разные вопросы.

Встреча будет проходить в Харьковском национальном университете радиоэлектроники, пр. Ленина, 14 (ст.м. Научная) 334 ауд., 20 января 2011 г. в 18-30. Официальное оповещение: http://dev.net.ua/blogs/leshchinsky/archive/2011/01/14/UNETA2001201SilverlightWindowsPhone7.aspx

Пока не знаю, что получится, будет тестовый прогон нового формата. Надеюсь, будет не очень скучно :) Приходите.

Wednesday, March 11, 2009

Кеширование и Silverlight

На днях столкнулся на работе с интересной ситуацией, которая в который раз напомнила о том, что .NET веб-программирование - это не только ASP.NET, но еще и куча всего под ним, благодаря чему этот ASP.NET, собственно, и работает. И что знание одного лишь ASP.NET не делает вас настоящим веб-программистом. Нужно знать еще много чего, начиная от HTML/CSS/JS и вплоть до протокола HTTP (хотя бы в какой-то мере). Вот и в нашем случае для решения проблемы понадобились знания HTTP-кеширования...

HTTP-кеширование - это кеширование страниц и других запрашиваемых ресурсов на машине пользователя или промежуточных прокси-серверах. Делается это, естественно, для того чтобы не загружать их постоянно с сервера и таким образом уменьшить трафик и увеличить производительность приложения. Управление кешированием происходит при помощи HTTP-заголовков. Для управления кешированием используются следующие заголовки: Expires, Last-Modified/If-Modified-Since, ETag/If-None-Match, Cache-Control, Pragma, X-Cache (который не является стандартным HTTP-заголовком, но тем не менее используется веб-серверами и прокси-серверами вроде squid) и т.д.

Я бы не хотел сейчас останавливаться на описании всех этих заголовков: со многими из них вы уже знакомы. Всех заинтересовавшихся отправляю читать несколько интересных статей, а остальным расскажу про наш опыт, чтобы не наступили на те же грабли.

Итак, есть Silverlight-приложение, которое на веб-сервере представлено XAP-файлом. Наверно, вы в курсе, что во избежание постоянных загрузок этих иногда очень даже немаленьких файлов с сервера, XAP-файлы по умолчанию кешируются в браузере. Ну, как обычные ZIP-файлы, например. Так вот, заливаем мы обновленную версию XAP-файла на удаленный сервер, пробуем запустить с одного компьютера - приложение обновлено, с другого - нет, показывается старая версия (тут необходимо отметить, что компьютеры находятся в разных локальных сетях). Ну, закешировал браузер, с кем не бывает. Очищаем кеш в FF - не работает, по-прежнему старая версия. Делаем Ctrl-F5 в IE - то же самое. Никаких изменений. Чешем репу, пробуем еще раз. И еще раз. С разными вариациями. Лезем в гугл - гугл что-то говорит по поводу кеширования SL-приложений, что нужно настроить в IIS опцию не кешировать приложение (свойства XAP файла в IIS -> HTTP Headers таб -> "Enable Content Expiration" -> "Expire Immediately" с вариациями в зависимости от версии IIS). Пробуем - не получается. Похоже, придется все-таки включать голову. Берем Fiddler, запускаем, смотрим запросы на XAP-файл. Так и есть, берет из кеша браузера. Делаем Ctrl-F5 - запрос уходит, файл получен заново... но он старый! Быстро вспоминаем, где еще могут быть закешированы файлы - на прокси-серверах. Ага! Быстрая проверка с удалением файла на сервере, который тем не менее, отлично заново откуда-то загружается подтверждает теорию. HTTP-заголовки тоже ее подтвержают:

Date: Thu, 05 Mar 2009 09:08:19 GMT
Age: 454965

Значит, файл действительно закеширован на прокси-сервере. Заголовок X-Cache (если вам повезло и он есть) позволяет даже узнать на каком:

X-Cache: HIT from <domain.com>

Здесь <domain.com> - адрес нашего родного корпоративного проксика :) Дальше дело за малым - перенастроить squid, чтобы он не кешировал запросы с корпоративного staging-сервера - и готово. Или еще не готово?

Конечно, не готово. А если у клиента или его end-user'ов прокси-сервер тоже настроен таким же образом? С одной стороны, это не так страшно, если вы не собираетесь часто обновлять приложение, но с другой стороны наш случай показал, что простое обновление файла НЕ СБРАСЫВАЕТ кеш прокси-сервера! То есть браузер получает файл прямо из прокси, а тот даже думать не желает лезть за обновлением на веб-сервер. Почему? Так настроен Cache-Control, который, во-первых, public (то есть доступен для кеширования не только в браузере, но и на прокси-серверах), а во-вторых, не содержит опции по проверке обновления файла по умолчанию. Из этого следует, что в случае, если между приложением и клиентом находится кеширующий прокси, и вы обновили приложение, то пользователи не увидят его до тех пор, пока кеш прокси-сервера не сбросится. А это не всегда приемлемо.

Как же решить проблему раз и навсегда? Можно рубануть с плеча и поступить так, как советуют люди, установив опцию "Expire Immediately" для вашего XAP-файла в IIS. Но если вы сделаете это, то у вас КАЖДЫЙ запрос пользователя будет заканчивать перезагрузкой файла с сервера. Что при размере последнего больше 500 Кб-1 Мб равносильно самоубийству в особо извращенной форме для какого-нибудь вебдванольного сайта с большим количеством посещений. Есть ли способ гуманнее? Да, есть, хотя я еще и не пробовал его, поэтому действуйте на свой страх и риск. Поскольку IIS не дает нам сильно разбежаться в плане установки своих кастомных заголовков для файлов, то здесь в одном из ответов рассказывается, как сделать HTTP-хендлер, который будет устанавливать необходимые заголовки (как минимум Cache-Control: private для production и no-cache или даже no-store для девелоперских машин). К слову, это же поможет вам и в девелопменте, т.к. каждый раз давить Ctrl-F5 или очищать кеш в FF - это тоже не выход, на мой взгляд. Описывать реализацию не буду - думаю, сами справитесь да и время уже позднее :)

Удачи вам в Silverlight-девелопменте!