2012-09-26 16 views
5

Mam metodę, która zwraca datatable. Myślałem, że przy użyciu .net 4.0 mógłbym asynchronizować logikę i zwracać dane. Ale ten kod zwraca null obiekt Dataable. Wszelkie pomysły na temat tego kodu.Powracaj DataTable za pomocą async .net 4.0

public DataTable GetData(string sql, string connectionName) 
{ 
    DataTable dt = (DataTable)GetDataAsync(sql, connectionName).AsyncState; 
    return dt; 
} 

private async Task<DataTable> GetDataAsync(string sql, string connectionName) 
{ 
    return await TaskEx.Run(() => { return FillData(sql, connectionName); }); 
} 

private DataTable FillData(string sql, string connectionName) 
{ 
    SqlConnection conn = _connections.Where(w => w.ConnectionName == connectionName).Single().Connection; 
    SqlDataAdapter adp = new SqlDataAdapter(sql, conn); 
    DataSet ds = new DataSet(); 

    adp.Fill(ds); 

    return ds.Tables[0]; 
} 
+0

Nie możesz użyć 'async' /' await' z .NET 4.0 lub C# 4. Jest to nowa funkcja w C# 5 i zależy od typów w .NET 4.5. –

+4

Jon - skoro używa TaskEx.Run, zgaduję, że używa się asynchronicznie kierowania pakiet, który umożliwia kierowanie 4,0 i asynchronicznie/czekają –

Odpowiedz

9

Po pierwsze, nie można używać async/await z .NET 4 lub C# 4. To nowa funkcja w C# 5. Były CTP, który zainstalowany na szczycie .NET 4, ale istnieją konkretne błędy w tych CTP-ach - nie korzystaj z nich przez. Powinieneś użyć pełnej wersji wydania .NET 4.5, która zawiera kompilator C# 5. (Wszystko to jest w Visual Studio 2012.)

Po drugie, używasz niewłaściwej właściwości zadania, jak pokazał Cuong Le. Właściwość Result to sposób uzyskania wyniku Task<T>.

Po trzecie, po wprowadzeniu zmiany w celu użycia właściwości Result, blokujesz pobieranie tabeli - co nie ma sensu. To:

public DataTable GetData(string sql, string connectionName) 
{ 
    DataTable dt = (DataTable)GetDataAsync(sql, connectionName).Result; 
    return dt; 
} 

... jest w dużej mierze równoważne:

public DataTable GetData(string sql, string connectionName) 
{ 
    return FillData(sql, connectionName); 
} 

Jeśli masz zamiar rozpocząć zadanie i natychmiast czekać na niego, równie dobrze można po prostu wywołać metodę synchronicznie.

+0

Ok, więc jak mogę to zrobić w .NET 3.5, jeśli może pomóc, że Jon? ? – Malcolm

+0

Miałem zamiar używać tylko 4.0 asynchronizacji, więc nie będę go teraz używał. – Malcolm

+0

@Malcolm: Jakiś powód, dla którego nie chcesz używać 4.5? –

2

Jeśli chcesz użyć kodu async, a następnie don't block on it. Upewnij się również, że używasz Async Targeting Pack, a nie asynchronicznego CTP.

private async Task<DataTable> GetDataAsync(string sql, string connectionName) 
{ 
    return await TaskEx.Run(() => { return FillData(sql, connectionName); }); 
} 

private async GetAndProcessDataAsync() 
{ 
    DataTable table = await GetDataAsync("my sql", "my connection name"); 
    ProcessData(table); 
} 
8

Mój własny kod źródłowy.

public static async Task<DataTable> GetDataTableAsync(this System.Data.Common.DbCommand command, CancellationToken cancellationToken, string tableName = null) 
    { 
     TaskCompletionSource<DataTable> source = new TaskCompletionSource<DataTable>(); 
     var resultTable = new DataTable(tableName ?? command.CommandText); 
     DbDataReader dataReader = null; 

     if (cancellationToken.IsCancellationRequested == true) 
     { 
      source.SetCanceled(); 

      await source.Task; 
     } 

     try 
     { 
      await command.Connection.OpenAsync(); 
      dataReader = await command.ExecuteReaderAsync(CommandBehavior.Default); 
      resultTable.Load(dataReader); 
      source.SetResult(resultTable); 
     } 
     catch (Exception ex) 
     { 
      source.SetException(ex); 
     } 
     finally 
     { 
      if (dataReader != null) 
       dataReader.Close(); 

      command.Connection.Close(); 
     } 

     return resultTable; 
    } 
+0

Miło, jednak należy również przekazać token anulowania do metod OpenAsync i ExecuteReaderAsync, aby anulować je również –

+0

Dziękuję za faktyczne dostarczenie rozwiązania. Skąd bierze się token anulowania? – toddmo

+0

Możesz użyć wzorca 'using', aby zamknąć wszystko za ciebie po wyrzuceniu. – toddmo