вторник, 28 августа 2012 г.

Использование TFS c нескольких компьютеров в локальной сети с единым workspace

Небольшая заметка по поводу Team Foundation Server и его знаменитых workspaces:
Если вы программируете с контролером версии от Microsoft,  естественно c EDI Visual Studio, в локальной сети на нескольких компьютерах, то у вас могут возникнуть проблемы со средой разработки т.к. на один логин и пароль от TFS вас привяжут к одному компьютеру. И синхронихировать работу над одним проектом с двух машин непредставляется возможным. Но выход таки есть:
1. Вам понадобиться создать сетевой диск на всех машинах в локальной сети которые будут использовать единые логин и пароль для TFS. Данный сетевой диск слудует привязать к папке где лежит ваш проект. В моем случае я создал сетевой диск Z: и присвоил ему всю папку work  со всеми моими проектами для единого сервера TFS.
2. Далее на каждой машине кто будет юзать этот проект от одного пользователя, следует создать   Environmental variable для пользователя. а именно: _CLUSTER_NETWORK_NAME_=<имя компьютера с которого вы всегда пользовали TFS>

И вуоля! Теперь я могу работать и на стационаре и на лаптопе с одними пользовательскими данными.

понедельник, 17 января 2011 г.

Тестовое задание от Электронные торги и безопасность, ФГУП

Чото совсем писать не хочется...

Было найдено интересное тестовое задание раскрывающее суть динамического подключения сборок на .NET платформе.

Тестовое задание звучит так:
"Разработать WinForms приложение. Основное окно должно содержать грид для отображения списка объектов. На форме должны быть кнопки: добавить, изменить, удалить. Кнопки должны открывать диалоговые формы для ввода данных, изменения данных и подтверждения удаления. Кнопка добавления должна предварительно открывать список классов объектов для выбора класса создаваемого объекта (например: физ. лицо, юр. лицо, инд. предприниматель).
Приложение не должно знать заранее список классов объектов.
Настройки хранить в файле Options.xml. Каждый класс сущности реализовать в динамически подключаемой библиотеке. В файле Options.xml указать список классов и ДЛЛ, которые их реализуют. Для каждого класса своя ДЛЛ и своя форма для создания/изменения, но одна форма на удаление объекта любого класса. Свойства объектов хранить в xml-файле. После обработки список в гриде должен обновляться."

Мне оно показалось интересным в первую очередь тем, что я редко, да и думаю что любой другой программист не часто, используют подобную фичу в своих проектах, хотя в Self подготовке к 70-536 эта тема описывается.

Ну в общем перейдем к процессу решения этой задачи. Для начала я прикинул что?где? когда? Почитал немного доков от мелколегких здесь. И решил что структура проекта будет следующая:
1. WinForms приложение - приложение подключающее библиотеки - как сущности и отображающее их объекты.
2. Связующая библиотека - аля ядро, содержащая необходимые интерфейсы для Сущности и ее класса (самое главное тут).
3. Множество различных сборок,  удовлетворяющие интерфейсам из ядра.
Немного теории о доменах (не DNS а о Application доменах) и сборках можно почитать тут .

Сказано - сделано:
где: 
DynamicObject_t - WinForms
EntityLayer - ядро
TestEntity1 и TestEntity2 - множество библиотек.

По условию задачи в WinForms приложении у нас 2-е формы:
1. Основная  - с тремя "кнопыщками" и "гридом".
2. Для выбора типа (сущности, класса) добавляемого объекта.

Снова, сказано - сделано:




Но это все косметика, самое интересное это что же из себя представляет EntityLayer.

EntityLayer содержит два интерфейса: 1. IClassEntity.cs - отображает класс для работы со сборкой, 2. - IObject.cs отображает класс объектов сборки. И класс XmlHelper.cs - содержит функционал сериализации и десериализации объектов сборки в Xml.

,где IClassEntity.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms; 

namespace EntityLayer
{
    public interface IClassEntity
    {
        string Name { get; } //Имя сборки

        Form   Edit(int ID); //Возвращает объект формы для редактирования, объекта       

        Form   Add();//Возвращает объект формы для добавления нового объекта

        void   Delete(int ID); //Удаляет объект

        List<IObject> Objects { get;}//Возвращает список объектов сборки
    }
}


,а  - IObject.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; 

namespace EntityLayer
{
   public interface IObject
    {
       int ID {get; set; }//Идентификатор объекта в сборке

       string ObjectType { get;}//Имя сборки

       string Summary { get; }  // Общее поле, возвращает суммарное значение полей объекта.

    }
}

Таким образом, получается что с помощью интерфейса IClassEntity мы можем получить общие методы взаимодействия с любыми динамически подгружаемыми сборками - классами наследуемые от данного интерфейса.
Как мы будем это делать в нашем WinForms приложении?
Для этого в этом проекте я создал класс Options.Helper.cs со статическим методом GetEntities, он считывает заказанный нам в условии Options.xml со сборками и классами и записывает уже интерпретированные классы сборок в List<EntityLayer.IClassEntity>

public static List<EntityLayer.IClassEntity> GetEntities(out bool IsError)
        {
            List<EntityLayer.IClassEntity> list = new List<EntityLayer.IClassEntity>();
            IsError = false;
            try
            {
                XElement root =  Element.Load(Properties.Settings.Default.OptionFile);               

                    var Ents = root.Elements();

                    foreach (var h in Ents)
                    {                      
list.Add(GetEntity(h.Attribute(XName.Get("class")).Value, h.Attribute(XName.Get("path")).Value));
                    }               

            }
            catch(Exception ex)
            {
                Log.WriteErrorLine(ex.ToString());
                IsError = true;
            }
            return list;

        }

Что такое GetEntity? Сейчас разберемся....

static EntityLayer.IClassEntity GetEntity(string ClassName, string
AssemblyFile)
        {
            if(!File.Exists(AssemblyFile)) throw new FileNotFoundException("Can't
find assembly file."
);
 

            Assembly assembly = Assembly.LoadFile(Application.StartupPath + "\\"
+ AssemblyFile);
 

            return (EntityLayer.IClassEntity)Activator.CreateInstance(assembly.GetType(ClassName));//Именно здесь происходит загрузка инициированного объекта класса со сборки, и оборачивание его в IClassEntity интерфейс.

        }
Ок, теперь ясно как это считывается и интерпретируется, а как выглядит класс самой подключаемой сборки? Пожалуйста...



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EntityLayer; 

namespace TestEntity1
{
   public class CompanyEntity:IClassEntity
    {  
        List<Company> Companies;//Список наших объектов, в данном случае компании

        XmlHelper<Company> helper; 

        public const string ObjectXmlFile = "TestEntity1.xml"; //Файл для сериализации и обратного процесса

        public string Name
        {
            get{ return "Company";}
        }

        public CompanyEntity()
        {
            helper = new XmlHelper<Company>(CompanyEntity.ObjectXmlFile);

            Companies = helper.Deserialise();
        }



        public System.Windows.Forms.Form Edit(int ID)
        {
            return new EditCompany(ID,Companies);//Вовращение формы для редактирования, реализуемой в данной сборке
        }     



        public System.Windows.Forms.Form Add()
        {
            return new EditCompany(null, Companies);
        }



        public List<IObject> Objects//Возвращение объектов 
        {
            get
            {
                List<IObject> result = new List<IObject>();               

                foreach(var h in Companies)
                    result.Add(h);

                return result;
            }
        }



        public void Delete(int ID)//Удаление объекта
        {
            var h = Companies.Where(i=>i.ID==ID).FirstOrDefault();
            if(h != null)
            {
                Companies.Remove(h);
                helper.Serialise(Companies);
            }
        }      

    }
}


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

Полный код проекта: SVN Тестового Проекта (как хорошо что есть дядя Гугл).

вторник, 28 декабря 2010 г.

Request for the permission of type System.Web.AspNetHostingPermission failed

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

Ошибка была следующего содержания:
Request for the permission of type 'System.Web.AspNetHostingPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed. 

В моем случае я добавлял AjaxControlToolkit.dll.

В чем может заключаться ошибка:
1. Если вы пытаетесь добавить сборку с удаленного ресурса в сети, т.е. если параметры безопасности .NET среды не настроены на доверие к данной директории, будет вылетать данная ошибка при добавлении сборки.
2. Если сборка которую вы добавляете является строго типизированной.

Как решается проблема:
В случае 1:

  •  Следует дать права удаленной директории с помощью утилиты caspol.exe: [Drive]:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\caspol.exe -m -ag 1 -url "file:////\\[Имя Компьютера]\[ИмяОбщейПапки]\*" FullTrust -exclusive on
  • Можно не напрягаясь скопировать нужную сборку к себе на компьютер и подключить ее с локального компьютера без нервотрепки.


В случае 2:
Следует добавить данную сборку в Global Assembly Cache c помощью утилиты gacutil.exe:

  • Открываете Visual Studio Command Prompt 
  • Вводите туда  gacutil /i [Полный путь до сборки]
  • Наслаждаетесь

среда, 22 декабря 2010 г.

Начало начал

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

Последнее время я стал чаще задумываться на тему собственного самообразования.  Сам я по природе и по призванию IT-шник, работаю в качестве разработчика программного обеспечения на Microsoft .NET платформе. По ряду профессиональных причин приходиться часто читать различную литературу, связанную с различными процессами разработки программного обеспечения. Последнее время мне все чаще, стали попадать статьи на тематику написания собственного блога. Суть их такова, что для саморазвития необходимо писать статьи. Необходимо уметь выражать свои мысли на бумаге, уметь передать их читателю. А так как в со студенческой скамьи я ничего не писал (отчеты начальству и деловая переписка не в счет), то решил развивать данное качество в себе.