Azure Durable Functions: Can I use a startup.cs? - azure

I have a couple of functions that I want to refactor into a Azure Durable Function, where the orchestrator calls different ActivityFunctions (the previously seperate Azure Functions). The seperate functions use a startup where I configure dependency injection and some other configurations.
Is it possible to use a startup class in a Durable Function scheme? I cannot find anything that seems to suggest this in the documentation.
If it is not possible, what other alternatives are there, for example, to define database connection string and dependency injection?
Thnx

Dependency Injection is possible in Durable Functions too.
Install and add reference to the following package from Nuget:
Microsoft.Azure.Functions.Extensions.DependencyInjection
Here's a working sample of Startup file with Dependency Injection done:
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs.Host.Bindings;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System;
[assembly: FunctionsStartup(typeof(MyDurableFunction.Startup))]
namespace MyDurableFunction
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var executioncontextoptions = builder.Services.BuildServiceProvider()
.GetService<IOptions<ExecutionContextOptions>>().Value;
var currentDirectory = executioncontextoptions.AppDirectory;
var environment = Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT");
var config = new ConfigurationBuilder()
.SetBasePath(currentDirectory)
.AddJsonFile($"settings.{environment}.json", optional: false, reloadOnChange: false)
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<IMyBusinessService1>(sp =>
{
var secretFromAppSettings = config["secretKey"];
var passwordFromAppSettings = config["secretPassword"];
return new MyBusinessService1(secretFromAppSettings, passwordFromAppSettings);
});
builder.Services.AddSingleton<IDatabaseHelper, DatabaseHelper>();
builder.Services.AddLogging();
}
}
}
Hope this helps!

Yes you can use Dependency Injection similar to normal functions.
A complete example which I found in this blog

Related

Azure DevOps Promote NuGet packages to Release view

As part of an Azure DevOps pipeline, I would like to promote packages in our own NuGet feed to 'Release' view as part of the release build.
I have an application that traverses all project.assets.json files and find names and versions of packages used by the projects in the solution.
This list is reduced by pattern matching on names to our own packages.
Previously I have succesfully used the BuildHttpClient from Microsoft.TeamFoundation.Build.WebApi to access information about builds and build artifacts.
What are the available tools for accessing Nuget Packages, feeds and views?
The REST API is described here: https://learn.microsoft.com/en-us/rest/api/azure/devops/artifactspackagetypes/nuget/update%20package%20versions?view=azure-devops-rest-6.0, but I would hate to implement the classes myself, if there is a library for the purpose.
Nuget - Update Package Versions has a flaw - there is no {project} relevans for packages.
By adding Microsoft.VisualStudio.Services.Packaging.Client Version 16.179.0-preview we get the classes, we need as long as we are building .Net Framework 4.6.2 or later (no netstandard yet).
based on this, I built the following helper class (no exception handling or threading to keep it simple):
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.VisualStudio.Services.NuGet.WebApi.Types;
using Microsoft.VisualStudio.Services.Packaging.Shared.WebApi;
using Newtonsoft.Json;
namespace PromotePackages
{
public class PromotePackageBatch
{
private readonly string _organization;
private readonly string _feedId;
private readonly string _token;
public PromotePackageBatch(string organization, string feedId, string token)
{
_organization = organization;
_feedId = feedId;
_token = token;
}
public void PromotePackagesToView(IDictionary<string, string> Libraries, string viewName)
{
var packs = new List<MinimalPackageDetails>();
foreach (var kvp in Libraries)
{
packs.Add(new MinimalPackageDetails
{
Id = kvp.Key,
Version = kvp.Value
});
}
using (HttpClient client = new HttpClient())
{
NuGetPackagesBatchRequest req = new NuGetPackagesBatchRequest
{
Data = new BatchPromoteData
{
ViewId = viewName
},
Operation = 0,
Packages = packs
};
var httpContent = new StringContent(JsonConvert.SerializeObject(req), Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", _token))));
var response = client.PostAsync(BuildUri(), httpContent).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
}
}
private Uri BuildUri()
{
return new Uri($"https://pkgs.dev.azure.com/{_organization}/_apis/packaging/feeds/{_feedId}/nuget/packagesbatch?api-version=6.0-preview.1");
}
}
}
By reference to this doc: Azure DevOps Services .NET SDK API Reference, searching for any managed APIs by typing in the box, but we don’t find such library which implements this Rest API: NuGet - Update Package Versions.
You could create a new issue in the MicrosoftDocs/feedback repository on GitHub for this feedback.
And now we suggest that you directly use this Rest API to implement this.

Azure Function 3.1 + NLog + Structured Logging, Issues with LoggerName

NLog + Azure Functions 3.1
Azure function Startup class
public override void Configure(IFunctionsHostBuilder builder)
{
var logger = LogManager.Setup()
.SetupExtensions(e => e.AutoLoadAssemblies(false))
.LoadConfigurationFromFile(currentDirectory + Path.DirectorySeparatorChar + 'NLog.config')
.GetLogger(configuration.GetSection('logging:nlog:defaultloggername')?.Value);
builder.Services.AddLogging((logger) =>
{
//logger.ClearProviders();
logger.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
logger.AddNLog();
}).BuildServiceProvider();
}
//NLog.config
<variable name='commonLayout' value='${longdate}|${logger}|${uppercase:${level}}|${message}, ${all-event-properties:format=[key]=[value]:separator=, } ${exception}' />
Azure Function
public FunctionA(ILogger<FunctionA> logger){}
Structured logging does not work with Azure function 3.1. The loggername is spitting out FunctionA, how can I change this to use NLog object in the Azure function.
Note: I'm using Azure Function 3.1, I can inject NLog in .net core 2.1 though.
I'm guessing from your question that you want to control the name of the Logger, so you can make better use of NLog-Filtering-Rules.
Instead of doing this:
public FunctionA(ILogger<FunctionA> logger){}
Have you tried to ask for ILoggerFactory like this:
public FunctionA(ILoggerFactory logFactory)
{
var logger = logFactory.CreateLogger("MyFavoriteLoggerName");
logger.LogError("Test");
}
You can also make use of BeginScope or LogEvent properties like EventId_Id to signal origin.

Azure connection attempt failed

I'm using the following code to connect. I can connect to other Azure Resources ok.
But for one resource I get the following error: URL and Key are correct.
{"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond"}
The Code is as follows
_searchClient = new SearchServiceClient(searchServiceName, new
SearchCredentials(apiKey));
_httpClient.DefaultRequestHeaders.Add("api-key", apiKey);
_searchServiceEndpoint = String.Format("https://{0}.{1}",
searchServiceName, _searchClient.SearchDnsSuffix);
bool result = RunAsync().GetAwaiter().GetResult();
Any ideas? thx in advance? How can I troubleshoot this?
I will show how this is done in c#
you will need a appsettings.json
you will need this code in the program.cs file
there are a lot of other files in the example from the document
that you may need to use , learn and edit for ur usecase
When working in c# and azure, always know what is unique about the file structured your solution first. This is why we build the examples from the docs as we learn the solution. Next we must study the different blocks of code that when executed deliver one feature or functionality to the solution as a whole.
appsettings.json
{
"SearchServiceName": "[Put your search service name here]",
"SearchIndexName": "hotels",
"SearchServiceAdminApiKey": "[Put your primary or secondary Admin API key here]",
"SearchServiceQueryApiKey": "[Put your primary or secondary Query API key here]"
}
Program.cs
namespace AzureSearch.SDKHowTo
{
using System;
using System.Linq;
using System.Threading;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Spatial;
// This sample shows how to delete, create, upload documents and query an index
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfigurationRoot configuration = builder.Build();
SearchServiceClient serviceClient = CreateSearchServiceClient(configuration);
string indexName = configuration["SearchIndexName"];
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, serviceClient);
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, serviceClient);
ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(indexClient);
ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(indexName, configuration);
RunQueries(indexClientForQueries);
Console.WriteLine("{0}", "Complete. Press any key to end application...\n");
Console.ReadKey();
}
private static SearchServiceClient CreateSearchServiceClient(IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string adminApiKey = configuration["SearchServiceAdminApiKey"];
SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(adminApiKey));
return serviceClient;
}
private static SearchIndexClient CreateSearchIndexClient(string indexName, IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string queryApiKey = configuration["SearchServiceQueryApiKey"];
SearchIndexClient indexClient = new SearchIndexClient(searchServiceName, indexName, new SearchCredentials(queryApiKey));
return indexClient;
}
private static void DeleteIndexIfExists(string indexName, SearchServiceClient serviceClient)
{
if (serviceClient.Indexes.Exists(indexName))
{
serviceClient.Indexes.Delete(indexName);
}
}
private static void CreateIndex(string indexName, SearchServiceClient serviceClient)
{
var definition = new Index()
{
Name = indexName,
Fields = FieldBuilder.BuildForType<Hotel>()
};
serviceClient.Indexes.Create(definition);
}}
Azure concepts to learn
How and why we create azure clients
Why do we use appsettings.json
What is some example file structures for azure search solutions
What coding lanague do you want to use to build that solutio
do u want to use the azure sdk
How to find and create api keys
C# concepts to learn
What is an interface and how do you use it
How to import one file in the file structure into another
How the main function works
How to call variables in to a function
How to call a function with a function
How to write server side code vs client side code
How to deploy c# code to azure
What version of c# are u using What’s is asp.net and what version will u use
What is asp.net core and what version will u use
As u can see azure and c# have a high learning curve.
Luckily you have stack overflow and documentation to research all of the above questions and more:)
For how u would troubleshoot...what I do is research each block of code in the documentation example and run all of the code locally. Then I test each block of code one at a time. Ur always testing data flowing thought the block of code. So you can just console log the result of a block a code by creating a test varable and print that varable to the console.
Because each block of Code represents one feature or functionality, each test will output either a pass or fail delivery of that feature or functionality. Thus you can design functionality, implement that design and create a test for new Feature.

Disable ColoredConsole Logging provider from Azure Functions V2

I am using Serilog for structured logging in asp.net core and would like to use the same library with Azure Functions.
My goal is to write the log messages in JSON format to Console Sink through Serilog. It is working, but the Functions Framework is also writing the text based logs using ColoredConsole provider. I want to disable that.
As you can see from the following code I tried to replace the LoggerFactory and clearing the providers. It still didn't work.
[assembly: WebJobsStartup(typeof(FuncStartup))]
namespace Function.Test
{
public class FuncStartup : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
var loggerConfiguration = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithExceptionDetails()
.Enrich.WithEnvironmentUserName()
.Enrich.WithMachineName()
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.With<ServiceVersionEnricher>()
.WriteTo.Console(new JsonFormatter());
Log.Logger = loggerConfiguration.CreateLogger();
//return serviceCollection.Replace(new ServiceDescriptor(typeof(ILoggerFactory), s => new SerilogLoggerFactory(null, true), ServiceLifetime.Singleton));
builder.Services.AddLogging(b =>
{
b.ClearProviders();
b.AddSerilog(Log.Logger);
});
}
}
}
Output:

Where did IDefaultKeyServices go in ASP.NET Core 2.0? What replaces it?

In ASP.NET Core 1.x the IoC container could be used to get a concrete implementation of Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IDefaultKeyServices but no such interface is registered with the IoC in ASP.NET Core 2.0. Where did IDefaultKeyServices go? Or what replaces it?
The interface looked like this:
public interface IDefaultKeyServices {
//
// Summary:
// Gets the default Microsoft.AspNetCore.DataProtection.XmlEncryption.IXmlEncryptor
// service (could return null).
IXmlEncryptor GetKeyEncryptor();
//
// Summary:
// Gets the default Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository
// service (must not be null).
IXmlRepository GetKeyRepository();
}
Microsoft documents the interface here.
I realize that this interface is in an "Internal" namespace and is subject to change (and change it did!). But how does one now get the default key repository and the default key encryptor in 2.x?
IDefaultKeyServices and its implementation DefaultKeyServices were removed with this commit.
Instances of IXmlRepository and IXmlEncryptor could be accessed via XmlRepository and XmlEncryptor properties of KeyManagementOptions.
Key storage providers article lists built-in implementations of IXmlRepository. You setup appropriate repository by calling PersistKeysTo...() extension method on IDataProtectionBuilder, e.g.:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\"));
or
services.AddDataProtection()
.PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Sample\keys"));
Key Encryption At Rest article lists built-in implementations of IXmlEncryptor. You setup appropriate encryptor by calling ProtectKeysWith...() extension method on IDataProtectionBuilder, e.g.:
services.AddDataProtection()
.ProtectKeysWithDpapi();
Here is a demo sample (Microsoft.AspNetCore.DataProtection NuGet required):
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\"))
.ProtectKeysWithDpapi();
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetService<IOptions<KeyManagementOptions>>();
var keyManagementOptions = options.Value;
var xmlRepository = keyManagementOptions.XmlRepository;
// Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository
var repositoryType = xmlRepository?.GetType();
var xmlEncryptor = keyManagementOptions.XmlEncryptor;
// Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlEncryptor
var encryptorType = xmlEncryptor?.GetType();
}
One more useful article in addition to already linked: Key management extensibility

Resources