Skip to content

Commit 500c2f0

Browse files
Merge pull request #248067 from mattchenderson/upgradeassist
adding migration from csx options
2 parents 72ba2a2 + cb5aa48 commit 500c2f0

5 files changed

+148
-1
lines changed

articles/azure-functions/functions-reference-csharp.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,144 @@ The following table lists the .NET attributes for each binding type and the pack
581581
> | Storage table | [`Microsoft.Azure.WebJobs.TableAttribute`](https://github.com/Azure/azure-webjobs-sdk/blob/master/src/Microsoft.Azure.WebJobs), [`Microsoft.Azure.WebJobs.StorageAccountAttribute`](https://github.com/Azure/azure-webjobs-sdk/blob/master/src/Microsoft.Azure.WebJobs/StorageAccountAttribute.cs) | |
582582
> | Twilio | [`Microsoft.Azure.WebJobs.TwilioSmsAttribute`](https://github.com/Azure/azure-webjobs-sdk-extensions/blob/master/src/WebJobs.Extensions.Twilio/TwilioSMSAttribute.cs) | `#r "Microsoft.Azure.WebJobs.Extensions.Twilio"` |
583583
584+
## Convert a C# script app to a C# project
585+
586+
The easiest way to convert an application using C# script to a C# project is to start with a new project and migrate the code and configuration from your .csx and function.json files.
587+
588+
If you are using C# scripting for portal editing, you may wish to start by [downloading the app content to your local machine](./deployment-zip-push.md#download-your-function-app-files). Choose the "Site content" option instead of "Content and Visual Studio project". The project that the portal provides isn't needed because in the later steps of this section, you will be creating a new Visual Studio project. Similarly, do not include app settings in the download. You are defining a new development environment, and this environment should not have the same permissions as your hosted app environment.
589+
590+
Once you have your C# script code ready, you can begin creating the new project:
591+
592+
1. Follow the instructions to create a new function project [using Visual Studio](./functions-create-your-first-function-visual-studio.md), using [Visual Studio Code](./create-first-function-vs-code-csharp.md), or [using the command line](./create-first-function-cli-csharp.md). You don't need to publish the project yet.
593+
1. If your C# script code included an `extensions.csproj` file or any `function.proj` files, copy the package references from these files, and add them to the new project's `.csproj` file alongside it's core dependencies.
594+
595+
The conversion activity a good opportunity to update to the latest versions of your dependencies. Doing so may require additional code changes in a later step.
596+
597+
1. Copy the contents of the C# scripting `host.json` file into the project `host.json` file. If you are combining this with any other migration activities, note that the [`host.json`](./functions-host-json.md) schema depends on the version you are targeting. The contents of the `extensions` section are also informed by the versions of triggers and bindings that you are using. Refer to the reference for each extension to identify the right properties to configure.
598+
1. For any [shared files referenced by a `#load` directive](#reusing-csx-code), create new `.cs` files for their contents. You can structure this in any way you prefer. For most apps, it is simplest to create a new `.cs` file for each class that you defined. For any static methods created without a class, you'll need to define a new class or classes that they can be defined in.
599+
1. Migrate each function to a `.cs` file. This file will combine the `run.csx` and the `function.json` for that function. For example, if you had a function named `HelloWorld`, in C# script this would be represented with `HelloWorld/run.csx` and `HelloWorld/function.json`. For the new project, you would create a `HelloWorld.cs`. Perform the following steps for each function:
600+
601+
1. Create a new file named `<FUNCTION_NAME>.cs`, replacing `<FUNCTION_NAME>` with the name of the folder that defined your C# script function. It is often easiest to start by creating a new function in the project model, which will cover some of the later steps. From the CLI, you can use the command `func new --name <FUNCTION_NAME>` making a similar substitution, and selecting the target template when prompted.
602+
1. Copy the `using` statements from your `run.csx` file and add them to the new file. You do not need any `#r` directives.
603+
1. For any `#load` statement in your `run.csx` file, add a new `using` statement for the namespace you used for the shared code.
604+
1. In the new file, define a class for your function under the namespace you are using for the project.
605+
1. Create a new method named `RunHandler` or something similar. This new method will serve as the new entry point for the function.
606+
1. Copy the static method that represents your function, along with any functions it calls, from `run.csx` into your new class as a second method. From the new method you created in the previous step, call into this static method. This indirection step is helpful for navigating any differences as you continue the upgrade. You can keep the original method exactly the same and simply control its inputs from the new context. You may need to create parameters on the new method which you then pass into the static method call. After you have confirmed that the migration has worked as intended, you can remove this extra level of indirection.
607+
1. For each binding in the `function.json` file, add the corresponding attribute to your new method. This may require you to add additional package dependencies. Consult the reference for each binding for specific requirements in the new model.
608+
609+
1. Verify that your project runs locally.
610+
1. Republish the app to Azure.
611+
612+
### Example function conversion
613+
614+
This section shows an example of the migration for a single function.
615+
616+
The original function in C# scripting has two files:
617+
- `HelloWorld/function.json`
618+
- `HelloWorld/run.csx`
619+
620+
The contents of `HelloWorld/function.json` are:
621+
622+
```json
623+
{
624+
"bindings": [
625+
{
626+
"authLevel": "FUNCTION",
627+
"name": "req",
628+
"type": "httpTrigger",
629+
"direction": "in",
630+
"methods": [
631+
"get",
632+
"post"
633+
]
634+
},
635+
{
636+
"name": "$return",
637+
"type": "http",
638+
"direction": "out"
639+
}
640+
]
641+
}
642+
```
643+
644+
The contents of `HelloWorld/run.csx` are:
645+
646+
```csharp
647+
#r "Newtonsoft.Json"
648+
649+
using System.Net;
650+
using Microsoft.AspNetCore.Mvc;
651+
using Microsoft.Extensions.Primitives;
652+
using Newtonsoft.Json;
653+
654+
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
655+
{
656+
log.LogInformation("C# HTTP trigger function processed a request.");
657+
658+
string name = req.Query["name"];
659+
660+
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
661+
dynamic data = JsonConvert.DeserializeObject(requestBody);
662+
name = name ?? data?.name;
663+
664+
string responseMessage = string.IsNullOrEmpty(name)
665+
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
666+
: $"Hello, {name}. This HTTP triggered function executed successfully.";
667+
668+
return new OkObjectResult(responseMessage);
669+
}
670+
```
671+
672+
After migrating to the isolated worker model with ASP.NET Core integration, these are replaced by a single `HelloWorld.cs`:
673+
674+
```csharp
675+
using System.Net;
676+
using Microsoft.Azure.Functions.Worker;
677+
using Microsoft.AspNetCore.Http;
678+
using Microsoft.AspNetCore.Mvc;
679+
using Microsoft.Extensions.Logging;
680+
using Microsoft.AspNetCore.Routing;
681+
using Microsoft.Extensions.Primitives;
682+
using Newtonsoft.Json;
683+
684+
namespace MyFunctionApp
685+
{
686+
public class HelloWorld
687+
{
688+
private readonly ILogger _logger;
689+
690+
public HelloWorld(ILoggerFactory loggerFactory)
691+
{
692+
_logger = loggerFactory.CreateLogger<HelloWorld>();
693+
}
694+
695+
[Function("HelloWorld")]
696+
public async Task<IActionResult> RunHandler([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req)
697+
{
698+
return await Run(req, _logger);
699+
}
700+
701+
// From run.csx
702+
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
703+
{
704+
log.LogInformation("C# HTTP trigger function processed a request.");
705+
706+
string name = req.Query["name"];
707+
708+
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
709+
dynamic data = JsonConvert.DeserializeObject(requestBody);
710+
name = name ?? data?.name;
711+
712+
string responseMessage = string.IsNullOrEmpty(name)
713+
? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
714+
: $"Hello, {name}. This HTTP triggered function executed successfully.";
715+
716+
return new OkObjectResult(responseMessage);
717+
}
718+
}
719+
}
720+
```
721+
584722
## Binding configuration and examples
585723

586724
### Blob trigger

articles/azure-functions/migrate-dotnet-to-isolated-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ To upgrade the application, you will:
6565

6666
## Upgrade your local project
6767

68-
The section outlines the various changes that you need to make to your local project to move it to the isolated worker model. Some of the steps change based on your target version of .NET. Use the tabs to select the instructions which match your desired version.
68+
The section outlines the various changes that you need to make to your local project to move it to the isolated worker model. Some of the steps change based on your target version of .NET. Use the tabs to select the instructions which match your desired version. These steps assume a local C# project, and if your app is instead using C# script (`.csx` files), you should [convert to the project model](./functions-reference-csharp.md#convert-a-c-script-app-to-a-c-project) before continuing.
6969

7070
> [!TIP]
7171
> The [.NET Upgrade Assistant] can be used to automatically make many of the changes mentioned in the following sections.

includes/functions-dotnet-migrate-project-v4-isolated-2.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ms.topic: include
55
ms.date: 10/29/2022
66
ms.author: glenga
77
---
8+
9+
These steps assume a local C# project, and if your app is instead using C# script (`.csx` files), you should [convert to the project model](../articles/azure-functions/functions-reference-csharp.md#convert-a-c-script-app-to-a-c-project) before continuing.
10+
811
The following changes are required in the .csproj XML project file:
912

1013
1. Set the value of `PropertyGroup`.`TargetFramework` to `net7.0`.

includes/functions-dotnet-migrate-project-v4-isolated-net-framework.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ms.topic: include
55
ms.date: 07/31/2023
66
ms.author: mahender
77
---
8+
9+
These steps assume a local C# project, and if your app is instead using C# script (`.csx` files), you should [convert to the project model](../articles/azure-functions/functions-reference-csharp.md#convert-a-c-script-app-to-a-c-project) before continuing.
10+
811
The following changes are required in the .csproj XML project file:
912

1013
1. Set the value of `PropertyGroup`.`TargetFramework` to `net48`.

includes/functions-dotnet-migrate-project-v4-isolated.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ms.topic: include
55
ms.date: 10/29/2022
66
ms.author: glenga
77
---
8+
9+
These steps assume a local C# project, and if your app is instead using C# script (`.csx` files), you should [convert to the project model](../articles/azure-functions/functions-reference-csharp.md#convert-a-c-script-app-to-a-c-project) before continuing.
10+
811
The following changes are required in the .csproj XML project file:
912

1013
1. Set the value of `PropertyGroup`.`TargetFramework` to `net6.0`.

0 commit comments

Comments
 (0)