Exploring WinRT:

1. Windows.Storage namespace overview
2. File and Folder Pickers
3. Storage.AccessCache

So, because we are very restricted in accessing file system directly, sometimes we will need user’s help to access files and folder. There are three classes that give app access to the locations unavailable through Storage APIs - FileOpenPicker, FileSavePicker and FolderPicker - Windows 8’s replacement for the well know Open/Save dialogs. They represent UI elements that let users choose files and folders to open or file name and location to save a file.

FileOpenPicker

Using the picker, user can browse the file system and select one or multiple files to open. The following code was used to show this screen:

var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".jpg");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
filePicker.SettingsIdentifier = "picker1";
filePicker.CommitButtonText = "Open File to Process";

var files = await filePicker.PickMultipleFilesAsync();

To use the file picker, you have to add at least one file extension to FileTypeFilter collection, to indicate what file types are supported by the app. If FileTypeFilter is empty, file picker will throw “Unspecified error” exception on open. To show all files filter “*” should be used.

There is no way to open files without extension. FileTypeFilter accepts “.” as the filter but does not show anything when this filter is used.

All other properties are optional.

ViewMode property allows you to define how the items will be displayed. You can choose between Thumbnail and List, but be careful selecting the appropriate mode. User will not be able to switch it within the picker and may not be very happy if you will propose him to select an image using List view.

SuggestedStartLocation is used to suggest to the picker a folder to display. “Suggest” is a right word – this property is used only once, when the picker is opened for the first time. Next time when picker will be used, even if the application was restarted, the property is ignored and the last used folder is used as the start location.

Moreover, if you have more than one file picker in your app, all of them will share the same start location. If this behaviour is not what you expected, you can use SettingsIdentifier property to define a scope – all the pickers with the same SettingsIdentifier will share the same start location. The opposite is also true – locations for the pickers with the different identifiers are tracked separately.

CommitButtonText can be used to override standard “Open” text with something more specific.

And, finally, one of the two functions – PickMultipleFilesAsync or PickSingleFileAsync – should be used to show the configured picker to the user.

FileSavePicker

var fileSavePicker = new FileSavePicker();
fileSavePicker.FileTypeChoices.Add("Raw Images", new List { ".raw", ".dat" });
fileSavePicker.FileTypeChoices.Add(".jpg Image", new List { ".jpg" });
fileSavePicker.DefaultFileExtension = “.jpg”;
fileSavePicker.SuggestedFileName = “i08.jpg”;
filePicker.SettingsIdentifier = "picker1";

var fileToSave = await fileSavePicker.PickSaveFileAsync();

Similar to FileOpenPicker you have to add at least one file type to FileTypeChoices collection and the rest of the properties are optional.

If your app supports multiple file types, you can use DefaultFileExtension property to define a preferred one. Also the app can set SuggestedFileName property to suggest a full file name, so users don’t need to type it. Alternatively, if StorageFile object is already instantiated, you can use SuggestedSaveFile property

fileSavePicker.SuggestedSaveFile = file;

and it will automatically extract the default extension and suggested file name for you.

FileSavePicker.SettingsIdentifier works identical to FileOpenPicker.SettingsIdentifier and you can use the same identifiers to synchronize the open and save pickers.

ViewMode is not supported by FileSavePicker.

Method PickSaveFileAsync() returns StorageFile object linked with a newly created zero-sized file. If user selected existed file and allowed to override it, the file will be deleted and replaced with an empty one with the same name.

FolderPicker

There is nothing special about this dialog; the properties and usage are pretty similar to FileOpenPicker.

var folderPicker = new FolderPicker();
folderPicker.FileTypeFilter.Add(".jpg");
folderPicker.ViewMode = PickerViewMode.Thumbnail;
folderPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
folderPicker.SettingsIdentifier = "FolderPicker";

var folder = await folderPicker.PickSingleFolderAsync();
Exploring WinRT: Windows.Storage namespace overview

Exploring WinRT:

1. Windows.Storage namespace overview
2. File and Folder Pickers
3. Storage.AccessCache

Presenting Windows 8, Microsoft put a lot of emphasis on the new UI design and the users experience improvements. But for me, as the productivity and file management tools developer, UI-related changes, changes in the installation process, OS integration and file system access are equally important. In this post and the following posts I’d like to share my findings and thoughts related to these APIs.

As we already know, file system access for the WinRT apps is heavily restricted. The following diagram represents the big picture and was widely discussed during the BUILD sessions.

The full, unrestricted access is enabled for the app’s local folder only, located in C:\Users\<user_name>\AppData\Local\Packages\<package>. Within the local folder you can create, modify and delete files and folders without asking user’s permission. Local data access is provided using Windows.Storage.ApplicationData class:

var localFolder = ApplicationData.Current.LocalFolder;
var file = await localFolder.CreateFileAsync("data.txt");

If you are planning to access user’s documents, music, videos or any other data located in one of the system libraries, you have to indicate it through the app’s manifest. If app is trying to access a library item without specifying the corresponding capability in manifest, a runtime exception System.UnauthorizedAccessException will be thrown notifying you that access is denied.

Manifest editing is simple with new manifest designer integrated into Visual Studio 11:

Manifest editor

For the Music, Picture and Video libraries you are specifying the features you want in the Capabilities list and you are done. For the Documents Library things are more complicated. In addition to specifying Documents Library Access, you have to specify all the file types you want to be able to access using File Type Association declaration:

File Type Association

The reasons for this implementation are understandable, but it does not mean that I like it. I can imagine multiple scenarios when tools may need an access to the files with an unknown type. Yes, apps can use File Picker to access these files, but it requires interaction with user and in the certain cases prevents tasks automation.

Anyway, when manifest is configured properly, the library files and folders become available to the app with help of Windows.Storage.KnownFolders class:

var pictures = KnownFolders.PicturesLibrary;
var allPictures = pictures.GetFilesAsync();

Do you need a programmatic access to the files outside of the local folder or the libraries? Sorry, there is no API for this. File picker is your best friend here – let your user to choose files for you. There is only one exception – user’s Downloads folder.

To access Downloads folder your app does not need to specify any capabilities in the manifest, but in return it has write-only access to the folder. Windows.Storage.DownloadsFolder class is declared as static and exposes two methods only – CreateFolderAsync and CreateFileAsync. Of course, once your app created a new file (folder) and retrieved StorageFile (StorageFolder) object, it has full access to this item. But as soon as the object is disposed, the newly created files and folders become unavailable for you.

var folder = DownloadsFolder.CreateFolderAsync("New Folder");
// working with the folder ...

And last thing to overview is the application’s installation folder. This folder is located in C:\Users\<user_name>\AppxLayouts\ and, surprisingly, is read/write accessible via Windows.ApplicationModel.Package class:

var installationFolder = Package.Current.InstalledLocation;
var newFolder = await installationFolder.CreateFolderAsync("Setup");
TechDays Canada 2010: My talk on Wednesday in Toronto

Updated 2011/03/30: CTTDNUG presentation source code

Updated 2010/11/03: Presentation slides, demo project

This week, on Wednesday the 27th and Thursday the 28th of October, the TechDays Canada 2010 will take place in Toronto and I will be presenting a session on Wednesday the 27th at 2:20pm.

The talk is called “Some Behind-the-Scenes Details about WPF MVVM Frameworks” and is about the Model-View-ViewModel pattern implementation details. Here’s the abstract:

Currently MVVM is a pattern of choice among WPF community but as any pattern, it allows different interpretations and implementations. As a result, we have multiple MVVM frameworks and a variety of ways to solve the common pattern-related problems. Some of the frameworks are lightweight, some are heavy but usually every of them will miss at least one nice feature you want to have. This session proposes to explore different approaches used by the frameworks to perform the common tasks. If you want to have a MVVM foundation fully satisfy your project needs, this session can be a good start point for you. During the session, we will talk about different ways to bind the presentation layers, to discover ViewModels and make them blendable.

Below you can find a list of the described patterns with the names of the framework where they are used:

1. ViewModelLocator

MVVM Light Toolkit (Laurent Bugnion)

2. Attached Behaviors and MVVM

nRoute (Rishi)

JulMar MVVM Helpers + Behaviors (Mark Smith)

3. Using attached properties for ViewModel instantiation

MEFedMVVM (Marlon Grech)

Cinch (Sacha Barber)

4. Conventional binding, handling View lifecycle events from ViewModel

Caliburn.Micro (Rob Eisenberg)

5. Handling dialogs as services

Onyx (William E. Kempf)

6. ViewModelBase optimizations

ViewModelSupport (Brian Genisio)

Additional Resources

Паттерн Dependency Injection и введение в Ninject – DI фреймворк для .NET

В статье показывается пример тесно связанных классов, проводиться их рефакторинг с реализацией паттерна Dependency Injection (внедрение зависимости) и демонстрируется применение фреймворка Ninject, облегчающего внедрение зависимостей.

public class Engine
{
   public double GetSize()
   {
      return 2.5; // in liters
   }
}
 
public class Car
{
   private readonly Engine _engine;
 
   public Car()
   {
      _engine = new Engine();
   }
 
   public void GetDescription()
   {
      Console.WriteLine(“Engine size: {0}”, _engine.GetSize());
   }
}
 
class Program
{
   static void Main()
   {
      Car car = new Car();
      car.GetDescription();
   }
}

Каждый из нас писал подобный код хотя бы раз в жизни. А те, в чьи обязанности входит проверка кода начинающих программистов, могут видеть это достаточно часто. С синтаксической и логической точек зрения в нем нет ничего криминального. Код отлично отработает, выполнив все от него ожидаемое, и в нем абсолютно ничего не надо трогать, если это часть программы состоящей из пяти классов. Вопросы возникают, когда такой код появляется в реальном проекте, насчитывающем десятки классов, имеющем длинный жизненный цикл и большую вероятность изменения пользовательских требований, способа хранения данных или поддерживаемого оборудования.

Чем же он плох? Если кратко, то зависимостью конкретного класса Car от конкретного класса Engine. Представим, что конструктор класса Engine измениться – в этом случае придется менять и Car. Или, к примеру, появиться еще один двигатель. И что бы машина смогла его использовать, опять-таки, понадобиться изменить класс Car. Кроме того, подобная жестко запрограммированная зависимость снижает тестируемость классов – класс Car невозможно протестировать отдельно от Engine или заменить Engine на ложный объект, для симуляции непредвиденных обстоятельств.

Что же можно сделать для улучшения кода? Первое – ввести интерфейс IEngine, который будет реализовываться классом Engine.

public interface IEngine
{
   double GetSize();
}
 
public class Engine : IEngine
{
   public double GetSize()
   {
      return 2.5; // in liters
   }
}

Далее, изменить класс Car, что бы вместо класса Engine в нем использовался интерфейс IEngine. И второе, не менее важное изменение – класс Car не должен создавать двигатель сам, теперь конструктор получает ссылку на объект, реализующий интерфейс IEngine.

public class Car
{
   private readonly IEngine _engine;
 
   public Car(IEngine engine)
   {
      _engine = engine;
   }
 
   public void GetDescription()
   {
      Console.WriteLine(“Engine size: {0}L”, _engine.GetSize());
   }
}

И последнее, что необходимо сделать – это изменить функцию Main.

class Program
{
   static void Main()
   {
      IEngine engine = new Engine();
      Car car = new Car(engine);
 
      car.GetDescription();
   }
}

Получившееся в результате решение легче расширяемо, более тестируемо и является примером реализации паттерна Dependency Injection (внедрение зависимости) – зависимость машина-двигатель конфигурируется не внутри класса, а двигатель, созданный вне класса, внедряется в него.

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

Ninject

Основную идею использования DI фреймворков для создания объектов можно описать так: “Мне нужен объект класса A, создай его, и меня не интересует, что и как ты для этого будешь делать”. И вот как будет выглядеть создание машины с использованием Ninject:

class Program
{
   static void Main()
   {
      // Ninject Initialization
      IKernel ninjectKernel = new StandardKernel( new MyConfigModule() );
 
      // Using Car
      Car car = ninjectKernel.Get();
      car.GetDescription();
   }
}

Что такое ninjectKernel станет понятно чуть позже, а сейчас стоит обратить внимание на отсутствие любого упоминания IEngine или Engine. Благодаря предварительной конфигурации Ninject знает, что машине требуется двигатель и когда его просят создать новый экземпляр класса Car, он самостоятельно создает Engine и передает его в конструктор Car. Таким образом, все что требуется – это запросить класс. Все зависимости, необходимые для его создания или работы, DI фреймворк разрешит самостоятельно. Если, конечно, он был предварительно правильно сконфигурирован.

Ninject можно или загрузить с сайта Ninject.org в виде стабильной версии, или взять в виде актуальных исходных файлов из репозитория. Я рекомендую воспользоваться вторым способом, так как версия, находящаяся в репозитории, поддерживает несколько новых возможностей, в том числе код для интеграции с ASP.NET MVC.

Для начала работы с Ninject, в проект необходимо добавить ссылку на сборку Ninject.Core.dll, реализующую базовые возможности фреймворка. Второй шаг – конфигурирование. К сожалению, Dependency Injection – это не магия и что бы Ninject знал, каким образом разрешать зависимости, он должен быть проинструктирован. Для нашей программы необходимы только две инструкции:

Bind().To();
Bind().ToSelf();

В то время как многие DI фреймворки полагаются на конфигурационные XML файлы, Ninject имеет простой, интуитивно понятный API для задания зависимостей, использующий привычный синтаксис языка и позволяющий задействовать все возможности IDE.

Первая инструкция связывает интерфейс IEngine с классом Engine таким образом, что всякий раз, когда Ninject обнаружит необходимость в объекте типа IEngine, то будет создан объект Engine. Вторая инструкция описывает желаемое поведение при запросе на создание экземпляра класса Car – необходимо создать этот экземпляр, все просто. На самом деле, вторая инструкция не обязательна – такое поведение реализуется фреймворком по умолчанию. При необходимости автосвязывание классов можно и отключить, и настраивать все самому.

Теперь возникает вопрос – а где выполнять конфигурирование? Конфигурирование выполняется в виртуальном методе Load класса, реализующего интерфейс IModule. Проще всего будет наследовать такой класс от класса StandardModule.

public class MyConfigModule : StandardModule
{
   public override void Load()
   {
      Bind().ToSelf();
      Bind().To();
   }
}

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

IKernel kernel = new StandardKernel(cfg1, cfg2, …);
Библиотека Code Contracts: контрактное программирование под .NET

Code Contracts library for .NET 3.5: introduction in Russian. Code Contracts provide a language-agnostic way to express coding assumptions in .NET programs. The contracts take the form of pre-conditions, post-conditions, and object invariants and act as checked documentation of your external and internal APIs.

Контрактное программирование – это метод проектирования программ, предполагающий четкое специфицирование интерфейсов и описание обязанностей компонентов системы при взаимодействии друг с другом.

Обычно, контракт включает три основные группы элементов:

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

На PDC2008 было анонсировано появление в .NET 4.0 набора функций реализующих поддержку контрактного программирования и входящих в новое пространство имен System.Diagnostics.Contracts. На практике это будет выглядеть так:

class Account
{
   public double Balance { get; set; }

   public void Deposit(double amount)
   {
      Contract.Requires(amount >=0);

      Balance += amount;
   }

   public void Withdraw(double amount)
   {
      Contract.Requires(amount > 0);
      Contract.Requires(amount <= Balance);

      Balance -= amount;
   }

   public Account Transfer()
   {
      Contract.Ensures(Balance == 0);
      Contract.Ensures(Contract.Result() != null);

      Account newAccount = new Account() {Balance = this.Balance};
      Balance = 0;
      return newAccount;
   }

   [ContractInvariantMethod]
   protected void ValidAccount()
   {
      Contract.Invariant(Balance >=0);
   }
}

Как можно увидеть, контракт реализуется при помощи функций, что сразу вызывает вопрос, почему? Гораздо красивее была бы объявление контракта отдельно от кода, например с помощью атрибутов. К сожалению, атрибуты, по утверждению разработчиков, не позволяют описать все сценарии использования контрактов. Была возможность передавать в атрибуты сложные выражения, но они не захотели дублировать функциональность синтаксического анализатора. Так же они не захотели добавлять эту функциональность напрямую в язык, так как при этом другие .NET-языки не смогли бы ею воспользоваться. Так что мы имеем набор из десятка функций и нескольких атрибутов, которые войдут в mscorlib.

Code Contracts library

.NET 4 пока что не вышел, но попробовать контрактное программирование можно уже сейчас, загрузив библиотеку Code Contracts для .NET 3.5 с сайта Dev Labs. Библиотека доступна в двух вариантах: VSTS Edition для владельцев Visual Studio Team System, в которой доступны все возможности и ее применение разрешено в коммерческих целях, и Standard Edition для всех версий Visual Studio, за исключением Express Edition. Эта версия лицензируется для академических целей и не включает проверки контрактов во время компиляции.

CodeContracts

При инсталляции, в систему добавляется библиотека Microsoft.Contracts, примеры и документация. Также, в Visual Studio инсталлятор добавляет в свойства проекта дополнительную страницу Code Contracts, на которой можно управлять поведением библиотеки. Для того, что бы начать работу с контрактами, в проект необходимо добавить ссылку на библиотеку Microsoft.Contracts.dll, расположенную в папке %PROGRAMFILES%/Microsoft/Contracts/PublicAssemblies.

Код, приведенный выше для примера, демонстрирует использование трех основных частей контракта: предусловий Contract.Requires в функциях Deposit и Withdraw, декларирующих, что они работают только с положительными суммами денег; постусловий Contract.Ensures в функции Transfer, которые заявляют, что в качестве результата функция должна вернуть новый счет и обнулить текущий; инварианта класса ValidAccount, утверждающего, что счет находиться в правильном состоянии, если его баланс больше или равен нулю.

Итак, контракт объявлен. Но что это нам дает? Что произойдет, если контракт будет нарушен, например, в случае такого вызова account.Deposit(-1000.0)? Это зависит от используемых настроек. Если включена статическая проверка контрактов, то уже на этапе компиляции будет выдано предупреждение о нарушении контракта. Если же включена только проверка контрактов во время выполнения, то, в простейшем случае, в момент вызова функции будет сгенерировано исключение ContractException. Если проверка отключена полностью, то никакой реакции не последует, так как в скомпилированном коде будут отсутствовать любые проверки.

Дополнительно, библиотека позволяет достаточно гибко менять параметры runtime-проверки контрактов. Во-первых, можно задать какие именно части контракта необходимо проверять, например, только предусловия. И, во-вторых, можно перехватить событие Contract.ContractFailed или задать свой класс, методы которого будут вызываться вместо генерации исключения. Таким образом, к примеру, можно автоматически протоколировать нарушения контракта перед завершением программы.

Далее коротко пройдемся по всем основным элементам контракта.

Предусловия

Декларируют условия, необходимые для работы метода, выражаются с помощью Contract.Requires() и обычно используются для проверки входящих параметров. Функция Requires()принимает в качестве параметра логическое выражение выражающее условие контракта. Так же существует перегруженная функция, принимающая в качестве второго параметра строку – сообщение, используемое при нарушении условия.

Contract.Requires(amount > 0, "Invalid amount");

Как уже упоминалось выше, в зависимости от настроек текущей конфигурации в скомпилированном коде проверок контракта может и не быть. Однако, если вы хотите, что бы проверка предусловия осуществлялась всегда, вне зависимости от настроек, то можно использовать функцию Contract.RequiresAlways(), которая будет работать даже при отключеннии проверок в настройках проекта.

Contract.RequiresAlways(x != 0);

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

if (условие) throw new...

то, добавив вызов Contract.EndContractBlock() после этих проверок, вы превратите их в предусловия. Аналогичное действие окажет и вызов Contract.Requires(). На выражения накладываются следующие ограничения – они не должны выполнять ничего кроме генерации исключения, оператор else не поддерживается.

Постусловия

Постусловия декларируют состояние, достигнутое после завершения работы метода. Простой пример постусловия:

Contract.Ensures(Balance == 0);

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

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

Так, для верификации возвращаемого функцией значения используется специальный метод Contract.Result(), где T – это тип возвращаемого функцией значения.

Contract.Ensures( Contract.Result() > 0 );

Метод Contract.OldValue(e) позволяет получить значение переменной e до начала работы метода. Существует несколько ограничений на применение OldValue, главное из которых – переменная должна существовать перед началом выполнения инструкций метода и ее значение должно быть вычисляемым. В качестве таких переменных, например, могут выступать свойства класса или входящие переменные метода.

Contract.Ensures(Contract.OldValue(i) < n);

Для проверки в постусловиях значений out-переменных используется метод Contract.ValueAtReturn(out T t)

public void TestOut (out int a)
{
   Contract.Ensures(Contract.ValueAtReturn(out a) == 8);
   a = 8;
}

Инварианты класса

Инварианты класса относятся ко всему экземпляру класса и декларируют условия, при которых объект находиться в “хорошем” состоянии.

[ContractInvariantMethod]
protected void ValidAccount()
{
   Contract.Invariant(Balance >= 0);
}

Объявления всех инвариантов помещаются в один метод класса, помеченный атрибутом ContractInvariantMethod. Этот метод не должен содержать никакого кода, кроме объявлений инвариантов и не может возвращать значения. Каждый инвариант задается вызовом метода Contract.Invariant(). Проверка инвариантов класса происходит в конце каждого public метода класса – если посмотреть IL-код программы, то можно увидеть, что в процессе постобработки в конец каждого такого метода добавляется вызов нашей функции, помеченной атрибутом ContractInvariantMethod.

Дополнительно, в любом месте программы можно использовать Contract.Assert() для проверки условия в этой точке.

Contract.Assert( _number > 0 );

В процессе выполнения программы, если выражение ложно, то произойдет вызов Debug.Assert, в противном случае не последует никаких действий.

Контракты для интерфейсов

Описанные выше методы декларации контракта отлично работают в случае с конкретным классом. Однако что нам делать, если возникнет необходимость задать контракт для интерфейса? Ведь компилятор C# не позволит добавить для интерфейса тело функции с вызовом методов Contract.Requires() или Contract.Ensures(). На помощь приходит вспомогательный класс и пара атрибутов – ContractClass и ContractClassFor.

[ContractClass(typeof(SavingAccount))]
interface IAccount
{
   int Balance { get; }
   void Deposit(int amount);
}

[ContractClassFor(typeof(IAccount))]
class SavingAccount : IAccount
{
   int IAccount.Balance
   {
      get
      {
         Contract.Ensures(Contract.Result() >=0 );
         return default(int);
      }
   }
   void IAccount.Deposit(int amount)
   {
      Contract.Requires(amount > 0);
   }
}

Для интерфейса создается вспомогательный класс, реализующий его и декларирующий контракт. Для установления связи между классом и интерфейсом используются атрибуты. Точно таким же способом можно объявить контракт для абстрактного метода, создав вспомогательного наследника и реализовав метод.

Поскольку статья задумывалась как введение в библиотеку Code Contracts, то я не стал описывать некоторые нюансы ее использования и методы, используемые в специальных случаях – с ними вы можете познакомиться в достаточно подробном документе, идущем вместе с библиотекой. Так же, для начала, может быть интересным видео с одним из разработчиков библиотеки, доступное на сайте Dev Labs.

Next posts