API Xero Accounting GetContactsAsyn c Не авторизован + Контакты не содержат определение экземпляра publi c для ошибки «GetEnumerator» - PullRequest
0 голосов
/ 29 февраля 2020

Я пытался узнать, как использовать API учетной записи, и решил загрузить и использовать образец XeroOAuth2Sample, предоставленный в документации. (https://github.com/XeroAPI/xero-netstandard-oauth2-samples)

Итак, в HomeController.cs есть пример метода HTTPGet, который используется для получения общего количества счетов из API, предоставленного документами Xero. Код выглядит следующим образом:

[HttpGet]
        [Authorize]
        public async Task<IActionResult> OutstandingInvoices()
        {
            var token = await _tokenStore.GetAccessTokenAsync(User.XeroUserId());

            var connections = await _xeroClient.GetConnectionsAsync(token);

            if (!connections.Any())
            {
                return RedirectToAction("NoTenants");
            }

            var data = new Dictionary<string, int>();

            foreach (var connection in connections)
            {
                var accessToken = token.AccessToken;
                var tenantId = connection.TenantId.ToString();

                var organisations = await _accountingApi.GetOrganisationsAsync(accessToken, tenantId);
                var organisationName = organisations._Organisations[0].Name;

                var outstandingInvoices = await _accountingApi.GetInvoicesAsync(accessToken, tenantId, statuses: new List<string>{"AUTHORISED"}, where: "Type == \"ACCREC\"");

                data[organisationName] = outstandingInvoices._Invoices.Count;
            }

            var model = new OutstandingInvoicesViewModel
            {
                Name = $"{User.FindFirstValue(ClaimTypes.GivenName)} {User.FindFirstValue(ClaimTypes.Surname)}",
                Data = data
            };

            return View(model);
        }

Поэтому я пытался попрактиковаться и изучить API, создав страницу, которая в конечном итоге вызывала бы контакты из конечной точки API. Я создал класс Contact.cs Model, который выглядит следующим образом:

public class Contact
    {
        public string ContactID { get; set; }
        public string ContactStatus { get; set; }
        public string Name { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string EmailAddress { get; set; }
        public string SkypeUserName { get; set; }
        public string BankAccountDetails { get; set; }
        public string TaxNumber { get; set; }
        public string AccountsReceivableTaxType { get; set; }
        public string AccountsPayableTaxType { get; set; }
        public List<Address> Addresses { get; set; }
        public List<Phone> Phones { get; set; }
        public DateTime UpdatedDateUTC { get; set; }
        public bool IsSupplier { get; set; }
        public bool IsCustomer { get; set; }
        public string DefaultCurrency { get; set; }
    }

Затем я создал ContactViewModel.cs, у которого есть свойства, которые я хочу позже отобразить на моей странице Razor View со следующим код:

public class ContactViewModel
    {
        public string ContactID { get; set; }
        public string ContactStatus { get; set; }
        public string Name { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public bool IsSupplier { get; set; }
        public bool IsCustomer { get; set; }
        public string DefaultCurrency { get; set; }
    }

И затем у меня есть ContactsViewModel, представляющий собой список контактов из ContactViewModel:

public class ContactsViewModel
    {
        public List<ContactViewModel> Contacts { get; set; }
    }

Так что мои проблемы возникают, когда я пытаюсь сделать / вызовите запрос HTTPGet для моих контактов, код выглядит следующим образом:

[HttpGet]
        [Authorize]
        public async Task<IActionResult> Contacts()
        {
            var token = await _tokenStore.GetAccessTokenAsync(User.XeroUserId());

            var connections = await _xeroClient.GetConnectionsAsync(token);

            if (!connections.Any())
            {
                return RedirectToAction("NoContacts");
            }   

            foreach (var connection in connections)
            {
                var accessToken = token.AccessToken;
                var tenantId = connection.TenantId.ToString();

                var contactList = await _accountingApi.GetContactsAsync(accessToken, tenantId);

                List<ContactsViewModel> contacts = new List<ContactsViewModel>();

                foreach (var contact in contactList)
                {
                    contacts.Add(new ContactViewModel
                    {
                        ContactID = contact.ContactID,
                        ContactStatus = contact.ContactStatus,
                        Name = contact.Name,
                        FirstName = contact.FirstName,
                        LastName = contact.LastName,
                        IsSupplier = contact.IsSupplier,
                        IsCustomer = contact.IsCustomer

                    });
                }
                contacts.AddRange(contactList);
            }
            var model = new ContactsViewModel()
            {
                //  Contacts = contacts
            };
            return View(model);

        }

Итак, первая ошибка выглядит следующим образом:

ApiException: Error calling GetContacts: {"title":"Unauthorized","status":401,"detail":"AuthorizationUnsuccessful","instance":"354ff497-d29f-468b-9e1c-4345e9ce8123"}

, которая возвращается из "GetContactsAsyn c "method:

var contactList = await _accountingApi.GetContactsAsync(accessToken, tenantId);

Я не уверен, есть ли определенные c значения, которые я пропускаю, и которые мне также нужно передать, что вызывает эту ошибку? Я не мог найти что-либо относительно этого в документации Xero. Хотя при наведении курсора на GetcontactsAsyn c отображается это для получения дополнительной информации:

(awaitable) Task<Xero.NetStandard.OAuth2.Model.Contacts> IAccountingApiAsync.GetContactsAsync(string accessToken, stringXeroTenantId, [System.DateTime? ifModifiedSince = null], [string where = null], [string order = null], [List<System.Guid> iDs = null], [int? page = null], [bool? includeArchived = null])

И, наконец, contactList, похоже, выдает ошибки, поскольку заголовок подсказывает, что касается "GetEnumerator" и когда контакты добавляются в contactsList при использовании AddRange эта ошибка отображается

cannot convert from 'Xero.NetStandard.OAuth2.Model.Contacts' to 'System.Collections.Generic.IEnumerable<XeroOAuth2Sample.Models.ContactsViewModel>'

Есть ли что-то, что я явно упускаю из GetContactsAsyn c, которое должно быть там? Заранее благодарю за чтение и помощь.

Ответы [ 2 ]

2 голосов
/ 29 февраля 2020

Конечной точке контактов требуется дополнительная область OAuth2.0, чем области по умолчанию, запрашиваемые в примере. Вы можете увидеть набор областей, которые использует образец, здесь: https://github.com/XeroAPI/xero-netstandard-oauth2-samples/blob/master/XeroOAuth2Sample/XeroOAuth2Sample/Startup.cs#L105L106

Вы можете увидеть полный набор областей, которые можно запросить в нашей документации здесь: https://developer.xero.com/documentation/oauth2/scopes

В вашем случае вам нужно будет использовать либо области accounting.contacts или accounting.contacts.read для чтения контактов, либо область accounting.contacts, если в конечном итоге вы захотите обновить / создать контакты

Редактировать: Если вы хотите только читать контакты, вам нужно запросить, и пользователь должен дать согласие на область accounting.contacts.read. Если вы хотите обновить / создать контакты, вам нужно запросить и дать пользователю согласие на доступ к области accounting.contacts. Область Accounting.Contacts предоставит доступ для чтения и записи

0 голосов
/ 01 марта 2020

Таким образом, после добавления дополнительных параметров в файл startup.cs:

options.Scope.Add("accounting.contacts");
options.Scope.Add("accounting.contacts.read");

Я снова прошел процесс регистрации xero, как и предлагал повторно представить новую область. Я думаю, что исправил синтаксис и некоторые незначительные логики c моего HTTPGet-метода Contacts () в HomeController.

 [HttpGet]
        [Authorize]
        public async Task<IActionResult> Contacts()
        {
            var token = await _tokenStore.GetAccessTokenAsync(User.XeroUserId());

            var connections = await _xeroClient.GetConnectionsAsync(token);

            ContactsViewModel contacts = new ContactsViewModel();
            contacts.Contacts = new List<ContactViewModel>();

            if (!connections.Any())
            {
                return RedirectToAction("NoContacts");
            }   

            foreach (var connection in connections)
            {
                var accessToken = token.AccessToken;
                var tenantId = connection.TenantId.ToString();

                Contacts contactList = await _accountingApi.GetContactsAsync(accessToken, tenantId);
                contacts.Contacts.AddRange(contactList._Contacts.Select(contact => new ContactViewModel()
                {
                    ContactID = contact.ContactID.ToString(),
                    ContactStatus = contact.ContactStatus.ToString(),
                    Name = contact.Name,
                    FirstName = contact.FirstName,
                    LastName = contact.LastName,
                    IsSupplier = contact.IsSupplier.Value,
                    IsCustomer = contact.IsCustomer.Value
                }).ToList());
            }

            return View(contacts);
        }
...