Working with Azure Functions in Visual Studio Code like a boss

So after a while I decided to finally check Azure Functions extensions out in Visual Studio Code. I often want to check something really quickly and being forced to open Visual Studio each time makes me furious. I must say that initially I was a bit skeptical regarding Code functionality, but it turns out to be superb. Let's check what it offers for now.

Installing

Installing the extensions is super easy. Just go to the Extensions menu and search for Azure Functions:

Once extensions is installed you can easily disable or uninstall it

For now - that's really all!

Creating a function

With Azure Functions plugin installed you should be able to see available subscriptions in the Explorer area. If not left-click on the status bar where your username is displayed and select the ones you're interested in:

Workspace with only one subscription selected

 

Installing the extension gives you some more features. Now you're able to work with a project, create a function and publish it. Let's start with a function triggered by a HTTP request. Click on "Create New Project Button":

Now you're able to select a current location or create a new one where your project will be placed. Once you're satisfied you can select a language and... that's all, your workspace is ready to start working on a function.

Empty Functions project ready to rock!

Now let's create a function. You can create in in a similar way as a project. After providing all necessary data(like a name, a type of trigger, security level), a template will be created so you can start modyfing it as you wish.

A template, very similar to the one created in Visual Studio

Running a function

You can easily start testing your function by pressing F5. It'll start runtime and you'll be given an endpoint, which you can call anytime:

Publishing a function

Publishing a function from Visual Studio Code is as easy as other tasks. Once more go to the Azure Functions workspace and select "Deploy to Function App". You'll be asked about many different parameters like a subscription, resource group or storage account. Once everything's configured wait a second(or maybe two) until a function is published. You can start using it!

Function published along with a storage account and consumption plan

Summary

In the current shape VS Code will not replace full Visual Studio(at least for me personally), but I found Azure Functions extension extremely helpful in the smaller projects, which are developed fully in Code. If I don't have to switch between IDEs, I'm more than happy. 

Azure Function and custom extension for Data Lake - it really works!

It seems that this particular topic(extending Azure Functions with custom bindings) has gone very well(especially taking into account recent news regarding Function, which you can find here). In the final post about Data Lake extension I'll show you two things - how to register your app in AD so you can easily obtain clientId and clientSecret for authentication and how to actually run Data Lake bindings inside Azure Functions runtime!

Registering an application

This is a fairly easy step. You have to:

  • go to Azure Portal
  • find Azure Active Directory blade and then go to App Registrations
  • next click on New application registration - you'll see a form, which you can fill like this:

  • once an application is created go to Keys blade and create a new one - it's your secret
  • clientId in our extension is a value of ApplicationId field from the overview screen

Making it work with Functions runtime

We're prepared to make our extension work with WebJobs runtime, which is a bit different than the one used for Functions. What we do not control when working with Functions are extension, which are registered inside a host. If you try to reference current assembly and run your program, you'll probably see similar screen to this one:

This clearly shows, that there's a problem in discovering our custom binding. Fortunately it's something super easy to fix - as long as you know where the problem occurs. 

Consider following code:

/
public class DataLakeExtensionConfigProvider : IExtensionConfigProvider
{
	public void Initialize(ExtensionConfigContext context)
	{
		var rule = context.AddBindingRule<DataLakeAttribute>();
		rule.BindToInput(attribute => new DataLakeProvider(attribute.ClientId, attribute.ClientSecret));
	}
}

This is an extension config provider, which is needed to allow discovering a binding inside Functions runtime. You may ask what we're doing here? Well, it's pretty straightfoward - we're creating a new binding rule, which allows to bind [DataLake] attribute to DataLakeProvider class responsible for performing all actions. In fact this provider is similar in its purposes to DataLakeAttributeBindingProvider needed for WebJobs.

Additionally we have to show, that our attribute is actually a binding. This requires decorating it with [Binding] attribute:

/
[AttributeUsage(AttributeTargets.Parameter)]
[Binding]
public sealed class DataLakeAttribute : Attribute
{
	public DataLakeAttribute(string clientId, string clientSecret)
	{
		ClientId = clientId;
		ClientSecret = clientSecret;
	}

	public string ClientId { get; private set; }

	public string ClientSecret { get; private set; }
}

If you're missing this attribute, make sure you're using Microsoft.Azure.WebJobs assembly in version 2.1.0-beta1 at least.

Once we have this code we can go a step further - let's create a function, which will really test our extension!

Running a custom extension

To perform actions from this step you'll need VS2017 with Azure Functions SDK installed. If you're ready just add a new function with a timer trigger.

/
public static class DataLakeExample
{
	[FunctionName("DataLakeExample")]
	public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, TraceWriter log)
	{
		log.Info($"C# Timer trigger function executed at: {DateTime.Now}");
	}
}

You'll also need a reference to an assembly containing a custom binding. Now you can extend your function with the logic from the previous examples:

/
public static class DataLakeExample
{
	[FunctionName("DataLakeExample")]
	public static async Task Run([TimerTrigger("*/15 * * * * *")] TimerInfo myTimer,
		[DataLake("clientId", "clientSecret")]
		DataLakeProvider dataLake, TraceWriter log)
	{
		log.Info($"C# Timer trigger function executed at: {DateTime.Now}");

		using (dataLake)
		{
			var path = Path.Combine("This", "Is", "Just", "A", "Test2");
			await dataLake.CreateDirectory(path);
			await dataLake.AppendToFile(Path.Combine(path, "foo"), "THIS IS JUST A TEST");
		}
	}
}

Let's run our function:

What is even more important, data is available inside a Data Lake storage: