среда, 18 августа 2010 г.
Биндинг сложных объектов в ASP.NET MVC
подробнее
среда, 7 апреля 2010 г.
Создание OData API для StackOverflow включая XML и JSON за 30 минут
четверг, 18 марта 2010 г.
воскресенье, 14 марта 2010 г.
Введение в Managed Extensibility Framework
Оригинал: http://www.aspiringcraftsman.com/2008/10/introduction-to-managed-extensibility_799/
Введение
Обзор
Инфраструктура MEF позволяет приложению легко расширятся за счет возможности динамического связывания внутренних и подключенных (Add-in) компонентов вместе внутри контейнера, каталога и набора компонентов.Контейнер
Контейнер отвечает за управление процессом создания и построения зависимостей между компонентами. В фреймворке он представлен типом CompositionContainer.Этот тип реализует интерфейс ICompositionService, который может самостоятельно добавляться в контейнер для явного использования компонентами во время работы приложения.
Каталоги
- AssemblyCatalog1 - обеспечивает обнаружение компонентов в коллекции типов;
- TypeCatalog2 - обеспечивает обнаружение компонентов в сборке;
- DirectoryCatalog3 - обеспечивает обнаружение компонентов в каталоге файловой системы;
- AggregateCatalog4 - обеспечивает возможность комбинации множества каталогов в один составной каталог.
Компоненты
Пример приложения MefPad
Шаг 1 - Создание проекта и формы
- Создайте новый проект Windows Forms Application с именем "MefPad".
- Добавьте ссылку на сборку System.ComponentModel.Composition.dll.
- Переименуйте "Form.cs" в "MefPad.cs".
- Добавьте контрол MenuStrip пристыкованный к верху формы.
- Добавьте верхний пункт меню "File".
- Добавьте подпункт "Open" в меню "File".
- Двойным кликом по пункту "Open" создайте обработчик события "Click".
- Вернитесь в дизайнер формы и добавьте следующий подпункт "Save" в меню "File".
- Двойным кликом по пункту "Save" создайте обработчик события "Click".
- Вернитесь в дизайнер формы и добавьте контрол TextBox c именем "mainContentBox".
- Измените значение свойства Dock на "Fill".
На следующем рисунке изображен результат дизайна формы "MefPad".
Шаг 2 - Конфигурация MEF контейнера
- Добавьте следующий вызов Compose() в конструктор класса MefPad:
public MefPad()
{
InitializeComponent();
Compose();
}
- Добавьте пространство имен System.ComponentModel.Composition.
- Добавьте следующий метод:
{
var catalog = new DirectoryCatalog(".", "*Extensions.dll");
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
Этот метод использует DirectoryCatalog для поиска любых расширений MefPad. В данном случае каталог будет искать сборки в текущей директории запуска, имена которых оканчиваются на "Extensions.dll". Далее, создается экземпляр CompositionContainer c каталогом в качестве параметра конструктора. Затем в контейнер добавляется форма MefPad в качестве компонента. Это позволит контейнеру обнаруживать любые компоненты с атрибутами Export или Import в классе MefPad. И наконец, указываем контейнеру собрать все компоненты.
Шаг 3 - Объявление расширения
- Создадим новый интерфейс с именем IFilePersistenceExtension:
using System.IO;Этот интерфейс определяет типы которые будут использоваться классом MefPad для чтения и сохранения файлов на диск. Свойства Description и Extension будут использоваться для файлового диалога представленного пользователю, а метода Read() и Write() будут использоваться для открытия и сохранения соответственно.
namespace MefPad
{
public interface IFilePersistenceExtension
{
/// <summary>
/// Description of the file type.
/// </summary>
string Description { get; }
/// <summary>
/// The extension of the file type.
/// </summary>
string Extension { get; }
/// <summary>
/// Reads from an open stream.
/// </summary>
/// <param name="stream">An open <see cref="Stream"/></param>
/// <returns>character array of text read.</returns>
char[] Read(Stream stream);
/// <summary>
/// Writes to an open stream.
/// </summary>
/// <param name="stream">An open <see cref="Stream"/></param>
/// <param name="text">The text to be written to the stream</param>
void Write(Stream stream, char[] text);
}
}Шаг 4 - Создание и импорт
- Добавьте следующее свойство в класс MefPad:
[ImportMany()]
public List<IFilePersistenceExtension> FilePersistenceExtensions { get; set; }
Это свойство представляет собой коллекцию типов реализующих IFilePersistenceExtension которые будут представлены как типы файловых операций. Атрибут [Import] используется для индикации того что компонент MefPad имеет зависимость от типов реализующих интерфейс IFilePersistenceExtension. Во время обнаружения любых компонентов с контрактом данного типа в каталоге, контейнер будет добавлять экземпляры компонентов в коллекцию FilePersistenceExtension.Шаг 5 - Создание бизнес логики
- Добавьте следующий метод в класс MefPad:
T GetFileDialog<T>() where T : FileDialog, new()Этот метод обеспечивает настройку поведения при конфигурировании диалогов открытия и сохранения представленных пользователю. Метод ForEach() используется для добавления типов файлов в фильтр диалога.
{
var fileDialog = new T();
var fileTypesBuffer = new StringBuilder();
if (FilePersistenceExtensions != null)
FilePersistenceExtensions
.ForEach(x =>
fileTypesBuffer.Append(string.Format("{0}{1}|*{2}",
(fileTypesBuffer.Length == 0)
? null
: "|", x.Description,
x.Extension)));
fileDialog.Filter = fileTypesBuffer.ToString();
return fileDialog;
}
- Замените обработчики событий openToolStripMenuItem_Click и saveToolStripMenuItem_Click следующими методами:
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
Stream stream;
OpenFileDialog openFileDialog = GetFileDialog<OpenFileDialog>();
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
if ((stream = openFileDialog.OpenFile()) != null)
{
char[] content = FilePersistenceExtensions[openFileDialog.FilterIndex - 1].Read(stream);
mainContentTextBox.Text = new String(content);
stream.Close();
}
}
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
Stream stream;
SaveFileDialog saveFileDialog = GetFileDialog<SaveFileDialog>();
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
if ((stream = saveFileDialog.OpenFile()) != null)
{
FilePersistenceExtensions[saveFileDialog.FilterIndex - 1].Write(stream, mainContentTextBox.Text.ToCharArray());
stream.Close();
}
}
}
Эти методы обработчиков событий Click для пунктов меню "Open" и "Save" соответственно. Метод openToolStripMenuItem_Click вызывает метод Read() экземпляра IFilePersistenceExtension соответствующего выбранному пункту фильтра. Аналогично с методом saveToolStripMenuItem_Click вызывающего метод Write() экземпляра IFilePersistenceExtension соответствующего выбранному пункту фильтра.Шаг 6 - Создание Extension
- Создайте новый проект ClassLibrary с именем MefPadExtensions.
- Добавьте ссылку на проект MefPad.
- Добавьте ссылку на сборку System.ComponentModel.Composition.dll.
- В разделе "Build" настроек проекта измените свойство "Ouput path" на "..\MefPad\bin\Debug".
- Создайте новый класс TextFilePersistenceExtension:
using System.ComponentModel.Composition;Этот класс обеспечивает приложение MefPad возможностями по открытию и сохранению файлов.
using System.IO;
using MefPad;
namespace MEFPadExtensions
{
[Export(typeof(IFilePersistenceExtension))]
public class TextFileSaverExtension : IFilePersistenceExtension
{
public string Description
{
get { return "Text file"; }
}
public string Extension
{
get { return ".txt"; }
}
public char[] Read(Stream stream)
{
var streamReader = new StreamReader(stream);
string bytes;
try
{
bytes = streamReader.ReadToEnd();
return bytes.ToCharArray();
}
finally
{
streamReader.Close();
stream.Close();
}
}
public void Write(Stream stream, char[] text)
{
var streamWriter = new StreamWriter(stream);
try
{
streamWriter.Write(text);
}
finally
{
streamWriter.Close();
stream.Close();
}
}
}
}
- Создайте новый класс EncryptedFilePersistenceExtension:
using System.ComponentModel.Composition;Этот класс предоставляет приложению MefPad возможности по открытию и сохранению зашифрованных файлов.
using System.IO;
using System.Security.Cryptography;
using System.Text;
using MefPad;
namespace MEFPadExtensions
{
[Export(typeof(IFilePersistenceExtension))]
public class EncryptedFilePersistenceExtension : IFilePersistenceExtension
{
readonly byte[] iv = Encoding.ASCII.GetBytes("ABCDEFGHIJKLMNOP");
readonly byte[] key = Encoding.ASCII.GetBytes("ABCDEFGHIJKLMNOP");
public string Description
{
get { return "Encrypted"; }
}
public string Extension
{
get { return ".crypt"; }
}
public char[] Read(Stream stream)
{
Rijndael rijndael = Rijndael.Create();
var cryptoStream = new CryptoStream(stream,
rijndael.CreateDecryptor(key, iv),
CryptoStreamMode.Read);
var streamReader = new StreamReader(cryptoStream);
string bytes;
try
{
bytes = streamReader.ReadToEnd();
return bytes.ToCharArray();
}
finally
{
streamReader.Close();
cryptoStream.Close();
stream.Close();
}
}
public void Write(Stream stream, char[] text)
{
Rijndael rijndael = Rijndael.Create();
var cryptoStream = new CryptoStream(stream,
rijndael.CreateEncryptor(key, iv),
CryptoStreamMode.Write);
var streamWriter = new StreamWriter(cryptoStream);
try
{
streamWriter.Write(text);
}
finally
{
streamWriter.Close();
cryptoStream.Close();
stream.Close();
}
}
}
}Шаг 7 - Запуск приложения
- Запустите приложение введите в текстовое поле любой текст.
- В меню выберите пункт File -> Save
Заключение
Managed Extensibility Framework предоставляет разработчикам инструменты необходимые для легкого создания расширяемых .NET приложений. Более того, его будущее повсеместное использование как опции для обеспечения расширяемости предоставит легко доступное решение в разных проектах и компаниях. Используя MEF для своих нужд по расширяемости, вы сможете меньше фокусироваться на проблемах развития инфраструктуры и больше на создании хорошего программного обеспечения для своей компании.четверг, 25 февраля 2010 г.
Сохранение/Загрузка ObservableCollection
Вопрос: How to save, load ObservableCollection?
В принципе задачка Serialize/Deserialize объектов достаточно простая, но вдруг кто не знает.
Создаем класс People
public class People { public string FirstName { get; set; } public string LastName { get; set; } public DateTime BornDate { get; set; } public string Email { get; set; } }
Добавляем пространства имен, для удобства.
using System.Collections.ObjectModel; using System.IO; using System.Xml.Serialization;
А вот и наша коллекция:
private ObservableCollection<People> _Peoples;
Название файла для сохранения/загрузки лучше оформить отдельной переменной:
private string _FileName = "peoples.data";
Ну а теперь собственно и сами методы.
Загрузка данных:
private void LoadData() { if (File.Exists(_FileName)) { using (var reader = new StreamReader(_FileName)) { var xs = new XmlSerializer(typeof(ObservableCollection<People>)); _Peoples = (ObservableCollection<People>)xs.Deserialize(reader); } } else { _Peoples = new ObservableCollection<People>(); } }
Сохранение данных:
private void SaveData() { using (var writer = new StreamWriter(_FileName)) { var xs = new XmlSerializer(typeof(ObservableCollection<People>)); xs.Serialize(writer, _Peoples); } }
Для отображения списка можно воспользоваться ListBox
Для этого в xaml файл добавляем:
<ListBox x:Name="list" Width="Auto"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding FirstName}" Width="50" /> <TextBlock Text="{Binding LastName}" Width="50"/> <TextBlock Text="{Binding BornDate, StringFormat=d}" Width="60" /> <TextBlock Text="{Binding Email}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>
Исходники проекта
вторник, 9 февраля 2010 г.
Linq: Как получить из одного списка объектов пронумерованный?
Возникла задача получить из списка объектов (IList<People>) другой, а именно пронумерованный (IDictionary<int,People>). Те получить некоторый аналог ROWNUM (Oracle) или ROWNUMBER (MS SQL Server).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Linq.test
{
class Program
{
static void Main(string[] args)
{
// источник записей
var mans = new[] {
new People { Name = "John", Age = 23 },
new People { Name = "Bob", Age = 12 },
new People { Name = "Bill", Age = 43 },
new People { Name = "Patrick", Age = 69 }
};
// посмотрим что там в списке ;-)
foreach (var man in mans)
{ Console.WriteLine(man.ToString()); }
// получаем проиндексированный список
var counteredMan = GetIndexed(mans);
// собственно выводим его в консоль
foreach (var item in counteredMan)
{ Console.WriteLine(item.Key + " - " + item.Value); }
Console.ReadLine();
}
/// <summary>
/// Получение пронумерованного списка
/// </summary>
/// <param name="pupils"></param>
/// <returns></returns>
private static IDictionary<int, People> GetIndexed(IEnumerable<People> pupils)
{
return pupils.Select((man, i) => new
{
id = i+1,
man = man
}).ToDictionary(key => key.id, val => val.man);
}
}
/// <summary>
/// Объект для опытов
/// </summary>
public class People
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{ return "Гражданин " + Name + ", возраст: " + Age; }
}
}
четверг, 4 февраля 2010 г.
vSphere Host update Utility - Инициализатор типа "VirtualInfrastructure.Utils.HttpWebRequestProxy" выдал исключение.
Windows 7 x64 не перестаёт радовать новыми особенностями работы с различными ПО. На этот раз проблема возникла с VMware vSphere Client и VMware vSphere Host Update Utility 4.0.0.0 build 162856. Первый выдал ошибку:
Could Not Connect
Error parsing the server "xxx.xxx.xxx.xxx" "clients.xml" file. Login will continue, contact your system administrator.
Для решения данной проблемы необходимо:
Для решения проблемы запуска VMware vSphere Client нужно выполнить шаги 1-4, шаг 5 необходим для исправления ошибки в VMware vSphere Host Update Utility.
1. Создать каталог C:\Program Files (x86)\VMware\Infrastructure\Virtual Infrastructure Client\Launcher\lib ;
2. Скопировать в созданный каталог файл system.dll ;
3. Создать переменную среды DEVPATH с значением – “C:\Program Files (x86)\VMware\Infrastructure\Virtual Infrastructure Client\Launcher\lib” ;
4. Добавить в файл VpxClient.exe.config строчки выделенные жирным шрифтом:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.net>
<connectionManagement>
<clear/>
<add address="*" maxconnection="8" />
</connectionManagement>
</system.net>
<appSettings>
<add key = "protocolports" value = "https:443"/>
</appSettings>
<runtime>
<developmentMode developerInstallation="true" />
</runtime>
</configuration>
5. Создать файл VIUApp.exe.config в каталоге - C:\Program Files (x86)\VMware\Infrastructure\VIUpdate 4.0
Со следующим содержимым:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<developmentMode developerInstallation="true" />
</runtime>
</configuration>
Все.
вторник, 26 января 2010 г.
Идея: .NET IL box/unbox counter
На вход утилита должна принимать .NET библиотеку или исполняемый файл. Декомпилировать его в IL код, и выявлять и подсчитывать количество циклов с вложенными упаковками/распаковками.
пятница, 15 января 2010 г.
.NET P2P
- Microsoft Peer-to-Peer Networking Blog
- Peer-to-Peer Networking MSDN Forum
- Lance Olson - .NET P2P: Writing Peer-to-Peer Networked Apps with the Microsoft .NET Framework
- Justin Smith - Harness The Power Of P2P Communication In Windows Vista And WCF
- Kevin Hoffman How To Design State Sharing In A Peer Network [RU]
- Peer-to-Peer Programming with WCF and .NET Framework 3.5