вторник, 2 июля 2013 г.

Переброс wan-порта на lan на d-link dir-300.


Недавно на моём wifi маршрутизаторе после грозы сгорел wan-порт. В wan - порт подключается ethernet кабель. Соответственно, после этого события интернет у меня пропал. Все остальные порты на роутере замечательно работали (4 lan порта). Wifi хорош тем что избавляет тебя от необходимости перепрыгивать через всевозможные провода. Для меня роутер за 2 года работы стал совершенно незаменимой вещью, а потому недолго подумав, начал гуглить ближайший магазин для покупки нового роутера. Но та мысль, что  из-за одного неработающего порта мне предстояло выкинуть этот роутер и купить новый, не давала покоя.
Как оказалось впоследствии, порт wan можно перебросить на один из lan портов.  Всё это делается с помощью сторонней прошивки dd-wrt. Данная прошивка доступна не только для роутеров D-link, но и для других беспроводных маршрутизаторов популярных производителей. Установив данную прошивку, можно расширить возможности своего роутера.
Скачать прошивку можно отсюда (в поле ввода ввести dir 300). На странице представлено два варианта п.о - factory webFlash и webFlash. Сначала необходимо установить Factory прошивку, а после неё поставить webFlash. Всё это делается в стандартном веб-интерфейсе роутера. Кстати, те, кто пользовался для доступа к веб-интерфейсу адресом 192.168.0.1 будут немного озадачены тем, что по данному адресу роутер не отвечает. Всё дело в том что, dd-wrt прошивка имеет свои особенности, среди которых свой ip адрес для доступа к роутеру: 192.168.1.1. После всех манипуляций и настроек нужно сделать переброс порта. Для этого нужно открыть веб-интерфейс роутера и перейти в Administration->Commands. И в Command shell ввести следующее:
switch reg w 70 ffff416E
switch reg w 40 1002
После этого внизу нажать Save startup.
Настраиваем переброс порта.

На этом в общем то всё. Ваш wan порт теперь должен работать на 4м lan порте.


суббота, 22 июня 2013 г.

Json и C#.


Json - формат передачи данных, который буквально за несколько лет стал вровень с XML, а в некоторых аспектах даже перегнал его. Facebook, Twitter, и многие популярные сервисы используют этот формат для выдачи данных в своих API.
Существует куча сторонних библиотек для работы с Json в .net, но зачем пользоваться сторонними продуктами, если в .net присутствует всё необходимое для этих целей.
Для примера будем использовать такой Json:

  {  
   "firstName": "Иван",  
   "lastName": "Иванов",  
   "address": {  
     "streetAddress": "Московское ш., 101, кв.101",  
     "city": "Ленинград",  
     "postalCode": 101101  
   },  
   "phoneNumbers": [  
     "812 123-1234",  
     "916 123-4567"  
   ]  
 }  

Как видите, имеется некая информация о человеке: имя, фамилия, адрес, и его контактные телефоны. При работе с Json, данные могут сериализовываться/десериализовываться. То есть, любой класс описанный в C# мы свободно можем сериализовать и получить чистый Json. Десериализация работает по-другому: на входе у нас имеется Json, а на выходе должен получиться экземпляр класса, со свойствами описанными в Json. Естественно, что этот класс должен быть перед десериализацией подобающим образом определён.
Опишем класс Person:
 public class Person  
   {  
     public string firstName { get; set; }  
     public string lastName { get; set; }  
     public Address address { get; set; }  
     public string[] phoneNumbers { get; set; }  
     public class Address  
     {  
       public string streetAddress { get; set; }  
       public string city { get; set; }  
       public int postalCode { get; set; }  
     }  
   }  
Как видите, свойства класса должны соответствовать полям, что находятся в Json.
Для работы с Json необходимо подключить Reference System.Runtime.Serialization. Там находится пространство имён Json, его и будем использовать. Нам нужен класс DataContractJsonSerializer. Код для десериализции будет следующий:
 using System.Runtime.Serialization.Json;  
 ...
  private void ParseBtn_Click(object sender, EventArgs e)  
     {        
       DataContractJsonSerializer json = new DataContractJsonSerializer(typeof(Person));  
       string fileContent=System.IO.File.ReadAllText("json.txt");  
       Person person = (Person)json.ReadObject(new System.IO.MemoryStream(Encoding.UTF8.GetBytes(fileContent)));  
     }  

Один из конструкторов DataContractJsonSerializer принимает тип класса в который будет происходить десериализация. Далее мы вызываем метод ReadObject, принимающий поток с данными Json. 
Если всё было сделано верно, то экземпляр класса Person будет создан и его свойства будут заполнены в соответствии с Json.
В дальнейшем, можно вывести эти данные, например так:
  FNameLbl.Text = person.firstName;  
       LNameLbl.Text = person.lastName;  
       PhonesLbl.Text = string.Join(", ", person.phoneNumbers);  
       StreetLbl.Text = person.address.streetAddress;  
       CityLbl.Text = person.address.city;  
       PostalLbl.Text = person.address.postalCode.ToString();  
Всё должно работать, но есть один нюанс. Как вы наверно уже поняли, десериализация требует наличия в классе свойств, которые по имени совпадают с полями в Json. Так, например, в нашем Json все поля написаны с прописной буквы, и потому в классе Person тоже все свойства описаны идентично. Сами понимаете, что с точки зрения C# это недопустимо. Свойства класса должны начинаться с заглавной буквы.
Дабы решить эту проблему и не привязывать десериализацию к именам свойств класса, необходимо использовать атрибуты свойств и классов.
Наш класс с использованием атрибутов будет выглядеть так:
   [DataContract]  
   public class Person  
   {  
     [DataMember(Name = "firstName")]  
     public string FirstName { get; set; }  
     [DataMember(Name = "lastName")]  
     public string LastName { get; set; }  
     [DataMember(Name = "address")]  
     public Address PersonAddress { get; set; }  
     [DataMember(Name = "phoneNumbers")]  
     public string[] PersonPhones { get; set; }  
   }  
   [DataContract]  
   public class Address  
   {  
     [DataMember(Name = "streetAddress")]  
     public string StreetAddress { get; set; }  
     [DataMember(Name = "city")]  
     public string City { get; set; }  
     [DataMember(Name = "postalCode")]  
     public int Postal { get; set; }  
   }  
Теперь наш класс соответствует негласным правилам C#.
Скачать исходники можно тут 

четверг, 20 июня 2013 г.

SVN сервер на Windows для работы с XCode на Mac OS 10.8. Часть1.


В данном руководстве хотел бы обратить внимание на работу с SourceControl в XCode. Svn сервер будет располагаться на windows машине, которая должна быть доступна по сети. 
Для тех кто в танке: SVN (subversion) - некая централизованная система, где лежат все проекты команды, куда каждый участник поработав с кодом, выкладывает свои изменения, забирает изменения других разработчиков. В общем, SVN делает работу в команде с проектом значительно проще.
Данная система должна быть развёрнута в неком централизованном месте, доступном каждому участнику команды, т.е речь идёт о каком то выделенном сервере.
SVN продуктов пруд-пруди, но я выбрал VisualSvn, т.к он поддерживаем XCode, а его сервер (SVN) можно развернуть на Windows машине.
Разработчики VisualSvn как и все люди любят деньги, а потому для загрузки доступно 2 версии сервера: бесплатная, и соответственно, платная. Платная отличается немногими фишками, например, возможностью ведения лога попыток коннекта к серверу. Если это вам необходимо - то вперёд, платите. Для примера нам вполне сгодится бесплатная версия VisualSvn сервера. Скачать всё это можно по адресу http://www.visualsvn.com/server/
В процессе установки больших трудностей у вас возникнуть не должно. После успешной установки необходимо запустить утилиту, которая установилась вместе с сервером, называется она VisualSvn Server (вот же странно). Выглядит это добро примерно так:
Окно VisualSvn Server.

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

Дальше нужно перейти на вкладку Network и настроить порт:

Настройка порта.

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

И да, для подключения к нему надо использовать https протокол.
Для доступа к нашему серверу извне, необходимо открыть порт, который использует сервер (8443). После открытия порта, протестируем как работает сервер, для этого можно открыть любой браузер и в строку адреса ввести типа такого:
https://255.255.255.255:8443/svn где 255.255.255.255 ваш ip-адрес, а 8443 - порт, на котором работает сервер. Если всё было сделано удачно то должно появиться окошко для аутентификации, приглашающее ввести логин/пароль. Если вы в настройках поставили возможность windows-авторизации, то для доступа к серверу можно использовать ваш логин/пароль от windows. После ввода этих данных, вы должны увидеть корневую папку сервера, если бы у вас на сервере уже были репозитории, то вы смогли бы просмотреть папки/файлы своих проектов.

На этом первая часть закончена, ждите второй части, в которой будет уделено внимание работе с Svn через XCode.

понедельник, 8 октября 2012 г.

WPF: получаем строку из файла ресурсов в XAML разметку



   Недавно столкнулся с проблемой получения в XAML разметку WPF приложения строки из файла ресурсов. Кто не знает, ресурсы представляют собой весьма удобный контейнер, который может содержать информацию, которая необходима приложению. В моём случае, в свойство Text компонента TextBox необходимо было в XAML разметке назначить строку из файла ресурсов.
   Ну задача понятна. Попробуем её решить: создадим wpf приложение в VS. Сразу добавим соответствующую строку в ресурсы, для этого в главном меню перейдём в меню Project-...Properties. Если всё сделали правильно, перед вами откроется весьма солидное окно с множеством вкладок. Справа перейдём на вкладку Resources. Здесь добавим строку с именем defaultStringContent, в свойство value введём: "Эта строка извлечена из файла ресурсов". Нажмём Ctrl-S, тем самым сохранив сделанные изменения.

   Перейдём в окно дизайнера, создадим простенькую разметку нашего окна, как я уже сказал, основным элементом формы будет TextBox. Текст разметки приведён ниже:
<Window x:Class="GetResourceInXaml.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"      
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBox></TextBox>
    </Grid>
</Window>

   Я не буду вдаваться в детали работы с Xaml, т.к данный пост рассчитан на тех, кто хоть немного знает WPF, а работа с данной технологией невозможно без Xaml.
Теперь необходимо вставить в свойство Text TextBox'a строку из ресурсов. Для начала добавим в окно ссылку на ту самую ветвь в исходниках приложения, где содержатся эти ресурсы. У меня они содержатся в папке Properties. Посмотреть, где располагаются ресурсы можно в Solution Explorer'e. 

   В разметку сверху, где расположены строки типа: xmlns... Добавим:
        xmlns:local="clr-namespace:GetResourceInXaml.Properties"
   Здесь мы говорим, что через local мы можем обращаться к папке Properties. Отлично, теперь осталось назначить строку из ресурсов соответствующему свойству TextBox'a. Находим в разметке, где находится TextBox, и немного изменяем вид того, что написали:

        <TextBox Text="{x:Static local:Resources.defaultStringContent}"></TextBox>

   Если всё сделали правильно, то анализатор Xaml разметки подсветит то что мы добавили, начиная от фигурной скобки, тем самым давая понять, что что-то неправильно.
Перейдём опять в настройки проекта, на вкладку Resources, и здесь сверху переключим access Modifier с Internal на Public, ctrl-s.

   Теперь, если переключиться на xaml-представление, то мы должны увидеть в TextBox'e строку из ресурсов. Нажмём F5, тем самым скомпилировав приложение, удостоверимся в том, что строка из ресурсов действительно отображается.
На этом всё. Надеюсь, что данная заметка кому-то поможет.
Исходники:
http://ovrload.ru/files/getresourceinxaml_7c8ebf2d829a984fa735f0f49441df17.rar
08/10/2012

Богданов М.

пятница, 13 июля 2012 г.

Пауза и возобновление работы потока

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

За работу с потоками в C# отвечают несколько классов: во-первых это класс Thread (System.Threading), представляющий отдельный поток. А во-вторых - это ThreadPool, дающий возможность работы с пулом потоков. Пул потоков предпочтительнее для использования, да и удобнее он в реализации. Пул потоков - это очередь потоков приложения, в эту очередь вы можете вставить свой метод, который будет выполнен в отдельном потоке, когда один из потоков освободится.
Многие современные приложения используют возможность паузы выполнения какой то задачи. В тех же антивирусных сканерах обязательно имеются кнопки паузы для вирусного сканирования и его возобновления. Такие задачи как поиск вирусов в антивирусных комплексах реализованы почти наверняка через многопоточность, так как же приостановить выполнение потока, а потом его опять запустить с того же места? Попробуем в этом разобраться...

Создадим простейшее приложение на C#, которое будет использовать отдельный поток для вывода информации. На форме у нас должны располагаться три кнопки, в свойстве Text которых можно написать: Старт, Пауза, Стоп. Так же нам понадобится метка label.
Разместив необходимые компоненты на форме, можно приступать к кодингу. Объявим несколько глобальных переменных и напишем кое-что в конструктор формы:

EventWaitHandle ew;
        bool Stop, Pause;
        public Form1()
        {

            InitializeComponent();
            ew = new EventWaitHandle(false, EventResetMode.AutoReset);
            Stop = true;
        }
Здесь мы объявили объект класса EventWaitHandle, именно с помощью этого класса и происходит сигнализация потоку о необходимости остановке или возобновления своей работы. Так же мы объявили две булевых переменных.
На кнопку Старт повесим код:

private void button1_Click(object sender, EventArgs e)
        {
            if (Stop)
            {
                button2.Enabled = button3.Enabled = true;
                button1.Enabled = false;
                Stop = false;
                ThreadPool.QueueUserWorkItem(new WaitCallback((s) =>
                {
                    ThreadMethod(100);
                }));
            }
            else
            {
                ew.Set();
                button3.Enabled = true;
            }
        }
Так же создадим метод, который будет выполняться в отдельном потоке:

void ThreadMethod(int value)
        {
            Action<int> act = new Action<int>((v) =>
                {
                    label1.Text = v.ToString();
                });

            int i = 0;
            while (!Stop && i <= value)
            {
                if (Pause)
                {
                    ew.WaitOne();
                    Pause = false;
                }
                Thread.Sleep(500);
                i += 1;
                if (label1.InvokeRequired)
                    label1.Invoke(new MethodInvoker(() =>
                        {
                            act(i);
                        }));
                else
                    act(i);
            }
        }
Настала пора немного рассказать про этот загадочный EventWaitHandle. Экземпляр данного класса имеет много методов, наиболее полезные из которых это - WaitOne() и Set(). WaitOne() служит для приостановки действия потока, а Set - для возобновления его работы с места остановки. По нажатию кнопки Старт у нас в пул потоков помещается метод, который будет выполнен в отдельном потоке. Если вы не знакомы с лямбда-выражениями, то советую вам побыстрее исправлять это, т.к лямбды - чрезвычайно упрощают написание кода. В метод ThreadMethod, который мы запускаем в новом потоке мы передаём в параметре число 100.

Особенность работы с WinForm в C# заключается в том что доступ к компоненту можно получить только из того потока. в котором данный компонент создан, соответственно, если попытаться достучаться из другого потока до свойств компонента не созданного в этом потоке,  то велика вероятность возникновения ошибок. Для решения этой проблемы у всех компонентов имеется метод Invoke в который необходимо передать делегат (ссылку на метод). Через свойство InvokeRequired проверяется необходимость доступа через Invoke, если InvokeRequired равен false значит метод можно запустить и без Invoke.
На кнопки Пауза и Стоп повесим код, соответственно:

private void button2_Click(object sender, EventArgs e)//PAUSE
        {
            Pause = true;
            button3.Enabled = false;
            button1.Enabled = true;
        }

        private void button3_Click(object sender, EventArgs e)//STOP
        {
            Stop = true;
            button2.Enabled = false;
            button1.Enabled = true;
        }

Что же делает наше приложение? По нажатию кнопки Старт у нас запускается поток в котором меняется свойство Text label'a с задержкой в 500mc. При нажатии на Паузу, булева переменная Pause становится равна истине и в ThreadMethhod'e поток приостанавливается при помощи WaitOne(). При нажатии Старт поток возобновляет работу с места остановки. При нажатии Стоп поток останавливается, уничтожается. Вот такое незамысловатое приложение

Исходники: http://dl.dropbox.com/u/16627362/threadPause.rar

Автор: Богданов М. 
13.07.2012



четверг, 12 июля 2012 г.

C#: Linq to Access


Linq - чудесная технология, суть которой заключается в манипулировании данными посредством Sql-подобного языка запросов. Для работы с базами данных используется так называемый Linq2Sql - это всё тот же Linq, но ориентированный на базы данных.

В этой статье мы попытаемся применить LINQ для работы с базой данных на Access. Почему Access? Просто LINQ по умолчанию поддерживает работу только с MS Server, чтобы заставить его работать с другими субд, надо немного попотеть.
Что ж, приступим...
Для начала я создал простецкую бд с двумя таблицами: Сотрудник и Должность. Соответственно, каждый сотрудник имеет свою фамилию, имя, отчество и должность, которая оценивается в денежном эквиваленте. Такая база данных создана только в качестве примера, дабы было на чём тренироваться при работе с Linq.


Как я уже говорил, Linq не предназначен для работы с Access. Чтобы заставить его работать с этой субд можно воспользоваться библиотекой Alinq, которую можно скачать по ссылке: http://www.alinq.org/download/ALinq_V2.6.2.msi
После установки, все необходимые файлы у меня разместились в C://ProgramFiles(x86)/alinq
Мы ещё будем обращаться к этому каталогу в ходе реализации приложения.
Итак, начнём создавать наше приложение. Надеюсь, вы сами сможете создать новый проект.
Далее нам необходимо подключить необходимые библиотеки для работы с Linq To Access. В Solution Explorer'e вызовем контекстное меню и выберем Add Reference. Далее на вкладке Browse  перейдём в каталог, куда установился Alinq и добавим 2 библиотеки: Alinq.Access.dll и Alinq.dll
В главной форме добавим ссылки на сборки:
using ALinq.Access;
using ALinq;

Далее нам нужно создать классы, которые соответствуют таблице в бд. Класс Worker имеет следующий вид:
using System;
using System.Collections.Generic;
using System.Text;
using ALinq.Mapping;

namespace LinqAccess1
{
    [Table(Name="Сотрудник")]
    public class Worker
    {
        [Column(Name="Код",IsDbGenerated=true, IsPrimaryKey=true)]
        public int ID{get;set;}

        [Column(Name="Фамилия")]
        public string FirstName{get;set;}

        [Column(Name="Имя")]
        public string Name{get;set;}

        [Column(Name="Отчество")]
        public string SecondName{get;set;}

        [Column(Name="Должность")]
        public int WorkType{get;set;}

    }
}

Немного поясню представленный код. В квадратных скобках указываются атрибуты свойств. Именно таким образом Linq может понять что класс Worker - это сущность, которая соответствует таблице Сотрудник. У таблицы есть поля, которые представлены полями в классе. Опять же, данные поля описаны соответствующими атрибутами, так например поле 
Код таблицы бд, представлено в классе полем:

[Column(Name="Код",IsDbGenerated=true, IsPrimaryKey=true)]

public int ID{get;set;};

Где в кв. скобках сказано (если переводить на вольный русский язык), что это поле соответствует полю "Код" в бд, это поле является первичным ключом.
Так как у нас в бд две таблицы, то необходимо создать ещё один класс - WorkTypes, который будет отвечать за таблицу Должность.
using System;
using System.Collections.Generic;
using System.Text;
using ALinq.Mapping;
namespace LinqAccess1
{
    [Table(Name="Должность")]
    public class WorkTypes
    {
        [Column(Name = "Код", IsPrimaryKey = true, IsDbGenerated = true)]
        public int ID { get; set; }

        [Column(Name = "Должность")]
        public string WorkTypeName { get; set; }

        [Column(Name = "Зарплата")]
        public int Zarplata { get; set; }
    }
}



После реализации соответствующих сущностей, попробуем отобразить содержимое этих таблиц. Кинем на форму dataGridView. Объявим глобальную переменную типа DataContext. Этот тип по отвечает за соединение с бд и за представление данных, находящихся в таблицах.

public partial class Form1 : Form
    {
        Table<Worker> workers;
        DataContext context;
        public Form1()
        {
            InitializeComponent();
            context = new DataContext(@"db1.mdb");


            workers = context.GetTable<Worker>();
            dataGridView1.DataSource = workers;                
        }
Здесь в конструкторе формы мы инициализируем переменную context, где в параметрах конструктора передаём путь до нашей базы данных. Далее мы получаем содержимое таблицы Сотрудник, и отображаем данные в гриде.
В гриде у нас отображается информация из таблицы Сотрудник, при этом мы не написали ни единого Sql-запроса. В столбце WorkType у нас находятся внешние ключи, эти двоечки, единички совершенно не радуют глаз, т.к не дают пользователю совершенно никакой информации о том, на какой должности работает сотрудник (откуда он может знать, что цифра 4 соответствует программисту..). Дабы решить эту проблему составим linq-запрос и повесим его на кнопку:
        private void button1_Click(object sender, EventArgs e)
        {
            IQueryable query=from person in workers join worktype in context.GetTable<WorkTypes>()
                              on person.WorkType equals worktype.ID select new {FirstN=person.FirstName,Name=person.Name,Second=
                                  person.SecondName,Worktype=worktype.WorkTypeName};

            dataGridView1.DataSource = query;
        }
Теперь в столбце WorkType отображается соответствующая должность, которую занимает сотрудник.
Пойдём ещё дальше, и составим запрос на выборку сотрудников, у которых з/п  >= значению в textBox'e
IQueryable q = from worker in workers
                           join worktype in context.GetTable<WorkTypes>() on
                           worker.WorkType equals worktype.ID
                           where worktype.Zarplata >= int.Parse(textBox1.Text)
                           select new
                           {
                               FirstName = worker.FirstName,
                               Name = worker.Name,
                               Worktype = worktype.WorkTypeName,
                               zarpl = worktype.Zarplata
                           };
            dataGridView1.DataSource = q;

В целом, тестовый пример готов. Наверняка у вас возникли сложности в понимании linq запросов, для этого рекомендую вам книгу Д.Албахари Карманный справочник по Linq в C#. Данная книга позволит вам в краткие сроки постичь Linq

Исходники: приложение не будет работать при не установленном Alinq!
http://dl.dropbox.com/u/16627362/LinqAccess1.rar

Автор:
Богданов М. 
12.07.2012