2013-05-17 3 views
1

Я не уверен, что использовать в этом сценарии.Что я должен здесь использовать? Threading? Асинхронный?

У меня есть метод asp.net Web API, который в основном делает это

  1. Находит точку интересов от четыреугольного вблизи пользователя.
  2. Использует места расположения четырехквартирных домов, чтобы делать запросы в моей базе данных, чтобы найти уникальные данные о достопримечательностях рядом с пользователем.

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

Это означает что-то новое, что приходит в меня, я должен вставить в свою базу данных, проверить, существует ли она, и если да, то пропустите ее или если она существует, проверьте последнюю дату обновления (в соответствии с условиями четырехсоставной политики все данные должны быть обновлены после 30 дней), и если он закончил дату обновления, я должен обновить данные.

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

После завершения этапа 2 я хочу вернуть данные и позволить пользователю встать на пути. Если моя система кеширования не завершена, она должна продолжать идти, но не болота пользователя.

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

Не уверен, что мне нужно создать поток или использовать async/await для достижения этого.

Редактировать

Вот что я пытаюсь сделать

public HttpResponseMessage Get() 
{ 
    // this will do a foursquare lookup to find all stores near the user 
    // I want to insert them into my database and link it to my unquie data. 
    // stores pulled from foursquare will 
    // a) Be new and not in my database 
    // b) exist in my database but have been refreshed lately 
    // c) have not been refreshed in timeframe of foursquare policy 
    // THIS SHOULD WORK IN THE BACKGROUND 
    storeService.PointsOfInterestNearUser(80, -130); //As you can see it is 
         //void. Not sure where to put the async/await stuff 

    // find this product. Should be happening at the same time as above line. 
    var product = productService.FindProduct("Noodles"); 

    //This will get returned to the user. 
    // the new stores taht are being added in StoreNearUser 
    //won't effect this search as I will have not data on this new store 
    // if existing store is being refreshed it is possible old 
    //address might be picked up... 
    //I can live with that as I doubt the address will change much. 

    // this should happen after product 
    var allStores = storeService.FindStoresThatHaveItem(product); 

    // this should be returned as soon as above line is finished. 
    //If StoreNearUser is not done, it should keep going but not hold up user. 
    return allStores; 
} 
public void StoresNearUser(double latitude, double longitude) 
{ 
    // get all categories I can about in foursquare. 
    //First time from db otherwise cached. 
    List<StoreCategory> storeCategories = GetStoreCategories(); 

    // do a request and get everything in near the user 
    //(provided it is also in a category I care about) 
    var request = CreateFoursquareStoreRequest 
         (latitude, longitude, storeCategories); 

    // do the actual call. 
    var response = client.Execute<VenueSearch>(request); 


    if (response.StatusCode == System.Net.HttpStatusCode.OK) 
    { 
// start going through the results, add or update or skip of entry will happen 
     AddUpdateStores(storeCategories, response); 
    } 
    else 
    { 
     ErrorSignal.FromCurrentContext().Raise(response.ErrorException); 
    } 
} 

Edit 2

public async Task StoresNearUser(double latitude, double longitude) 
{ 
// get all categories I can about in foursquare. First time from db otherwise cached. 
    List<StoreCategory> storeCategories = GetStoreCategories(); 

// do a request and get everything in near the user(provided it is also in a category I care about) 
    var request = CreateFoursquareStoreRequest(latitude, longitude, storeCategories); 

    await client.ExecuteAsync<VenueSearch> 
       ( request 
       , response => 
        { 
         if (response.StatusCode == System.Net.HttpStatusCode.OK) 
         { 
          AddUpdateStores(storeCategories, response); 
         } 
         else 
         { 
          ErrorSignal.FromCurrentContext() 
             .Raise(response.ErrorException); 
         } 
        } 
      ); 
} 

дает мне эту ошибку

Cannot await 'RestSharp.RestRequestAsyncHandle' 

Я также не получаю разницу между Task и void. Из того, что я прочитал, если вы просто используете Task, это означает, что вы ничего не отправляете обратно в смысл, то почему бы просто не использовать void?

Edit 2 Я нашел this post, чтобы показать мне, как сделать обертку для Restsharp. Это не 100%, что я хочу, но это отдельная проблема.

public async Task StoresNearUser(double latitude, double longitude) 
{ 
    List<StoreCategory> storeCategories = GetStoreCategories(); 

    var request = CreateFoursquareStoreRequest 
        (latitude, longitude, maxRadius, returnLimit, storeCategories); 

    var response = await client.GetResponseAsync(request); 

    if (response.StatusCode == HttpStatusCode.OK) 
    { 
// had to use json.net right now as the wrapper does not expose restsharps deserilizer 
     var venue = JsonConvert 
        .DeserializeObject<VenueSearch>(response.Content); 
     AddUpdateStores(storeCategories, venue); 
    } 
    else 
    { 
     ErrorSignal.FromCurrentContext() 
        .Raise(response.ErrorException); 
    } 
} 

public async Task<HttpResponseMessage>Get() 
{ 
    await storeService.PointsOfInterestNearUser(80, -130); 
    var product = productService.FindProduct("Noodles"); 
    var allStores = storeService.FindStoresThatHaveItem(product); 
    return allStores; 
} 

Когда я смотрю из отладчика, похоже, что все идет полным ходом. Я думаю, product и allStores должны быть, так как мне нужен продукт, прежде чем я смогу найти магазины, но PointsOfInterestNearUser должен идти в то же время, что и FindProduct.

Редактировать 3 Вот мой метод FindProduct. Не уверен, что делать асинхронно для меня, похоже, все должно подождать.

public ResponseResult<Product> FindProduct(string barcode) 
    { 
     ResponseResult<Product> responseResult = new ResponseResult<Product>(); 
     Product product = null; 

     try 
     { 

      var findBarCode = context.Barcodes.Where(x => x.Code == barcode).Select(x => x.Product).FirstOrDefault(); 

      responseResult.Response = product; 

      if (product == null) 
      { 
       responseResult.Status.Code = HttpStatusCode.NotFound; 
      } 
      else 
      { 
       responseResult.Status.Code = HttpStatusCode.OK; 
      } 
     } 
     catch (SqlException ex) 
     { 
      ErrorSignal.FromCurrentContext().Raise(ex); 
      responseResult.Status.Code = HttpStatusCode.InternalServerError; 
      responseResult.Status.Message = GenericErrors.InternalError; 
     } 

     return responseResult; 
    } 

Edit 4

Все еще не уверены, как сделать Task.WhenAll()

public async Task<HttpResponseMessage>Get() 
    { 
     Task[] tasks = new Task[2]; 
     tasks[0] = storeService.PointsOfInterestNearUser(80, -130); 
     tasks[1] = productService.FindProduct("Noodles"); 

     await Task.WhenAll(tasks); 

     // not sure how to get product back out. I looked in the debugger and saw a "Result" that has it but when I do tasks[1].Result inetllisene cannot find .Result 
     var allStores = storeService.FindStoresThatHaveItem(product); 
     return allStores; 
    } 
+0

Похоже, что нить будет работать лучше всего. Если вы не заботитесь о возвращенной информации из вызова для обновления db, зачем использовать async/wait? Можете ли вы просто стрелять и забыть? – Jras

+1

@KirkWoll: Совсем нет. 'async' и' await' не подразумевают многопоточность. –

+0

@ Stephen, это правда, я забыл, что все это может произойти в той же теме. К сожалению. –

ответ

4

Я бы рекомендовал использовать async/await для этого. Обновление кеша является одной из редких ситуаций, когда возвращение на раннем этапе из запроса ASP.NET является приемлемым. Вы можете увидеть мой blog post on the subject для получения полезного кода.

Так, что-то вроде этого (упрощено, чтобы просто посмотреть один «интересное место» на место):

public async Task<PlaceWithData> FindPlaceAsync(Location myLocation) 
{ 
    Place place = await GetPlaceFromFoursquareAsync(myLocation); 
    PlaceWithData ret = await GetExtraDataFromDatabaseAsync(place); 
    if (ret.NeedsRefresh) 
    BackgroundTaskManager.Run(() => UpdateDatabaseAsync(place, ret)); 
    return ret; 
} 

Вы можете также рассмотреть вопрос о расширении системы кэширования ASP.NET, а не делать «рулон ваш собственный "кеш.

+0

Я думаю, что мне нужно дать пример кода, возможно, это покажет, что я делаю больше, поскольку я думал, что асинк был хорошим способом, но проблема, с которой я сталкиваюсь, это в основном void метод, и ему это не понравилось. – chobo2

+0

Я рассмотрел ваш пример кода. Я рекомендую вам сначала сделать все «async» и только потом изменить его, чтобы вернуться раньше. При конвертировании в 'async' мне нравится работать изнутри, поэтому первое, что я бы посмотрел на преобразование, - это' client.Execute' (т. Е. Добавить 'client.ExecuteAsync') и работать стек вызовов. –

+0

Хорошо, я изменил запрос клиента на ExecuteAsync, но я не уверен, что вы имеете в виду «сделать все асинхронным». Я также использую EF 5, и когда я просто делаю изменение клиента, я получаю эту ошибку сейчас. «Операция не может быть завершена, потому что DbContext был удален». Обычно он удаляется ninject. – chobo2

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