Продолжение первой части.
Изменение логики шаблона
Теперь давайте изменим файл, созданный по шаблону. Ключевым изменением станет добавление логики для подсчета символов и слов.
Я хочу, чтобы функция читала только тело запроса, поэтому я уберу код для чтения параметра запроса.
11 //string name = req.Query["name"];
И далее мне нужно только прочитать данные из тела запроса. Пока я этим занимаюсь, я изменю имена переменных с name
на text
.
старая 16 //name = name ?? data?.name;
новая 16 var text = data?.text;
Теперь пришло время для логики, которая считывает текст и генерирует вывод с количеством символов и слов. Вместо создания еще одной Azure-функции для выполнения этой задачи я сначала добавлю подкласс с именем DocObject
для инкапсуляции результатов анализа.
public class DocObject
{
public string Text { get; set; }
public int WordCount { get; set; }
public int CharCount { get; set; }
public int NonSpaceCharCount { get; set; }
}
Затем я добавлю метод (AnalyzeText
) в уже существующую функцию.
private static DocObject AnalyzeText(string text)
{
var charsLen = text.Length;
if (charsLen==0) return " ";
var noSpacesLen = text.Replace(" ", "").Length;
char[] delimiters = new char[] { ' ', '\r', '\n' };
var wordCount = text.Split(delimiters,
StringSplitOptions.RemoveEmptyEntries).Length;
var docObject = new DocObject { Text = text,
WordCount = wordCount,
CharCount = charsLen,
NonSpaceCharCount = noSpacesLen };
return docObject ;
}
Оба эти фрагмента кода располагаются после метода Run
. Чтобы найти эффективный способ подсчета слов, учитывающий некоторые знаки препинания, я прибегла к сторонней помощи stackoverflow.com/questions/8784517/counting-number-of-words-in-c-sharp.
Наконец, мы создаем строку из результатов AnalyzeText
, которую отправим в качестве результата функции. Вот новый листинг для метода Run
нашей функции WordCount
. Я избавилась от параметра ILogger
в сигнатуре метода и вызова log.LogInformation
в исходной логике:
[FunctionName("WordCount")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous,"get", "post", Route = null)] HttpRequest req)
{
string requestBody = await new StreamReader (req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
string text = data?.text;
var httpResponseText = $@"CountText results: Total Chars:{docResults.CharCount}
Chars No spaces: {docResults.NonSpaceCharCount}
Word count: {docResults.WordCount}";
return text != null
? (ActionResult)
new OkObjectResult(AnalyzeText(text): new BadRequestObjectResult
("Please include text to analyze");
}
Если вы хотите проверить, что не допущено никаких опечаток, вы можете запустить dotnet build из окна терминала. Лично я полагаю, что это полезная привычка.
Отладка функции WordCount
Одна из замечательных возможностей расширения Azure Functions в VS Code, а также в Visual Studio заключается в том, что, поскольку вы работаете в IDE, вы можете воспользоваться всеми благами отладки, предоставляемыми вашим IDE. Если вы новичок с VS Code, вы можете даже не подозревать, что он предоставляет множество возможностей для отладки с точками останова, контрольными переменными, CodeLens и т. д. Итак если вы вдруг обнаружите, что ваша функция не делает то, что вы от нее ожидаете, вы можете установить точку останова (брейкопинт) и провести отладку, как и в любом другом коде.
Поскольку функция теперь работает с телом запроса, нам потребуется способ сформировать тело и включить его в HTTP-запрос к функции. Быть может вы уже достигли определенного мастерства в работе с такими инструментами, как Fiddler, Postman или инструментами разработчика вашего браузера. Я фанат другого расширения VS Code под названием REST Client Huachao Mao.
Я создала для этого новую подпапку в папке .vscode с именем RESTClientTesters
, чтобы оставить в чистоте проект нашей функции. Добавьте новый файл с именем WordCountTest.http
. HTTP-расширение не требуется для работы REST Client. Я просто использую его для идентификации моих файлов REST Client. Введем HTTP-запрос, указав метод, заголовки и тело. Вот простой запрос, который я буду использовать для начала. Само тело запроса — это последние три строки.
POST http://localhost:7071/api/WordCount HTTP/1.1
content-type: application/json
{
"text": "Hey, I built a serverless function!"
}
Прежде чем мы сможем протестировать запрос, нам нужно снова запустить функцию. Поместим несколько точек останова в код, чтобы просмотреть логику в действии, и нажмем F5 чтобы запустить ее в режиме отладки. Не забудьте дождаться сообщения “host lease locked”, чтобы убедиться, что функция готова принимать запросы. Затем при открытом окне редактора WordCountTest.http можно отправить запрос. Мы можем использовать комбинацию клавиш (Windows: CTRL-ALT-R; macOS: Opt-Cmd-R) или нажать F1 и выбрать Rest Client: Send Request. Расширение откроет новое окно для отображения результатов, возвращаемых функцией. Результат, показанный на рисунке 6: 35 символов, 30 символов без пробелов, а количество слов равно 6.
Развертывание нашей новой функции в облаке
Чтобы наша новая функция начала выполнять свою работу, нам нужно развернуть ее в Azure. Даже с 30-летним опытом работы с программным обеспечением термин “развертывание” по-прежнему заставляет мое сердце биться немного чаще. К счастью, и Visual Studio, и VS Code упрощают эту задачу. Помните иконку “upload” в обозревателе Azure Functions, которую вы могли увидеть рисунке 2? Если вы залогинились в свою учетную запись, то для развертывания этой функции нужно не так уж много. В моем случае мне нужно убедиться, что сначала создается приложение-функция, а затем WordCount внутри него. Кроме того, вспомните те локальные настройки, о которых мы говорили ранее. Для этой простенькой функции я не делала ничего, что бы касалось таких настроек, как определение привязок, предоставление строк подключения или учетных данных. У вас будет возможность загрузить свои локальные настройки в конце процесса развертывания.
Теперь нам нужно кликнуть на кнопку загрузки. Нам опять нужно будет пройти через ряд диалоговых окон, как и при создании функции. Сначала создадим новое приложение-функцию в Azure (вместо того, чтобы добавлять ее в существующее приложение-функцию). Вы можете заметить, что есть еще и расширенная версия этой опции, но в рамках этого руководства мы выберем простой вариант. Нам нужно будет указать новое имя для приложения-функции. Диалоговое окно запросит “глобально уникальное” имя. Это означает, что оно должно быть уникально не только в рамках нашей учетной записи, но и с учетом любой учетной записи во всем мире. Это связано с тем, что окончательный URI будет поддоменом azurewebsites.com. Я выбрала CodeMagFunctions
для этого примера. Простая версия "Create new Function App” не дает нам возможность выбрать группу ресурсов или расположение. Расширенный вариант позволяет указать для нового приложения-функции эти и еще несколько дополнительных параметров. Вы также можете изменить эти параметры в портале Azure постфактум.
После того, как расширение создаст новое приложение-функцию, оно заархивирует скомпилированную функцию и отправит ее в Azure. Вы получите несколько отчетов о состоянии, а затем уведомление, когда все будет готово. В конце вам будет предложено загрузить настройки. Сейчас нам не нужно это делать, поэтому мы просто закроем диалоговое окно.
Поскольку это развертывание в виде zip-файла, код функции на портале будет доступен только для чтения. Вы получите сообщение об этом с инструкциями по изменению параметров приложения, если вы захотите редактировать их непосредственно на портале. По сути, если вы создаете их в VS Code или VS, предполагается, что вы будете вносить изменения в своей IDE, а затем повторно развернете обновленную функцию.
Наша функция была опубликована в новом приложении-функции, и по завершению этого уведомление сообщит мне, что ее URI — https://codemagfunctions.azurewebsites.net/api/WordCount. Вы можете продолжать использовать REST Client или выбранный вами HTTP-инструмент, чтобы тестировать свою функцию в реальном времени. Обратите внимание, что я, вероятно, не оставлю свою функцию общедоступной надолго, чтобы не тратить ресурсы Azure, связанные с моей подпиской Visual Studio.
Для тестирования из VS Code я добавил новую POST-команду в файл WordCountTester.http, которая указывает на новый URL. Затем я выделила эту команду целиком (строки с 8 по 13), нажала F1 и запустила команду REST Client Send Request снова. Расширение выполнило только тот запрос, который я выделила в файле. На рисунке 7 показано новое POST-сообщение и ответ.
Дальнейшие шаги: Попробуем сделать пару привязок!
Я начала свое знакомство с Azure-функциям, создав и протестировав их непосредственно на портале, где вы можете легко добавлять триггеры, входные и выходные привязки прямо через пользовательский интерфейс. В одно и то же время, по мере улучшения моего понимания того, как работают эти функции, развивалось и расширение Azure Functions для VS Code. В конце концов я перешла на использование VS Code с расширением для сборки, отладки и развертывания Azure-функций. Я также создала ряд функций, которые считывают данные из Azure Cosmos DB с помощью входных привязок, сохраняют данные в Cosmos DB с помощью выходных привязок и даже отправляют текстовые сообщения с выходными привязками для Twilio API. Вы можете увидеть все это в действии в записи моего выступления на конференции в Оредеве в 2018 году (доступна на YouTube по ссылке).
Я не буду подробно описывать, как это сделать в этой и без того длинной статье, поэтому вот краткий обзор того, как выглядят привязки для функции-триггера Cosmos DB. Для этого потребуется учетная запись Azure и существующая учетная запись Cosmos DB. Смотрите эту документацию, чтобы создать учетную запись Cosmos DB. В C# привязки описываются подобно триггер в нашей функции WordCount, как атрибуты метода Run в коде. Это сильно отличается от того, как они настраиваются в функции на основе JavaScript или C#-скриптов, где конфигурации хранятся в JSON-файле.
Я изменила метод Run
функции WordCount
, чтобы он включал атрибут выходной привязки CosmosDb, которая будет хранить документы в контейнере Items
в моей базе данных со строкой подключения, которая теперь определена в local.settings.json:
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous,"get", "post", Route = null)]
HttpRequest req)
[CosmosDB (databaseName: "WordCounts",
collectionName: "Items",
ConnectionStringSetting ="CosmosDBConnection",
CreateIfNotExists=true)]
ICollector<doc> docs)
{
Есть три способа гарантировать, что данные, предназначенные для выходной привязки будут обнаруживаться привязкой. Один из них заключается в создании параметра Out в сигнатуре. Поскольку я использую асинхронный метод, в C# это невозможно. Другой способ гарантировать, что выходную привязку можно будет обнаружить, — возвращать значение. Но я уже использую return для отправки HttpResponse. Третий способ — использовать ICollector. Это также необходимо, если вы хотите отправить обратно сразу несколько документов. Поскольку это решает проблему, я буду использовать шаблон ICollector
для возврата одного документа.
После того, как мой код получит заполненный DocObject в docResults, я добавлю его к документам объекта ICollector
:
documents.Add(docResults);
Это все, что мне нужно сделать. Выходная привязка позаботится обо всем остальном, что является одним из поистине удивительных преимуществ привязок. Теперь, когда я запускаю свою функцию, я не только получаю HttpResponse, но еще и документ, показанный на рисунке 8, добавляется в мою базу данных Cosmos DB (которая, кстати, создается на лету благодаря настройке CreateIfNotExists).
Заключение
Еще столько всего можно обсудить об Azure-функциях и о том, как их можно использовать в составе производственных решений, а не только в небольших демонстрационных приложениях. Мне нравится работать с инструментами, которые не только продуктивны, но и доставляют удовольствие; комбинация Azure-функций, кода Visual Studio и расширения Azure Functions определенно попадает в эту категорию!
Всех желающих приглашаем на открытое занятие «Что полезного в новых версиях C#?». На нем разберем ключевые нововведения релиза .NET 6.0 с C# 10, а также познакомимся с полезными и часто используемыми новшествами последних версий языка C#. Регистрация открыта по ссылке.