Прочитав статью Клиент для SOAP API Почты России на Python и воодушевленный подвигом ребят, а также располагая свободным временем, решено было сделать тоже самое.
Но на .NET, так как Visual Studio более адаптивна к веб-сервисам с описанием в wsdl.
Для получения информации по списку почтовых трекеров (trackid_list)
Создадим проект UnitTest:

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

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

После добавления у вас появится появится доступ к классу UnitTestProject_ruPost.ruPost.ItemDataService, а также в файл app.config будет добавлены настройки доступа к веб сервису.
Весь код написан к .NET 4.5
Напишем для этого тест:
Стоит заметить, что у меня нет возможности протестировать его без ошибки.
Так как я не обладаю логином и паролем к сервису и нет возможности его получить, поэтому результатом данного теста будет ошибка сервиса о не прошедшей авторизации.

В заключении хотелось бы отметить, что данная статья носит исключительно ознакомительный характер, про то как возможно реализовать доступ к сервису почты России с использованием .NET, так как ещё раз повторюсь, у меня нет официального доступа к сервису.
Всем, у кого есть замечания и предложения по доработке, прошу на git.
Но на .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.