Показаны сообщения с ярлыком C#. Показать все сообщения
Показаны сообщения с ярлыком C#. Показать все сообщения

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

FAQ Narrator in WPF

The built-in Narrator in Windows 10 and Windows 11 is launched by the "LeftCtrl + Win + Enter" shortcut.

Links:

Complete guide to Narrator

Accessibility best practices

In the app window, the control that is in focus is voiced. Also, the Windows narrator voices every key pressed.

In Windows 7, only the specified control name is pronounced. 

Narrator is missing out of the box in Windows 7 SP1 without updates and the very first versions of Windows 10.

1. Narrator announces the type of the selected control, followed by it's name. 

The voiced name is set using the AutomationProperties.Name property. 

For example:

    AutomationProperties.Name = "Login"

For custom controls, you need to write the type yourself. Otherwise, "Custom" will be pronounced.

Example:

Create a class

    public class ToggleSwitchControlAutomationPeer : UserControlAutomationPeer {

        public ToggleSwitchControlAutomationPeer(ToggleButton owner) :

            base(owner) { }

        protected override string GetLocalizedControlTypeCore() {

            return "Toggle switch";

        }

    }

And in control itself

    protected override AutomationPeer OnCreateAutomationPeer() {

        return new ToggleSwitchControlAutomationPeer(this);

    }


2. Recommendation:

Add the app name to the main window and, if possible, to all windows of the application. 

Otherwise, there will be a faceless "MainWindow" or "Login Window".

For example:

"YourApplication MainWindow" or "BestApp Login Window"


3.

By default, the Windows narrator repeats the name of the control, so you don't need to add it to the designation.


4.

With the PasswordBox control (and some more) in the .Net Framework up to 4.7.1 trouble. There are actually three outputs:

a) Updating .Net Framework.

b) Add our own control in which we use the textbox.

c) We use a textbox with a special font (for a password, but potentially unsafe).

https://github.com/dotnet/docs/blob/main/docs/framework/whats-new/whats-new-in-accessibility.md

In .NET Framework 4.7 and earlier versions, xref:System.Windows.Controls.PasswordBox controls were announced as "no item in view" or had otherwise incorrect behavior

5.

Try to use short, clear phrases. No abbreviations, acronyms, compound words.

среда, 25 августа 2021 г.

Figma to WPF XAML

 0. Go to figma

1. Press to the need element

2. (If the element consists of several, then select the group

3. Press Export

4. Select SVG

5. Press Export

6. Open Inkscape

7. Select all elements - Resize page to selection

8. Select all elements - Group

9. File - Save As - Save as type - Microsoft XAML

10. Paste file to Visual Studio




среда, 27 февраля 2019 г.

Строки в компоненте DataGrid разного размера (Compact Framework)

Вводная: Есть проект для ТСД Windows Mobile 6.5 на .Net Compact Framework 3. И в нём есть DataGrid с некоторыми данным. Но проблема в том, что в данной версии фреймворка нельзя задать высоту для конкретной строки или авторасширение по контенту.

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



Решение: Напрямую мы не можем обращаться к высоте каждой строки. Но такой параметр ЕСТЬ, правда он с приватным модификатором доступа, поэтому придётся немного схитрить

Добавим после заполнения данными (dataGrid1.DataSource = dataTable;) 
такой код
//Здесь получаем все строки 
var allRows = (ArrayList)dataGrid1
   .GetType()
                        .GetField("m_rlrow", BindingFlags.NonPublic
                                           | BindingFlags.Static
                                           | BindingFlags.Instance)
                        .GetValue(dataGrid1);
 
//Здесь формируем массив строк для обработки с их индексами
foreach (var pair in dataTable.Rows.Cast<DataRow>()
                                   .Select((r, i) => new {Row = r, Index = i})
                                   //Указываем параметр по которому увеличиваем размер строки
                                   .Where(x => x.Row["Type"].ToString().Contains("\n")))
{
 int index = pair.Index;
        //Эдесь мы можем получить доступ к строке если надо
        //DataRow row = pair.Row;
        SetGridRowHeight(allRows[index], 60);
 
}

Далее сама функция изменения размера
public static void SetGridRowHeight(object row, int height)
{
    row.GetType().GetField("m_cy", BindingFlags.NonPublic
                                 | BindingFlags.Static
                                 | BindingFlags.Instance)
                 .SetValue(row, height);
}
 

И результат:




среда, 5 сентября 2018 г.

Доступ в интернет с эмулятора Windows Mobile 6 на Windows 10

Вводная: Есть ТСД, штука дорогая, защищённая, с мощными батареями и главное в наличии. "Покупать другие не предлагать". Разработка для них знакома и не представляет сложности. Все поставилось, но софт требует доступа к интернет-серверу (REST-api, все дела). А его нет! Проблема в том, что доступ к сети реализован через VirtualPC 2007, которая в Windows 10 не работают от слова вообще.

Но выход есть:
1. Ставим локальный прокси. Я рекомендую Fiddler https://www.telerik.com/fiddler

2. Запускать от админа, потом в меню Tools -> Options -> Connections 

3. Обязательно указываем "Allow remote computers to connect"


4. Запускаем Microsoft Device Emulator Manager 9 (входит в состав Microsoft Device Emulator 3.0 https://www.microsoft.com/ru-ru/download/details.aspx?id=5352 )

5. Выбираем наш эмулятор и в контекстном меню выбираем Cradle

6. Должен открыться "Центр устройств Windows Mobile" https://www.microsoft.com/ru-ru/download/details.aspx?id=3182

7. В нём выбираем "Подключение без настройки устройства"


8. На эмуляторе Settings -> Connections -> Connections -> Edit my proxy server

9. Указываем Ip адрес компьютера на котором запущен Fiddler и дважды нажимаем OK



10. Пробуем выходить в интернет

PS: Минус у этого решения есть и достаточно серъёзный - это всё надо делать каждый раз после перезапуска компьютера. Но автоматизируется легко. AutoIt или на том-же C#.

PS2: Кстати при наличии лицензионного ключа на 2008 Professional пришлось ставить пиратскую. Мой серийник, честно купленный в 2010 году, все найденные дистрибутивы просто отказались принимать :(

воскресенье, 10 июня 2018 г.

Разбиение файла импорта 1С на сайт на части

Вводная: Есть хостинг, есть сайт у сайта есть импорт товаров из 1С. Из 1С УТ файлы выгружаются, через стандартный механизм обмена с web-сайтом.
Но скрипту импорта периодически не хватает памяти, чтобы загрузить всё. И падает с ошибкой. Было решено "разбивать" файлы на части по 1000 товаров. И загружать последовательно.

Решение:
            Directory.EnumerateFiles(Environment.CurrentDirectory)
                     .Where(file => Path.GetFileName(file).StartsWith("output")).ToList()
                     .ForEach(File.Delete);
            
            XDocument source = XDocument.Load("import.xml");

            int iteration = 0;

            while (iteration * 1000 < source.Descendants("Товар").Count())
            {
                XDocument xdoc = new XDocument(source);

                var allElements = xdoc.Descendants("Товар").OrderBy(a => a.Element("Ид")?.Value);

                var whatToLeave = xdoc
                                    .Descendants("Товар")
                                    .OrderBy(w => w.Element("Ид")?.Value)
                                    .Skip(1000 * iteration).Take(1000);

                allElements.Except(whatToLeave).ToList().ForEach(e => e.Remove());

                iteration++;
                xdoc.Save($"output{iteration}.xml");
            }

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

Удаление папок по времени

Вводная: Делаю для себя небольшую систему резервного копирования. Задача - удалять старые папки-даты при добавлении новых. По алгоритму - оставляем только 15 последних папок, остальные удаляем.

Решение: На вход подаётся List класса BackupDirectoryInfo. Просто DirectoryInfo не используется, так как в качестве хранилища бэкапа используются и файловые ресурсы, и облачные хранилища. Если требуется использовать только папки на физическом диске, то можно обойтись одним DirectoryInfo.

public abstract class BackupDirectoryInfo
{
     public string Name;
     public string Path;
     public DateTime CreatedTime;

     public abstract void Delete();
}
private void DeleteOldFolder(List<BackupDirectoryInfo> dirs )
{
    var orderedList = dirs.OrderByDescending(x => x.CreatedTime)
                      .Take(15);

    var dirToDelete = dirs.Except(orderedList).ToList();
            
    dirToDelete.ForEach(x => x.Delete() );
}

суббота, 30 декабря 2017 г.

Заполнить базу в MS SQL тестовыми данными

Вводная: сабж.

Решение:
USE [testBackup]
GO

DECLARE @count INT 
SET @count = 1

WHILE @count <= 100000
BEGIN
INSERT INTO [dbo].[Table_1]
    SELECT 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + 
            CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) + CHAR((ABS(CHECKSUM(NEWID())) % 26) + 97) [Test]
    SET @count += 1
END
GO

Ну и удаление
USE [testBackup];
GO
DELETE FROM [dbo].[Table_1];
GO

четверг, 1 декабря 2016 г.

Тестовая задача C# - создание самораспаковывающегося архива

Реализовать программу, которая создаёт самораспаковывающийся архив.

  1. Тип результирующего файла - exe.
  2. Одного файла должно быть достаточно, чтобы передать его для извлечения в другом месте.
  3. При старте спрашивает папку в которую распаковать.
  4. Сжатие любое, но должно присутствовать.
  5. Программа должна уметь создавать архив из произвольного количества папок и файлов, произвольного типа.

Сторонние библиотеки использовать нелья, только Net.Framework (любая версия на ваш выбор).


четверг, 23 июня 2016 г.

Небольшой FAQ про локализацию текста в приложениях при разработке в C# Mono на Linux

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

2. По умолчанию тип проекта "Translation Project" в списке не отображается, чтобы он появился надо включить его в Tools - Add-in Manager - Gettext Translation Support.

3. То что указано в Mono.Unix.Catalog.GetString("Hello World!") является одновременно и именем, и значением по умолчанию (которое используется, если в переводе не найдено)

4. При разработке в GTK# и использовании графической разработки, дизайнер автоматически подставляет GetString, вместо отображаемого значения.

5. По умолчанию имя ВСЕХ проектов переводов - "i8n1", можете поменять в свойствах Translation Project. Также в опциях можно указать в какой католог кидать переводы + увидеть строку для инициализации

6. Для указания где брать переводы используется команда
Mono.Unix.Catalog.Init ("i8n1", "./locale");

7. Чтобы указать в приложении конкретный язык нужно до инициализации (и назначения значений переменных) выполнить
Environment.SetEnvironmentVariable ("LANGUAGE", "ru");

8. Можно сменить язык во время работы приложения. Но для этого нужно заново указать все компоненты (для примера у нас есть три элемента label)


protected void OnButtonRUClicked (object sender, EventArgs e)
{
 Environment.SetEnvironmentVariable ("LANGUAGE", "ru");
 Mono.Unix.Catalog.Init ("i8n1", "./locale");
 nameUpdate ();
}

protected void OnButtonENClicked (object sender, EventArgs e)
{
 Environment.SetEnvironmentVariable ("LANGUAGE", "en");
 Mono.Unix.Catalog.Init ("i8n1", "./locale");
 nameUpdate ();
}

void nameUpdate()
{
 label1.LabelProp = global::Mono.Unix.Catalog.GetString ("label1");
 label2.LabelProp = global::Mono.Unix.Catalog.GetString ("label2");
 label3.LabelProp = global::Mono.Unix.Catalog.GetString ("label3");
}

9. Если после создания проекта перевода в основном проекте были добавлены компоненты которые нужно переводить, то чтобы они появились в ранее созданом проекте перевода нужно просто щелкнуть правой кнопкой на нём и выбрать "Update Translations"

10. На текст перевода распространяются ограничения обычного текста в коде. То есть спецсимволы, такие как "\" или сами кавычки нужно экранировть.

11. Вы можете в любом месте проекта сделать
string str = global::Mono.Unix.Catalog.GetString ("TestMessage");
затем сделать Update Translations и новое сообщение появится для перевода

12. В переводах допустима подстановка -
string str = global::Mono.Unix.Catalog.GetString ("Hello {0}!");
string str2 = string.Format (str, "World");

пятница, 10 июня 2016 г.

Тестовая задача на программиста C# №2

Что выведет этот код. Почему? Есть ли здесь ошибка? Если есть то какая и как исправить?

void Main()
{   
   var Ref1 = new SomeClass { Val = 111 };
   var Ref2 = Ref1;

   Ref2.Val += 1;
   
   Console.WriteLine(Ref1.Val);
   Console.WriteLine(Ref2.Val);
}

public class SomeClass { public int Val; }

понедельник, 11 апреля 2016 г.

Тестовая задача на программиста C#

Периодически прохожу разные собеседования на программиста C#. Буду выкладывать тестовые задание и/или вопросы с собеседования. 

Задача: Пусть есть БД с 2 таблицами
В таблице 1 находится информация по номерам:

  • ID - идентификатор строки таблицы, 
  • номер
  • цена за час
  • его описание 

В таблицу 2 заносятся операции по бронированию:

  • ссылка на ID номера
  • дата начала бронирование
  • дата окончания бронирования

Реализовать автоматический расчёт стоимости при создании брони.

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

Сторонние библиотеки использовать разрешается. БД можно использовать любую.

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

Срок - 3 дня.

среда, 20 января 2016 г.

Программная отчистка корзины Яндекс.Диск

Вводная: Когда-то давно случился у Яндекс.Диска небольшой конфуз http://habrahabr.ru/post/204580/ после которого пользователям выдали 200 Гб места. Что сделало его очень удобным для удалённого бэкапа небольших баз. Но как всегда есть одно - НО. И но это заключается в методе удаления файлов с яндекс.диска. https://yandex.ru/support/disk/desktop/faq.xml#delete Грубо говоря, при удалении файлов, они не удаляются, а переносятся в корзину, где и хранятся 30 дней. Но если у вас бэкап занимает около 10 гигабайт и вы храните 10 предыдущих копий, то уже через дней 20 весь яндекс.диск будет у вас заполнен и после чего просто ПРЕКРАТИТ СИНХРОНИЗИРОВАТЬ. При этом выкидывая попап, что место на яндекс диске закончилось - но если это сервер, то на него могут месяцами не заходить и узнать об отсутствии бэкапов слишком поздно. Так что надо корзину чистить, но стандартными средствами есть два выбора - либо через сайт, либо через правую кнопку мыши на папке яндекс.корзины. И оба способа для сервера не очень подходят.

Решение: Создаём консольный проект. У меня имя проекта - clearYandexDiskTrash

Устанавливаем через NuGet библиотеку yandexdisk.client.
Или скачиваем с сайта https://github.com/raidenyn/yandexdisk.client и устанавливаем вручную.
Библиотека требует .NetFramework версии 4.6, так что нужно чтобы в свойствах проекта была именно она.

Заодно, также в свойствах проекта, перейдём на вкладку Settings и добавим настройку с именем yandexDiskToken.

Далее код -

using System;
using System.Threading;
using clearYandexDiskTrash.Properties;

using YandexDisk.Client;
using YandexDisk.Client.Http;

namespace clearYandexDiskTrash
{
  class Program
  {
    static void Main()
    {
      try
      {
        //You should have oauth token from Yandex Passport.
        //See https://tech.yandex.ru/oauth/
        string oauthToken = Settings.Default.yandexDiskToken;

        // Create a client instance
        using (IDiskApi diskApi = new DiskHttpApi(oauthToken))
        {
           var x = diskApi.Commands.EmptyTrashAsync("", CancellationToken.None);
        }
      }
      catch(Exception ex)
      {
         Console.WriteLine("Application clearYandexDiskTrash error." + " Message: " + ex.Message);
      }
    }
  }
}

Теперь запускаем и переходим в папку с скомпилированной программой. Там должен появится файл - clearYandexDiskTrash.exe.config. Открываем его блокнотом и изменяем параметр yandexDiskToken на наш. Который мы можем получить на сайте яндекса - https://tech.yandex.ru/oauth/ (но для быстроты и если нужно написать "для себя", то проще и быстрее получить токен на https://tech.yandex.ru/disk/poligon/ )

Далее не забываем поменять настройки бэкапов, чтобы программа запускалась перед выполнением бэкапа. И проверить выполнение. И ещё раз проверить через несколько дней.

понедельник, 21 декабря 2015 г.

Использование ВК для логгирования через C#

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

Решение: Для начала нужна зарегистрированная страница в VK. Переходим по ссылке https://vk.com/apps?act=manage и нажимаем "Создать приложение". Название пусть будет "vkLogSend", тип "Standalone-приложение".

Придёт смс с кодом, который нужно указать. Далее переходим во вкладку "Настройки" и сохраняем куда-нибудь "ID приложения", в нашем случае 1111111.



На этом работа с сайтом закончена и можем переходить непосредственно к программированию.

Открываем Visual Studio и создаём консольный проект vkLogSend. Далее сразу можно перейти в NuGet и установить два пакета - VkNet (реализация ВКонтакте API для .NET) и NLog (библиотека логгирования для C#).

Далее создаём класс с именем "vkTarget.cs" и содержанием -

using System;

using NLog;
using NLog.Targets;

using VkNet;
using VkNet.Enums.Filters;

namespace vkLogSend
{
    [Target("vk")]
    public sealed class VKTarget : TargetWithLayout
    {
        public VKTarget() { }

        protected override void Write(LogEventInfo logEvent)
        {
            var logMessage = this.Layout.Render(logEvent);

            SendTheMessageToRemoteHost(logMessage);
        }

        [STAThread]
        private void SendTheMessageToRemoteHost(string message)
        {
            var appId = 111111; // указываем id приложения
            var email = "user@mail.com"; // email для авторизации
            var password = "Pa$$w00rd"; // пароль
            var settings = Settings.Messages; // уровень доступа к данным

            var api = new VkApi();

            api.Authorize(appId, email, password, settings); // авторизуемся

            api.Messages.Send(1111111, false, message); // посылаем сообщение пользователю
        }
    }
}

Теперь нужно создать правила для NLog, это делается через создание файла NLog.config, в нашем примере пусть будет два правила: вывод на консоль и отправка в ВК -

<?xml version="1.0" encoding="utf-8" ?>

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <extensions>
    <add assembly="vkLogSend"/>
  </extensions>

  <targets>
    <target name="console" xsi:type="Console" layout="${date:format=HH\:mm\:ss} | ${level} | ${message}" />
    <target name="vk" type="vk" layout="${date:format=HH\:mm\:ss} | ${level} | ${message}"/>
  </targets>

  <rules>
    <logger name="*" minlevel="Trace" writeTo="console" />
    <logger name="*" minlevel="Trace" writeTo="vk" />
  </rules>

</nlog>

По сути стандартный файл NLog с добавленной секцией <extensions> и прописывание правила для таргета "vk"

И напоследок использование -


using System;
using NLog;

namespace vkLogSend
{
    class Program
    {
        static Logger logger = LogManager.GetCurrentClassLogger();

        static void Main()
        {
            logger.Trace("vkLogSend test message. Error on machine: " + Environment.MachineName);
            Console.WriteLine("Press any key..."); Console.ReadKey();
        }
    }
}

И у нас ничего не работает :) В библиотеке VkNet, при установке через NuGet есть ошибка - устанавливаются библиотеки Newtonsoft.Json и HtmlAgilityPack неверных версий. Решение простое - через NuGet обновляем их до последних и всё должно заработать.

После обновления библиотек можем тестировать и отправлять себе логи через Вконтакт.

\



PS: Есть нюанс при работе - если у вас настроено подтверждение входа (через смс или другим способом), то данный код работать не будет. Имейте это в виду.

среда, 14 октября 2015 г.

Неверное отображение WPF программы в классической теме оформления Windows

Иногда при разработке на C# использованием WPF возникает проблема с отображением окон, особенно если используются не стандартные компоненты, а какие нибудь свои, либо измененные стандартные. Для примера создадим окно с одним TabControl`ом и парой TabItem`ов. Добавим кнопки и пару элементов. Окно при использовании стандартной темы Windows 7

При использовании темы Aero все будет выглядеть вполне нормально, но если мы запустим программу при использовании темы Classic (к примеру на почти всех серверных ОC тема по умолчанию именно классическая), то отображение будет не очень корректным -

Для исправления данной проблемы сделаем следующее -
В References добавим ссылку на PresentationFramework.Aero и добавим следующий код -

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component/themes/aero.normalcolor.xaml" />
    </ResourceDictionary.MergedDictionaries>

Обычно этого достаточно, но если у вас используется директива Style и вы забыли (или не стали определять директиву BasedOn) то будет выглядеть в классической вот так -

У вас в таком случае два выхода -
1. В файле где у вас определены стили нужно немного их переписать -
если было - <Style x:Key="TabItemStyle" TargetType="TabItem">
Надо добавить директиву BasedOn
 <Style x:Key="TabItemStyle" TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
2. Либо полностью прописать нужный стиль, как должны выглядить элементы.

Теперь программа выглядит корректно при любой теме.

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

Проверка контрагента через налоговую с помощью C#

Вводная: Есть сервис у налоговой "Проверка контрагента" http://npchk.nalog.ru/ В 1С, в свежих релизах он реализован по умолчанию. Но надо было добавить данный функционал в программу на языке C#. Описание работы с сервисом и возможные варианты ответов можно посмотреть по ссылке http://npchk.nalog.ru/ws2.doc

Решение: Для начала создадим пустой проект.
1. В свойствах текущего решения надо добавить ссылку на сервис (в свойствах решения Add -> Service Reference)

2. В качестве ссылки вставляем ссылку на WSDL схему http://npchk.nalog.ru/FNSNDSCAWS_2?wsdl
Студия сама должна найти методы и сгенерировать большую часть кода. Также на этом шаге можем указать имя для сервиса (в нашем примере будет ServiceFNS). Нажимаем OK

3. Переходим к непосредственному редактированию кода. Переходим в Form1 и добавляем ссылку на созданный нами интерфейс для обращения к сервису
using npChkExample.ServiceFNS;

4. Теперь добавим на форму кнопку и напишем простейший обработчик для проверки одного контрагента. Код достаточно простой.

  • Создаём объект по конкретному контрагенту (NdsRequest2NP), 
  • передаём его в массив (NdsRequest2NP[]) 
  • и делаем запрос к сервису - (new FNSNDSCAWS2_PortClient().NdsRequest2(sList)).
  • Вывод результата.

var s = new NdsRequest2NP{
 INN = "7536134094",
        KPP = "753601001",
        DT  = "03.10.2015"
};
 
NdsRequest2NP[] sList = { s };
var s2 = new FNSNDSCAWS2_PortClient().NdsRequest2(sList);
MessageBox.Show(s2.NP.First().State.ToString());


В качестве ответа на запрос возвращается тот же список контрагентов, что и в запросе, в который
для записи о каждом контрагенте добавлен признак состояния (атрибут State), принимающий
значения:
0 - Налогоплательщик зарегистрирован в ЕГРН и имел статус действующего в указанную дату
1 - Налогоплательщик зарегистрирован в ЕГРН, но не имел статус действующего в указанную
дату
2 - Налогоплательщик зарегистрирован в ЕГРН
3 - Налогоплательщик с указанным ИНН зарегистрирован в ЕГРН, КПП не соответствует ИНН
или не указан
4 - Налогоплательщик с указанным ИНН не зарегистрирован в ЕГРН
5 - Некорректный ИНН
6 - Недопустимое количество символов ИНН
7 - Недопустимое количество символов КПП
8 - Недопустимые символы в ИНН
9 - Недопустимые символы в КПП
10 - КПП не должен использоваться при проверке ИП
11 - некорректный формат даты
12 - некорректная дата (ранее 01.01.1991 или позднее текущей даты)

В нашем случае в качестве ответа нам будет выведено Item0, что согласно описанию сервиса означает "Налогоплательщик зарегистрирован в ЕГРН и имел статус действующего в указанную дату". Что соответствует реальному положению дел.

5. Если надо проверить несколько юрлиц, то нужно предварительно добавить в массив больше (можно одновременно до 10000 за раз) (можно и по одному, но ждать очень долго придётся:) )


PS: В реальной программе лучше использовать Async версию запроса, чтобы не вызывать блокировку программы.

суббота, 26 сентября 2015 г.

Немного мыслей про логгирование в приложениях на C#

Предположим вы решили писать какую-то программу, небольшую утилиту. И даже прикрутили к ней лог. И даже не стали писать свой велосипед, а взяли какую-нибудь отлаженную и хорошую библиотеку (в моём случае NLog http://nlog-project.org ). Так вот в первые строчки лога после запуска вбивайте "ВРЕМЯ-Название-ВЕРСИЮ-ОСНОВНЫЕ НАСТРОЙКИ".

Объясню почему -

  • Название - чтобы когда вам просто тупо скинули файл лога (ещё и переименовав его как-нибудь "Лог.ткст", то вы из первой строчки могли вытащить хоть какую то инфу от чего этот лог )))
  • Время - чтобы понимать, что лог актуальный, а то бывает вообще программа не работает и лог от старой версии. А вы смотрите в него и в нём всё нормально.
  • Версию - похоже на предыдущий пункт, но немного другое. Бывает, что человек, которому вы делаете программу и выкатили новый релиз, на вас ругается, что новый функционал не работает. А в логах чисто. И пользователь утверждает, что таки да - "ОБНОВИЛ, Мамой клянусь". Так вот. Бывает, что не обновляет. Бывает сам закосячишь и в апдейторе забудешь предварительно закрыть предварительно программу если открыта (а винда не даст вам просто взять и перезаписать, запущенный файл). А косяки прут. Дополнительно можно вставлять версию операционнки, особенно если есть "зависимый" функционал (то есть работает только выше 7, XP мимо и прочее такое). Сюда же можно всякое про браузеры, антивирусы и прочее что влияет на работу программы. 
  • Основные настройки - все особо смысла нет (разве что при дотошной отладке, обычно если место хранение настроек едино и прочиталась одна, то и все остальные тоже. Но не факт) А для чего? Чтобы убедиться, что программа считывает настройки и не пытается работать с настройками по умолчанию. И не подключается к удалённому серверу БД не потому, что "файрволл, нет клиенсткой библиотеки и прочее блядство", а просто потому, что пробует подключиться на дефолтный локалхост

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

Ну и пункт выходящий из предыдущего пункт - пусть логгирование дебаг уровня будет вместо комментариев :) Тоже достаточно интересный финт ИМХО.

Дополнительно нужно не забывать про права записи для логов. И пробовать запускать программу от ограниченного (в правах) пользователя. Так как если программа ставится в Program Files и логи пишутся в папку с программой, то можно поймать трабл когда логи не будут писаться. А учитывая, что вывод в лог часто в самом начале программы, то может получится, что будет ошибка на запись и программа просто будет вылетать при запуске не оставляя логов. Но при этом во время разработки глюков не будет никаких.

Добавлено 12.10.2015:
Ещё нужно давать возможность совсем отключать логи. Это может потребоваться в разных ситуациях, начиная от запрета на запись из соображений безопасности, кончая увеличением ресурса SSD или увеличением скорости работы.

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

Ограничение размера логов - ОЧЕНЬ желательно реализовывать систему "обрезки" логов, либо по размеру, либо по дате. Иначе рано или поздно вы просто забьёте пользователю всё свободное место на диске. Да и работать с лог-файлами размером в пару десятков-сотен гигабайт очень неудобно