Alexey's profileLife vs. ProgrammingPhotosBlogListsMore Tools Help

Blog


    February 28

    Visual Studio "Orcas" - мартовский CTP

    Еще не настал март, как уже вышел обещанный CTP новой Visual Studio, о которой я рассказывал здесь.

    Скачать можно как образ для Virtual PC (сам Virtual PC бесплатен, если кто не помнит), так и "обычный" инсталляционный пакет.

    Изменений ОЧЕНЬ много, да я уже давал ссылку  на видео с некоторыми из них...

    February 26

    CAB + WPF

    23-го февраля, видимо в качестве праздничного подарка, был выпущен релиз Composite Application Block, который поддерживает WPF. Ура!

    Пока создатели SmartClient Software Factory грозятся выпустить в конце апреля новую версию их продукта, которая будет содержать инструменты для добавления View, использующих WPF (и еще нескольких новых фич), CAB с поддержкой WPF можно скачать здесь: http://www.codeplex.com/wpfcab

    Для работы с ним нужно:

    1. Создать "пустой" WPF-проект.
    2. Удалить Window1.xaml и выкинуть из файла App.xaml упоминания о нем.
    3. Добавить в заголовок App.xml следующее указание неймспейса:

      xmlns:cab="clr-namespace:Microsoft.Practices.CompositeUI.Windows.Workspaces;assembly=Microsoft.Practices.CompositeUI.Windows"

    4. Создать в нем класс-аппликейшн, например ShellApplication, который унаследовать от ApplicationShellApplication<MainWorkItem, App>. Здесь MainWorkItem - это "главный" воркайтем приложения, а App - это класс, который уже есть в Вашем проекте и описывается файлами App.xaml и App.xaml.cs
    5. Создать класс Program (имя может быть любым), в котором определить статический метод Main так, как это делается в "обычном" WinForms-приложении. Запустить в нем созданный в п.2 класс-аппликейшн:
      new ShellApplication().Run();
    6. Установить класс Program как стартовый класс в свойствах приложения.

    Все, проект WPF CAB готов. Дальше все как обычно, кроме того, что вместо WinForms можно использовать WPF для создания View.

    Кстати, если сейчас запустить приложение, то у него даже не будет окна. Для того, чтобы исправить этот "недостаток", нужно создать новую WPF-форму с именем, скажем, ShellWinfow.xaml и переопределить известный метод в ShellApplication:

    protected override void AfterShellCreated()
    {
       
    base.AfterShellCreated();
       
    ShellWindow mainWindow = RootWorkItem.Items.AddNew<ShellWindow>();
       
    Shell.MainWindow = mainWindow;
        mainWindow.Show();
    }

    Ну и еще одна "фича". В тех элементах, где планируется использование воркспейсов (DeckWorkspace, TabWorkspace, etc), в заголовок можно добавить следующий атрибут: xmlns:cab="http://schemas.microsoft.com/cab/wpf
    Это позволит потом определять воркспейсы в XAML-файле следующим образом:

    <cab:DeckWorkspace x:Name="headerWorkspace"/>

    В остальном работа с CAB не изменилась.

    Более подробно можно посмотреть в примере (BankShell), который теперь тоже "переведен" на CAB WPF.

    February 24

    Бесплатный курс ASP.NET AJAX

    Можно получить здесь: ASP.NET AJAX Free Course

    Как сказано в описании курса, требования к слушателям такие:

    • Visual Studio 2005 / Visual Studio 2003 (2 года)
    • .NET 2.0 / .NET 1.1 (2 года)
    • ASP.NET 2.0 / 1.1 (2 года)
    • JavaScript (6 месяцев)

    Так же рекомендуется:

    • HTML DOM (6 месяца)
    • Понимание или опыт работы с AJAX

     

    Technorati tags: ,

    February 20

    Обновления

    Пара полезных обновлений :)

    Вышел ServicePack 2 для MS SQL Server. Скачать можно здесь:
    http://www.microsoft.com/downloads/details.aspx?FamilyID=d07219b2-1e23-49c8-8f0c-63fa18f26d3a&DisplayLang=en

     

    И второе: обновился Reflector. Полезный инструмент, если кто не знает ;)
    В пятой версии куча удобных новшеств.

    Скачать можно тут: Reflector 5.0
    Всякие интересные плагины для него здесь: Reflector 5.0 Add-Ins 

    И вот тут: Reflector 5.0 New Features обязательно посмотрите презентацию о  новых возможностях. А то будет как в анекдоте: "А что, можно было?!" :)

    February 17

    M-V-P в Composite Application Blocks

    M-V-P (Model-View-Presenter) - это разновидность шаблона M-V-C (Model-View-Controller) с некоторыми существенными отличиями.
    Я не буду описывать отличия, если кто-то интересуется, то суть этих отличий кратко описана у Дэррона Шэлла здесь и детально у Мартина Фаулера здесь.

    Так же я не буду останавливаться на той части триады, которая называется Model. Полагаю, что с ней и так все понятно, так как эта часть в принципе не осведомлена о двух других, может существовать и без них. К тому же отличий от M-V-C в данном случае нет.

    Я остановлюсь на реализации View и Presenter.

    Справедливости ради нужно отметить, что Composite UI Application Block предлагает именно M-V-C, но при работе со Smart Client Software Factory вы будете общаться именно с M-V-P. Класс презентера (как и некоторые другие) не являются частью CAB, но будут созданы фабрикой в общем модуле вашего приложения.
    В Composite Web Application Block презентер уже имеется изначально, поэтому я думаю, что соответствующая реализация будет включена и в следующий релиз CAB.

    M-V-P в данном случае предполагает наличие View - пользовательского интерфейса и наличие Presenter'а, который содержит логику работы пользователя над моделью.
    При этом View "знает" о наличии Presenter'а "напрямую" в то время, как Presenter "знает" о наличии View опосредованно - через интерфейс.

    То есть, мы, к примеру, имеем:

    1. Интерфейс ICustomerView, в котором определяются свойства и методы, отвечающие за поведение View;
    2. Класс CustomerView, который является реализацией ICustomerView и занимается непосредственно представлением данных. Кроме этого экземпляр CustomerView содержит ссылку на соответствующий Presenter, с которым и общается в рамках своей работы;
    3. Класс CustomerViewPresenter, который ничего не знает о CustomerView. Вместо этого он знает об интерфейсе ICustomerView, ссылку на который содержит.

    В коде это выглядит так:

    //Interface
    public interface ICustomerView
    {
        void ShowCustomerInfo(Customer customer);
    }
    //Presenter
    public class CustomerViewPresenter : Presenter<ICustomerView>
    {
        public override void OnViewReady()
        {
            base.OnViewReady();
            //Get the customer somewhere
            .....
            View.ShowCustomerInfo(customer);
        }
    }
    //View
    public partial class CustomerView : UserControl, ICustomerView
    {
        public CustomerView()
        {
            InitializeComponent();
        }
        [CreateNew]
        public CustomerViewPresenter Presenter
        {
            set
            {
                _presenter = value;
                _presenter.View = this;
            }
        }
        protected override void OnLoad(EventArgs e)
        {
            _presenter.OnViewReady();
        }
        public void ShowCustomerInfo(Customer customer)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(delegate() { ShowCustomerInfo(customer); }));
                return;
            }
            .....
        }
    }

    Отсюда видно, что при создании экземпляря CustomerView ObjectBuilder создает экземплярCustomerViewPresenter, ссылка на который теперь доступна внутри CustomerView. Сам же презентер получает ссылку на экземпляр, реализующий известный ему интерфейс, поэтому ему все равно, какой тип пользовательского интерфейса скрывается за ICustomerView.

    Важно отметить то, что в случае M-V-P слой View сам обрабатывает пользовательский ввод и "уведомляет" презентер о необходимости получить/обработать данные модели, а так же о своем состоянии. В указанном примере View уведомляет Presenter о том, что он загружен и готов к работе (событие OnLoad в CustomerView).

    Презентер же, выполнив какие-то действия (например, получив от ICustomerService экземпляр класса Customer), сообщает View о необходимости отобразить информацию об этом кастомере.

    Здесь очень важным является тот момент, что View никакой информацией о логике Presenter'а  не располагает, поэтому реализация метода ShowCustomerInfo делается потокобезопасной. На самом деле, Presenter может начать обрабатывать данные асинхронно для того, чтобы пользовательский интерфейс не блокировался на время работы. Пока ведется обработка данных, Presenter может "просить" View информировать пользователя о прогрессе и лишь после окончания обработки вызвать метод ShowCustomerInfo. Поэтому View должен быть готов к тому, что практически любой вызов от презентера придет из контекста другого потока, реализуя методы интерфейса ICustomerView потокобезопасными.

    На самом деле, это очень простая схема и именно так и нужно делать всегда: View лишь уведомляет Presenter о том, что пользователь захотел сделать что-то (например, вызывая _presenter.ApproveCustomer). View не в праве расчитывать на то, что Presenter ответит немедленно, вернув какой-то результат. Строго говоря, результаты вообще не в компетенции View, View не в праве решать, что делать с результатом. Вместо этого обработкой данных и получением результата занимается Presenter и после того, как операция выполнена, просто заставляет View сделать что-то другое.

    Такой подход позволяет нам получить следующие плюсы:

    1. Безболезненно менять View по нашему усмотрению (или даже заменить его полностью, например, на консоль или веб-страницу, лишь бы интерфейс был реализован);
    2. Изменять логику обработки пользовательского ввода так, как будет угодно.
    3. Получить механизм, работающий в рамках "правильной" архитектуры, то есть, когда части приложения просто нотифицируют друг друга о необходимости какой-либо реакции.
      View говорит презентеру: "Пользователь велел сделать то-то". Презентер делает что-то и через "полчаса" говорит View: "ну, я сделал, сообщи там как-нибудь".
      "Пользователь хочет новых данных" - "Нарисуй новые данные".
      "Пользователь сказал, что эти данные не годятся" - "Нарисуй вот эти данные"
      "Пользователь велен их стереть" - "Нафиг, скажи, что у него нет прав".
      И так далее. Никакая часть не ждет другую. Никакая часть не блокируется в ожидании (ну, потому, что не ждет). Никаких идиотских циклов ожидания с DoEvents().

    Ко всему этому писать (и поддерживать!) код легко и приятно (а то иной раз просто хочется запустить мышкой в монитор, разбирая очередные 350 спагетти-строк в _button1_Click).

    Пользуйтесь шаблонами проектирования, в них мудрость :) Возьмите "полуфабрикаты" в виде Composite Application Blocks, возьмите Software Factories - и они помогут вам придерживаться "правильного" пути.
    И будет вам счастье.

    February 16

    Сервисы в Composite Application Blocks

    Сегодня немного расскажу об архитектуре Composite Application Blocks (Web и UI) и о том, как ее использовать "во благо". Речь в основном пойдет о двух фундаментальных вещах: сервисах и шаблоне проектирования M-V-P (Model-View-Presenter).

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

    Слабой связанности в Composite Application Blocks можно добиваться посредством создания сервисов.
    Кто такой сервис? Сервисом может быть любая независимая часть вашего приложения.
    Сервис дает возможность приложению задавать вопросы типа "что" не заботясь об ответах на вопрос "как". Наше приложение просит сервис дать список пользователей - и получает его не заботясь о том, был ли список получен из БД или с Веб-сервиса. Приложение просит сервис информировать пользователя о прогрессе, не заботясь о том, будет ли пользователю показан ProgressBar или отобразится окошечко "Please Wait".
    Приложение знает что надо делать. Сервис знает как надо делать. Приложение знает, что где-то есть, кто-то, кого можно пнуть, чтобы он сделал свою работу.

    О том, как это реализуется.
    Сервис обычно состоит из "двух частей" - интерфейса сервиса и его реализации. Интерфейс сервиса обычно размещается где-нибудь в доступном для всех (интересующихся) частей приложения месте (в Shared-библиотеке), а реализация - где придется там, где удобнее реализовывать этот интерфейс (например в каком-то модуле).

    Например, мы определим интерфейсы ISourceControlService и IProgressService в общей библиотеке, чтобы все части приложения имели к ним доступ. После этого мы можем создать модуль SourceSaveVersionController, в котором создать класс SourceSaveService : ISourceControlService, которая будет работать работать с Microsoft SourceSave.
    При загрузке и инициализации этого модуля происходит регистрация сервиса в системе:

    Services.AddNew<SourceSaveService, ISourceControlService>();

    С этого момента из любой части приложения мы можем обратиться к сервису, отвечающему за контроль версий, получить экземпляр, реализующий ISourceControlService и даже не задумываться о том, с какой именно системой контроля версий мы имеем дело:

    ISourceControlService scControl = Services.Get<ISourceControlService>();

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

    Для IProgressService можно поступить еще хитрее: реализовать этот интерфейс в главной форме приложения и зарегистрировать ее саму как сервис типа IProgressService. А можно сделать как-то иначе, придумать что-то другое, ведь уже стало понятно, что остальному коду совершенно безразлично то, кто предстанет перед ними под личиной IProgressService и как он будет выполнять свою работу :)

    Сама работа с сервисами в Composite Application Blocks тоже очень удобна.
    Например, для регистрации сервиса в CAB можно использовать такую конструкцию:

    [Microsoft.Practices.CompositeUI.Service(typeof(IComponentsProvider))]
    public class AccessComponentsProvider : IComponentsProvider
    {.....}

    В этом случае при загрузке модуля экземпляр сервиса будет автоматически создан и зарегистрирован.

    Там, где нам необходимо общаться с сервисами, и в CAB и в Composite Web AB можно сделать так:

    [

    ServiceDependency]
    public IAuthorizationService AuthService
    {
       
    get { return _authService; }
       
    set { _authService = value; }
    }

    ObjectBuilder сам найдет для вас подходящий сервис IAuthorizationService (если, конечно, он был зарегистрирован) и вызовет присвоит ссылку на него свойству AuthService. В случае, если нужный сервис зарегистрирован не был, вы получите null. Однако, в конструктор аттрибута ServiceDependency можно передать булевый параметр для того, чтобы ObjectBuilder возбуждал исключение если сервис найти не удается.

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

    Используйте сервисы - и да будет вам счастье :)

    February 15

    Web Client Software Factory и Web App Project

    Неудобством Web Client Software Factory является было то, что фабрика создавала и поддерживала Web Site Application Project.

    Со вчерашнего дня эту фабрику можно "научить" работать и с Web Application Project.

    Сделать это можно так:

    1. Установить исходные коды фабрики, если они еще не установлены. Для этого нужно просто в главном меню (Start) в папке фабрики запустить WebClientFactorySourceInstall.msi.
    2. Скачать дополнения: WebClientFactoryWAPSupport (это zip-файл)
    3. Найти в установленных исходниках папку GP и распаковать туда содержимое архива из пункта 2.
    4. Из распакованной папки WebClientFactoryWAPSupport открыть файл решения WebClientFactory Guidance Package.sln и сделать Build всего этого дела. Все должно пройти нормально, если архив был распакован в правильное место.
    5. Щелкнуть правой кнопкой мыши на проекте WebClientFactoryPackage и зарегистрировать получившийся Guidance Package (процесс займет какое-то время).

    Все, теперь можно создавать Web Client Project'ы с использованием Web Application Project. Что не может не радовать.

    Оригинальная инструкция здесь: http://www.codeplex.com/websf/Wiki/View.aspx?title=Web%20Application%20Project%20Guidance%20Package

    February 09

    Web 2.0: Просто и понятно

     

    Вот так :)

    February 05

    Video Of Scott Guthrie's Newest Presentation

    Tom Mertens выложил видео с бельгийской User Group, на которой выступал Scott Guthrie.

    Посмотреть можно здесь:

    http://blogs.msdn.com/tommer/archive/2007/02/03/video-of-scott-guthrie-s-newest-presentation-first-look-at-visual-studio-orcas.aspx

    К сожалению, смотреть можно только онлайн, так как расшарить WMV Том сейчас почему-то не может, как мы его об этом ни просили :)

    February 03

    К вопросу о String.Empty

    Олег Михайлик и Гайдар затеяли разбирательство на тему того, почему String.Empty и "" равны или не равны друг другу.

    Подробные объяснения от Олега можно прочесть тут: http://blogs.gotdotnet.ru/personal/mihailik/CommentView.aspx?guid=2F1AF381-0EF6-4F8E-97F9-28CFB9F2162B

    Добавить хотелось только то, что у Рихтера есть и вторая книжка (так и вспоминается КВН: "букварь, вторая и синяя" :)).

    Так вот в ней описано как интернирование строк в .NET Framework 2.0 и атрибут CompilationRelaxions, так и то, почему не стоит ему доверять.

    Я просто процитирую:

    Если сборка отмечена атрибутом CompilationRelaxions, определяющим значение флага CompilationRelaxions.NoStringInterning, в соответствии со спецификацией ECMA CLR может не интернировать все строки, определенные в метаданных сборки. Заметье: в целях повышения производительности приложения компилятор C# всегда при компиляции сборки определяет этот атрибут/флаг.

    Даже если в сборке определен этот атрибут/флаг, CLR может предпочесть интернировать строки.

    [SKIP, здесь идет код, который показывает, что строки и не должны бы интернироваться, но все равно это происходит]

    Причина в том, что эта версия CLR предпочитает игнорировать атрибут/флаг, созданный компилятором C#, и CLR интернирует строку при загрузке в AppDomain.

    [SKIP]

    В действительности, CLR версии 2.0 учитывает этот атрибут/флаг, но только если код сборки создан с использованием утилиты NGen.exe

    Вот такие вот пироги, вот и объяснение того, почему константа String.Empty в mscorlib не интернирована.
    Даже если задать атрибут для своей сборки руками, не полагаясь на компилятор, то результат получится тот же самый, я как-то проверял.

    Так что тот же самый Рихтер прав: не стоит закладываться на то, интернированы ли строки, или нет. С другой стороны, мало кто, думаю, пользуется сравнением строк через ReferenceEquals :)

    Оркас: сроки

    Да, в прошлом постинге я забыл сказать про сроки.

    Со слов Скотта тот CTP, что был продемонстрирован на UserGroup, можно будет скачать примерно в конце февраля - в первой неделе марта.

    Официальная бета-версия должна выйти в конце весны.

    Ну а в целом .NET Framework 3.5 и Visual Studio "Orcas" покинут стены Майкрософт в 2007-м году, точнее сроков названо не было.

    Technorati tags: , ,
    February 02

    "Orcas" и ASP.NET Ajax "от производителя"

    1-го февраля в бельгийском городе Mechelen (20 км. от Брюсселя) была проведена юбилейная (1-го февраля группе исполнился ровно год) встреча Visual Studio User Group, главным и единственным докладчиком на которой был Microsoft General Manager Scott Guthrie.

    Скотт - это человек, который непосредственно принимал участие в проектировании и разработке ASP.NET, вложил огромный вклад в развитие .NET в целом и CLR в частности. В настоящее время он руководит командами разработки CLR, ASP.NET, WinForms, Visual Studio. Кроме того, он замечательный докладчик, которого можно слушать, слушать и слушать...

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

    Итак, что же такое "Orcas"? "Orcas" - это следующее поколение Visual Studio и .NET Framework 3.5.
    Нововведений в "Оркасе" очень много. 

    Дальше читайте на http://alexey.raga.name, сюда что-то не могу ничего запостить из своего блог-клиента.