2015-11-19 2 views
1

Хорошо, мне нужно уточнить и проверить, рекомендуется ли и как реализовать асинхронную работу на сервере.WCF Restful Service - Внедрение асинхронных операций

Во-первых, вот некоторые подробности моей службы:

  • Размещенные в IIS 8.5 на сервере с Server 2012 R2.
  • Использует .NET 4.5 и может использовать 4.6 или больше. Здесь нет никаких ограничений.
  • WCF Restful обслуживание. Режим параллелизма = за звонок.
  • Клиент - это мобильное приложение, уже ожидающее вызова службы обслуживания моей службы.
  • Буквально каждый метод вызывает базу данных, другую веб-службу (а не веб-службу async) или создает PDF-файл. Я не шучу. Каждый. Один. Вызов.
  • Хотелось бы использовать асинхронные операции на основе задач.

Теперь, имея в виду вышеизложенное, я прочитал, что выполнение асинхронных операций обслуживания будет помогать с операциями ввода-вывода (например, работающая база данных, внешние вызовы веб-сервисов, генерация PDF и т. Д.). Однако я не могу найти хороший консенсус относительно того, как это сделать.

Stephen Clearly кажется довольно знающим парнем, однако один из его блогов сказал, что никогда не будет использовать Task.Run на веб-службе, которую я бы предположил, что мне придется использовать метод, который вызывает обращение к базе данных/веб-сервису на моем собственный сервис WCF, чтобы сделать его асинхронным. (источник: http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html). Он рекомендует использовать Task.FromResult? Мои результаты не могут/не должны кэшироваться?

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

Вот пример текущей (очевидно) синхронной версии кода. Что мне нужно сделать, чтобы сделать его асинхронным, как описано выше?

Я предполагаю, что я просто выполнил бы асинхронную эту сервисную операцию и дождался вызова MobileData.GetNoteAttachmentData. Что мне нужно сделать в GetNoteAttachmentData?

Пример Эксплуатация услуг:

public NoteAttachmentContract GetNoteAttachmentData(string annotationId) 
    { 
     DataSet NoteAttachmentData = null; 
     MobileData MobileData = new MobileData(); 
     NoteAttachmentContract Result = null; 
     TokenContract CurrentToken = MobileData.GetToken(); 

     try 
     { 
      NoteAttachmentData = MobileData.GetNoteAttachmentData(CurrentToken, annotationId); 

      if (NoteAttachmentData != null && NoteAttachmentData.HasData()) 
      { 
       DataRow NoteAttachmentRecord = NoteAttachmentData.Tables[0].Rows[0]; 

       string DocumentBody = NoteAttachmentRecord["documentbody"].ToString(); 
       string NoteId = NoteAttachmentRecord["annotationid"].ToString(); 
       string FileName = NoteAttachmentRecord["filename"].ToString(); 

       Result = new NoteAttachmentContract(DocumentBody, FileName, NoteId.IsGuid(false) ? new Guid(NoteId) : (Guid?)null); 
      } 
     } 
     catch (MobileServiceException ex) 
     { 
      throw ex; 
     } 
     catch (Exception ex) 
     { 
      throw new MobileServiceException(ex.Message, CurrentToken); 
     } 
     finally 
     { 
      if (NoteAttachmentData != null) 
      { 
       NoteAttachmentData.Dispose(); 
       NoteAttachmentData = null; 
      } 
     } 

     return Result; 
    } 



public DataSet GetNoteAttachmentData(TokenContract token, string annotationId) 
{ 
    DataSet Result = null; 
    SqlCommand Command = null; 

    try 
    { 
     using (SqlConnection connection = new SqlConnection(token.ConnectionString)) 
     { 
      SqlParameter AnnotationIdParameter = new SqlParameter(); 
      AnnotationIdParameter.SqlDbType = SqlDbType.UniqueIdentifier; 
      AnnotationIdParameter.ParameterName = "@AnnotationId"; 
      AnnotationIdParameter.Value = new Guid(annotationId); 

      connection.Open(); 
      Command = new SqlCommand(Properties.Resources.GetNoteAttachmentData, connection); 
      Command.Parameters.Add(AnnotationIdParameter); 

      using (SqlDataAdapter adapter = new SqlDataAdapter(Command)) 
      { 
       adapter.Fill(Result); 
       Command.Parameters.Clear(); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     if (Result != null) 
     { 
      Result.Dispose(); 
      Result = null; 
     } 

     throw ex; 
    } 
    finally 
    { 
     if (Command != null) 
     { 
      Command.Parameters.Clear(); 
      Command.Dispose(); 
     } 
    } 

    return Result; 
} 

ответ

1

Весь смысл использование операций асинхронных в службе, чтобы освободить нить, когда все, что вы делаете, это чего-то ждет. Если ваш служебный код выполняет только синхронную работу, то Task.Run() позволяет освободить текущий поток, но в итоге просто переносит фиксацию на нить, ничего не делая для другого потока. Затем вы просто добавляете накладные расходы с дополнительной работой, необходимой для управления асинхронной работой. Если какой-либо из методов, вызванных вашей операцией, не имеет асинхронного эквивалента, вам лучше оставить вещи такими, какие они есть. Например, существует ли метод MobileData.GetNoteAttachmentDataAsync, который возвращает задачу? Если есть, сделайте свой метод асинхронным и ожидайте ответа от этого метода.

+0

GetNoteAttachmentData запускается на том же самом точном сервере. Я поместил этот код в тот же тег кода.Поэтому я полностью контролирую весь код, к которому прикасается сервер, потому что он все работает от самой службы. Вызов базы данных? Выйти из бизнес-объекта службы, следовательно, объект «MobileData». Итак, как я могу сделать GetNoteAttachmentData (который запущен на той же службе, в том же потоке в настоящее время), будет async? Нужно ли мне? Причина в том, что вы только что сказали, что все, что она делает, это вытянуть другой поток, чтобы удерживать его, пока он работает в режиме ввода-вывода, что является контрпродуктивным. – Reshaos

+0

И если это правда, зачем вообще создавать асинхронные методы? Почему бы не синхронизировать все методы веб-службы, даже если они выполняют работу ввода-вывода? Являются ли задачи полезными только для приложений пользовательского интерфейса и используют только фоновые работы в веб-службах? – Reshaos

+0

На низком уровне win32 api есть асинхронные варианты всех операций ввода-вывода. Таким образом, все, что вызывает авию ввода-вывода, должно вызывать асинхронные версии. Большинство (если не все) фреймворков api, которые обертывают собственные вызовы ввода-вывода, выставляют асинхронные варианты. Например, класс [FileStream] (https://msdn.microsoft.com/en-us/library/system.io.filestream%28v=vs.110%29.aspx) имеет метод ReadAsync. Где-то есть какой-то код, который вызывает метод ввода-вывода, который должен быть переключен на использование версии Async, а затем вызывать асинхронность, чтобы вы могли ее ожидать. – MattC

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