C# как захватить результаты асинхронных?

Я новичок в C# и пытаюсь использовать Lync SDK для программного поиска пользователя Lync, чтобы получить его статус. Я не уверен, как передать результаты в ответ веб-службы, когда выполняется асинхронный обратный вызов.

Это код:

Контроллер Webservice GET конечная точка:

        // GET: api/Lync/5
            public String Get(int id)
    {
        log.Info("[GET] Search for Lync User: " + id);

        Lync lync = new Lync();

        ////lync.signIn();
        Boolean isSignedIn = lync.isUserSignedIn();

        if (isSignedIn)
        {
            log.Info("User is Signed In");
            Console.Write("Enter search key : ");
            lync.Search("medina");

            //lync.Search("medina",
            //(lyncContacts) =>
            //{
            //    log.Debug("Search Results Callback fired!");
            //    log.Info("Results found: " + lyncContacts.Count);
            //    return lyncContacts.ToString();
            //});
            //Console.WriteLine(name);
            //Console.ReadLine();
            return "testUser";
        }
        else
        {
            log.Info("User is not Signed In!");
            // TODO: Return status 500
            return "testUser";
        }
        //Console.ReadLine();
        //return "testUser";
    }

Вышеуказанный метод вызывает бизнес-сервис lync.search(..), который выглядит следующим образом:

        public void Search(string searchKey)
    {
        List<LyncContact> contactList = new List<LyncContact>();
        //List<ContactInformationType> ContactInformationList = new List<ContactInformationType>();
        //ContactInformationList.Add(ContactInformationType.Activity);
        //ContactInformationList.Add(ContactInformationType.Availability);
        // ContactInformationList.Add(ContactInformationType.CapabilityString);

        //ContactSubscription contactSubscription = LyncClient.GetClient().ContactManager.CreateSubscription();

        Console.WriteLine("Searching for contacts on " + searchKey);

        LyncClient.GetClient().ContactManager.BeginSearch(
             searchKey,
             (ar) =>
             {
                 SearchResults searchResults = LyncClient.GetClient().ContactManager.EndSearch(ar);
                 if (searchResults.Contacts.Count > 0)
                 {
                     log.Info("Search results found: " + searchResults.Contacts.Count);

                     Console.WriteLine(searchResults.Contacts.Count.ToString() + " found");

                     foreach (Contact contact in searchResults.Contacts)
                     {
                         String displayName = contact.GetContactInformation(ContactInformationType.DisplayName).ToString();
                         ContactAvailability currentAvailability = (ContactAvailability)contact.GetContactInformation(ContactInformationType.Availability);

                         Console.WriteLine(
                              contact.GetContactInformation(ContactInformationType.DisplayName).ToString() + "   " + contact.GetContactInformation(ContactInformationType.Availability).ToString());

                         log.Debug("Display Name: " + displayName);
                         log.Debug("Availability: " + currentAvailability);
                         LyncContact lyncContact = new LyncContact.Builder().DisplayName("Snehil").Availability("Busy").build();

                         contactList.Add(lyncContact);
                         //done(contactList);
                     }
                     return;
                 }
                 else
                 {
                     log.Info("No Results found!");
                     //done(contactList);
                     return;
                 }
             },
             null);
    }      else
                 {
                     log.Info("No Results found!");
                     //done(contactList);
                     return;
                 }
             },
             null);
    }

Я пытался использовать Task+await, но мне трудно понять, как я могу вернуть результаты функции обратного вызова как результаты метода поиска. Как мне захватить это в классе контроллера?

2 ответа

Решение

Если вы хотите использовать шаблон async / await для этого использования Task.FromAsync https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.fromasync(v=vs.110).aspx

Гугл для примеров. Как это:

public async Task<List<LyncContact>> SearchAsync(string searchKey)
{
    List<LyncContact> contactList = new List<LyncContact>();

    Console.WriteLine("Searching for contacts on " + searchKey);

    var cm = LyncClient.GetClient().ContactManager;
    var searchResults = await Task<SearchResults>.Factory.FromAsync<String>(
        cm.BeginSearch,
        cm.EndSearch, searchKey, null);

    if (searchResults.Contacts.Count > 0)
    {

        Console.WriteLine(searchResults.Contacts.Count.ToString() + " found");

        foreach (Contact contact in searchResults.Contacts)
        {
            String displayName = contact.GetContactInformation(ContactInformationType.DisplayName).ToString();
            ContactAvailability currentAvailability = (ContactAvailability)contact.GetContactInformation(ContactInformationType.Availability);

            Console.WriteLine(
                 contact.GetContactInformation(ContactInformationType.DisplayName).ToString() + "   " + contact.GetContactInformation(ContactInformationType.Availability).ToString());

            LyncContact lyncContact = new LyncContact.Builder().DisplayName("Snehil").Availability("Busy").build();

            contactList.Add(lyncContact);
        }
    }

    return contactList
}

В контроллере вы можете сделать:

public async Task<String> Get(int id)
{
    log.Info("[GET] Search for Lync User: " + id);

    Lync lync = new Lync();

    ////lync.signIn();
    Boolean isSignedIn = lync.isUserSignedIn();

    if (isSignedIn)
    {
        log.Info("User is Signed In");
        Console.Write("Enter search key : ");
        var lyncContacts = await SearchAsync("medina");

        log.Info("Results found: " + lyncContacts.Count);
        return lyncContacts.ToString();
    }
    else
    {
        log.Info("User is not Signed In!");
        // TODO: Return status 500
        return "testUser";
    }
    //Console.ReadLine();
    //return "testUser";
}

Или вы можете использовать TaskCompletionSourceсм. http://blog.stephencleary.com/2012/07/async-interop-with-iasyncresult.html (предыдущий пост, но принцип все еще действует.

Предупреждение

Я не могу скомпилировать это, поскольку у меня нет доступа к библиотекам, которые вы используете. Это должно работать, но могут быть некоторые ошибки компиляции

Что оно делает

Как вы выяснили, обратные вызовы не очень хорошая модель для работы. с помощью задач и модели async / await работать намного проще. К счастью для нас с вами, они создали несколько методов, которые могут служить мостом между старой и новой моделью. Используя Task.FromAsync, вы можете преобразовать методы IAsyncResult в более простую в использовании методологию на основе задач. Стивен Клири написал несколько хороших блогов о них. Смотрите пост, о котором я упоминал ранее.

Похоже, что, посмотрев на закомментированный код, вы попытались предоставить своего рода обратный вызов вашему Search функция. Это будет работать, это должно быть типа Action<Microsoft.Lync.Model.SearchResults>

public void Search(string searchKey, Action<SearchResults> callback)
{
   ....
   LyncClient.GetClient().ContactManager.BeginSearch(
             searchKey,
             (ar) =>
             {
                 SearchResults searchResults = LyncClient.GetClient().ContactManager.EndSearch(ar);
                 callback(searchResults);
             });
   ....
}

Затем просто раскомментируйте код в вашем контроллере:

lync.Search("medina",
        (lyncContacts) =>
        {
            log.Debug("Search Results Callback fired!");
            log.Info("Results found: " + lyncContacts.AllResults.Count);                
        });
Другие вопросы по тегам