Как стать автором
Поиск
Написать публикацию
Обновить

Клиент для API Почты России на .NET

Прочитав статью Клиент для SOAP API Почты России на Python и воодушевленный подвигом ребят, а также располагая свободным временем, решено было сделать тоже самое.
Но на .NET, так как Visual Studio более адаптивна к веб-сервисам с описанием в wsdl.


Как работает

Для получения информации по списку почтовых трекеров (trackid_list)
  • необходимо получить номер билета (ticket_number), с указанием логина и пароля сервиса
  • запросить информацию с предъявлением выданного билета, с указанием логина и пароля сервиса


Подключаем Web Reference

Создадим проект UnitTest:



Добавим с помощью встроенных средств обертку на сервис vfc.russianpost.ru



Стоит отметить, что добавлять нужно именно WebReference.
С ServiceReference возникает проблема в приведении типов, так что, вероятно, сам сервис не поддерживает более новый формат.



После добавления у вас появится появится доступ к классу UnitTestProject_ruPost.ruPost.ItemDataService, а также в файл app.config будет добавлены настройки доступа к веб сервису.

Класс обертка RussianPostAgent

Весь код написан к .NET 4.5

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using UnitTestProject_ruPost.ruPost;


namespace UnitTestProject_ruPost
{
    /// <summary>
    /// Класс обертка для vfc.russianpost.ru
    /// </summary>
    public class RussianPostAgent
    {
        #region Внутренние объекты

        //Экземпляр клиента-сервиса        
        static readonly ItemDataService client = new ItemDataService();
        //Словари с описанием статусов
        static readonly Dictionary<int,string> _oper_types = new Dictionary<int,string>();
        static readonly Dictionary<int,string> _oper_categories = new Dictionary<int,string>();

        //Статический конструктор
        static RussianPostAgent()
        {
           _oper_types.Add(1,"Приём");
           _oper_types.Add(2,"Вручение");
           _oper_types.Add(3,"Возврат");
           _oper_types.Add(4,"Досылка почты");
           _oper_types.Add(5,"Невручение");
           _oper_types.Add(6,"Хранение");
           _oper_types.Add(7,"Временное хранение");
           _oper_types.Add(8,"Обработка");
           _oper_types.Add(9,"Импорт международной почты");
           _oper_types.Add(10,"Экспорт международной почты");
           _oper_types.Add(11,"Передано таможне");
           _oper_types.Add(12,"Неудачная попытка вручения");
           _oper_types.Add(13,"Регистрация отправки");
           _oper_types.Add(14,"Таможенное оформление завершено");
           _oper_types.Add(15,"Передача на временное хранение");
           _oper_types.Add(16,"Уничтожение");
            
           _oper_categories.Add(0,"Сортировка");
           _oper_categories.Add(1,"Вручение адресату");
           _oper_categories.Add(2,"Прибыло в место вручения");
           _oper_categories.Add(3,"Прибыло в сортировочный центр");
           _oper_categories.Add(4,"Покинуло сортировочный центр");
           _oper_categories.Add(5,"Прибыло в место международного обмена");
           _oper_categories.Add(6,"Покинуло место международного обмена");
           _oper_categories.Add(8,"Иное");
           _oper_categories.Add(9,"Адресат заберет отправление сам");
           _oper_categories.Add(10,"Нет адресата");
        }

        /// <summary>
        /// Получить соответствие ID из словаря если оно есть
        /// </summary>
        /// <param name="d">Словарь</param>
        /// <param name="id">ID</param>
        /// <returns></returns>
        static string _get_(IDictionary<int,string> d,string id)
        {
            int _id=-1;
            if (d!=null&&!string.IsNullOrEmpty(id)
                && int.TryParse(id, out _id)
                && d.ContainsKey(_id))
                return d[_id];
            return id;
        }

        /// <summary>
        /// Получить тип операции по ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        static string _get_oper_type(string id)
        {
            return _get_(_oper_types,id);
        }
        
        /// <summary>
        /// Получить категорию операции по ID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        static string _get_oper_category(string id)
        {
            return _get_(_oper_categories, id);
        }

        #endregion

        /// <summary>
        /// Получить детальную информацию о состояние почтовых трэков
        /// </summary>
        /// <param name="login">Логин в системе vfc.russianpost.ru</param>
        /// <param name="password">Пароль</param>
        /// <param name="trackid_list">Список trackid</param>        
        public static Task<dynamic> getStates(string login, string password, string[] trackid_list)
        {            
            //Если параметры пустые, то выходим
            if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password)
                || (trackid_list == null || trackid_list.Length == 0))
                return null;

            return Task.Factory.StartNew<dynamic>((Func<object,dynamic>)(
                (args) =>
                {
                    object result = null;

                    //Обработка ошибки
                    Func<object, bool> f_error =
                        e =>
                        {
                            if (e is error)
                            {
                                error _error = e as error;
                                //Установим результат с исключением
                                if (_error != null)
                                   result = new { Exception = string.Format("{0} (код ошибки:{1})",
                                                              _error.ErrorName,
                                                              _error.ErrorTypeID) };
                                return true;
                            }
                            return false;
                        };

                    //Запрос билета, на  доступ к детальной информации списка трэков
                    result = client.getTicket(
                          new file
                          {
                              DatePreparation = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"),
                              FileTypeID = "1",
                              FileName = "0",
                              SenderID = "0",
                              RecipientID = "1",
                              FileNumber = "0",
                              Item = trackid_list.Aggregate(new List<item>(), (l, i) =>
                              {
                                  l.Add(new item { Barcode = i });
                                  return l;
                              }).ToArray()
                          }
                          , login, password, "RUS");

                    //Если нет ошибки в ответе
                    //То по номеру выданного билета получим детальную информацию по списку трэков
                    if (!f_error(result) && result is string)
                    {                        
                        result = client.getResponseByTicket(result as string,
                                                            (args as string[])[0],
                                                            (args as string[])[1]);
                        if (!f_error(result)&&result is item)
                        {
                            item item = result as item;
                            //Вернем результат
                            return 
                            new
                            {
                                Exception = string.Empty, //Ошибка не указана
                                //Список операции
                                Operations = item.Operation.Aggregate(new List<object>(),
                                                        (a, o) =>
                                                        {
                                                            a.Add(new 
                                                                       {
                                                                         TrackID = item.Barcode, 
                                                                         Date = o.DateOper, 
                                                                         ID = o.IndexOper,
                                                                         Name = o.OperName, 
                                                                         Category = _get_oper_category(o.OperCtgID) 
                                                                        }
                                                                     );
                                                            return a;
                                                        }
                                                     ).ToArray(),
                                //Список ошибок
                                Errors = item.Error.Aggregate(new List<object>(),
                                                       (a, e) =>
                                                       {
                                                        a.Add(
                                                         new {
                                                                  TrackID = item.Barcode,
                                                                  Date = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"),
                                                                  ID = e.ErrorTypeID,
                                                                  Name = e.ErrorName
                                                                }
                                                                  );
                                                           return a;
                                                       }).ToArray()
                            };                         
                        }
                    }

                    return result;
                }), new string[] { login, password });
                

        
        }
    }
}




Тестируем класс-обертку

Напишем для этого тест:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;


namespace UnitTestProject_ruPost
{
    [TestClass]    
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            Task<dynamic> tStateTracks = RussianPostAgent.getStates(
                "[login]", "[password]",
                new string[] { //Список трэкеров
                               string.Empty.PadRight(13,"1"[0]), //"1111111111111"
                               string.Empty.PadRight(13,"2"[0]),
                               string.Empty.PadRight(13,"3"[0]),
                               string.Empty.PadRight(13,"4"[0]),
                             });
            //Ожидаем завершения задачи
            tStateTracks.Wait();
            
            //Получим результат выполнения 
            dynamic data = tStateTracks.Result;

            //Проверим его на ошибку
            string error = data.Exception as string;                   
            Assert.IsFalse(!string.IsNullOrEmpty(error), error);

            //Вывод результатов
            object[] operations = data.Operations;            
            object[] errors = data.Errors;
            foreach (dynamic oper in operations)
                       Assert.Inconclusive(
                           string.Format("TrackId:{0}\tDate:{1}\tID Oper:{2}\tOper Name:{3}\tCategory:{4}",
                           oper.TrackID,
                           oper.Date,
                           oper.ID,
                           oper.Name,
                           oper.Category
                           ));
                   foreach (dynamic err in errors)
                       Assert.Inconclusive(
                           string.Format("TrackId:{0}\tErrorID:{1}\tError:{2}",
                           err.TrackID,
                           err.ID,
                           err.Name
                           ));            
        }
    }
}



Стоит заметить, что у меня нет возможности протестировать его без ошибки.
Так как я не обладаю логином и паролем к сервису и нет возможности его получить, поэтому результатом данного теста будет ошибка сервиса о не прошедшей авторизации.



Заключение


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

Всем, у кого есть замечания и предложения по доработке, прошу на git.

В следующей статье мы поговорим, о реализации аналогичного асинхронного решения, но без обращения к веб-сервису почты России и с использованием antigate.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.