2013-11-14 4 views
0

У меня есть большой набор данных, который поддерживает мой пользовательский интерфейс, поэтому я решил создать фоновый вызов для заполнения моего локального репозитория и сразу же отобразить другие элементы управления в пользовательском интерфейсе и загрузить результаты асинхронного вызова, когда я получаю ответ.Реализация асинхронного вызова для долгого процесса MVC4

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

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

КОД ОБНОВЛЕНО

Я создал папку под названием службы и создали FacilitiesService.cs в этой папке, смотрите ниже:

public class FacilitiesService 
{ 
    internal async Task<List<Facility>> GetFacilitiesBySourceDbAsync(string sourceDb) 
    { 
     var fac = new Facility(); 

     var con = Connect(); // Omitted 

     try 
     { 
      con.Open(); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine("Error: GetFacilityBySourceDb " + ex.Message); 
     } 

     try 
     { 
      OracleDataReader reader = null; 
      // Requestor 
      var cmd = new OracleCommand("SELECT FACILITY, FACILITY_ID FROM MyTable where (source_db = '" + sourceDb + "')", con); 

      reader = cmd.ExecuteReader(); 

      while (reader.Read()) 
      { 
       fac.Add(new Facility() 
       { 
        FacilityName = reader["FACILITY"].ToString(), 
        FacilityId = reader["FACILITY_ID"].ToString() 
       }); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
     finally 
     { 
      con.Close(); 
      con.Dispose(); 
     } 

     return fac; 
    } 
} 

Тогда в моих HomeController.cs у меня есть следующие:

public class HomeController 
{ 
    public async Task<List<Facility>> FacilitiesAsync() 
    { 
     ViewBag.SyncOrAsync = "Asynchronous"; 
     var service = new FacilitiesService(); 

     this._facilities = new List<Facility>(); 

     var facilities = await service.GetFacilitiesBySourceDbAsync("TEST"); 

     foreach (var item in facilities) 
     { 
      Facility fac = new Facility() 
      { 
       FacilityName = item.FacilityName, 
       FacilityId = item.FacilityId 
      }; 

      _facilities.Add(fac); 
     } 

     return _facilities; 
    } 
} 

Это мой Объект (модель) Класс:

public class Facility : List<Facility> 
{ 
    [Required] 
    [Display(Name = "Facility")] 
    public string FacilityName { get; set; } 
    public string FacilityId { get; set; } 

    public Facility() 
    { 
     // Default Constructor 
    } 

    public Facility(string facilityName, string facilityId) 
    { 
     this.FacilityName = facilityName; 
     this.FacilityId = facilityId; 
    } 
} 

Я использую вызов Ajax пнуть метод FacilitiesAsync в коде от вызова функции на странице About.cshtml, когда язычки пользователя выключает управление tetbox/ввода с ИД «метки», я мог бы переключить это к чему-то еще позже, но я получаю данные назад, когда я пошагово код-позади и я вижу, как функции beforeSend и полный огонь предупреждение:

<script type="text/javascript"> 
$(function() { 
    var availableTags = [ 
    // Neeed data from function call to populate this list 
    ]; 
    $("#tags").autocomplete({ 
     source: availableTags 
    }); 
    $("#tags").focusout(function() { 
     var result = null; 
     $.ajax({ 
      beforeSend: function() { 
       alert("Testing"); 
      }, 
      url: "FacilitiesAsync", 
      success: function(data) { 
       result = data; 
      }, 
      complete: function() { 
       alert(result); 
      } 
     }); 
    }); 
}); 
</script> 

@using (Html.BeginForm()) { 
    <div class="ui-widget"> 
     <label for="tags">Tags: </label> 
     <input id="tags" /> 
    </div> 
} 

этот прекрасно работает! Тем не менее, я хочу взять данные из вызова, сделанного для кода, чтобы заполнить массив доступныхTags, и я не уверен, как это сделать. Предложения?

ответ

0

Есть несколько ошибок в реализации и одна проблема с подходом.

Во-первых, GetFacilitiesBySourceDbAsync не содержит await. Компилятор выдает предупреждение в этой ситуации, сообщая вам, что это не асинхронный метод, когда вы это делаете; он будет работать синхронно. Это важное предупреждение. Если вам нужен асинхронный код, вам необходимо сделать его асинхронным. Это означает использование асинхронных методов базы данных (ExecuteReaderAsync и т. Д.).

Во-вторых, Task.WhenAll звонок в Index не имеет смысла (поскольку вы выполняете только одну задачу). Кроме того, поскольку Index является синхронным, но вызывает асинхронный метод, код, который не показан, вероятно, вызывает Result, что нет-нет на ASP.NET. Как я объясняю в своем блоге, this will actually deadlock один раз ваш код async на самом деле асинхронный.

Но даже если вы исправите это, оно не будет делать то, что вы хотите. Есть проблема с подходом, и это то, что async doesn't change the HTTP protocol (это также ссылка на мой блог). ASP.NET MVC понимает асинхронные методы и не выполнит запрос до завершения действия метода async. Вам нужно будет использовать что-то вроде AJAX, чтобы заставить веб-страницу делать то, что вы хотите.

+0

Я полностью изменил подход. Пожалуйста, взгляните и сообщите мне свои мысли. –

+0

Теперь это вопрос JavaScript, а не вопрос 'async' ASP.NET MVC; вы можете задать новый более целенаправленный вопрос. В качестве общего ответа я предлагаю вам использовать обещания. –

+0

Хорошо, спасибо. Я задам еще один вопрос. –

Смежные вопросы