Хорошо, мне нужно уточнить и проверить, рекомендуется ли и как реализовать асинхронную работу на сервере.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;
}
GetNoteAttachmentData запускается на том же самом точном сервере. Я поместил этот код в тот же тег кода.Поэтому я полностью контролирую весь код, к которому прикасается сервер, потому что он все работает от самой службы. Вызов базы данных? Выйти из бизнес-объекта службы, следовательно, объект «MobileData». Итак, как я могу сделать GetNoteAttachmentData (который запущен на той же службе, в том же потоке в настоящее время), будет async? Нужно ли мне? Причина в том, что вы только что сказали, что все, что она делает, это вытянуть другой поток, чтобы удерживать его, пока он работает в режиме ввода-вывода, что является контрпродуктивным. – Reshaos
И если это правда, зачем вообще создавать асинхронные методы? Почему бы не синхронизировать все методы веб-службы, даже если они выполняют работу ввода-вывода? Являются ли задачи полезными только для приложений пользовательского интерфейса и используют только фоновые работы в веб-службах? – Reshaos
На низком уровне win32 api есть асинхронные варианты всех операций ввода-вывода. Таким образом, все, что вызывает авию ввода-вывода, должно вызывать асинхронные версии. Большинство (если не все) фреймворков api, которые обертывают собственные вызовы ввода-вывода, выставляют асинхронные варианты. Например, класс [FileStream] (https://msdn.microsoft.com/en-us/library/system.io.filestream%28v=vs.110%29.aspx) имеет метод ReadAsync. Где-то есть какой-то код, который вызывает метод ввода-вывода, который должен быть переключен на использование версии Async, а затем вызывать асинхронность, чтобы вы могли ее ожидать. – MattC