Cannot connect to CosmosDB from VS Code Azure Function - azure

I created Azure Function (2.0v) from C# HTTP template . Then I added output binding to CosmosDB based on CosmosDB docs:
public static class AddEvent
{
[FunctionName("AddEvent")]
public static void Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
HttpRequest req,
[CosmosDB("SomeDatabase", "SomeCollection", Id = "id",
ConnectionStringSetting = "myCosmosDB", CreateIfNotExists = true)]
out dynamic document)
{
document = new { Text = "something", id = Guid.NewGuid() };
}
}
Packages, that I use (csproj file):
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.0-beta7" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.11" />
This is my local.settings.json. I based them on values from CosmosDB emulator:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureWebJobsDashboard": "",
"myCosmosDB": "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
}
}
Unfortunately, when I hit HTTP trigger I get:
System.Private.CoreLib: Exception while executing function: AddEvent.
Microsoft.Azure.WebJobs.Host: Exception binding parameter 'document'.
Microsoft.Azure.DocumentDB.Core: The type initializer for 'Microsoft.Azure.Documents.UserAgentContainer' threw an exception.
Object reference not set to an instance of an object.
What does this exception means? I cannot find any relevant information about it and it completely stops my local work. Function works well without CosmosDB attribute.

This was a regression with the latest version (2.0.11776) of the host. This has been addressed and the release is currently in progress.

It should be a breaking change in new cli. Try to downgrade cli to 2.0.1-beta.25, it works on my side. BTW, I recommend you to update Microsoft.NET.Sdk.Functions to 1.0.13 to avoid possible exception.
beta.24 seems outdated and also causes Method not found error on my side. While beta.26 leads to error same as beta.28.
However, if I debug the project directly using VS(which uses beta.26 no-runtime version) or publish it to Azure, works fine. Have opened an issue on github, you can track it if interested.
Update
Solved in 2.0.1-beta.29, runtime 2.0.11857.0.

What version of the DocumentDB package are you referencing?
Recommendation would be to either:
downgrade any DocumentDB nuget to 1.13.2.
Remove the DocumentDB reference completely and instead directly reference Microsoft.Azure.WebJobs.Extensions.DocumentDB, which will reference the correct version for you.

Related

Getting connection string for DBContext when deploying to Azure

EDIT: This question has been significantly restructured, now I've figured out a bit more of the problem and this should clarify things.
I am following this tutorial: https://learn.microsoft.com/en-us/azure/app-service/tutorial-dotnetcore-sqldb-app
I've deployed my own multiproject app, which works, but I can't get the connection string working properly. For some reason, it only works if I hardcode the connection string into the OnConfiguring method of my DBContext class. Otherwise, it throws an error.
Like so:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(
"Nasty hard coded azure connection string",
providerOptions => { providerOptions.EnableRetryOnFailure(); });
}
However, obviously, i want to get the connection string from a configuration file or environment variable.
Prior to deploying, I had the following. An extension method for IServiceColleciton which sets up the connection string:
public static void ConfigureSqlContext(this IServiceCollection services,
IConfiguration configuration) =>
services.AddDbContext<PeakedDbContext>(opts =>
opts.UseSqlServer(configuration.GetConnectionString("defaultConnection")));
then this method is called in program.cs. A pretty normal setup.
And I also set up an IDesignTimeDBContextFactory like so:
public class RepositoryContextFactory : IDesignTimeDbContextFactory<PeakedDbContext>
{
public PeakedDbContext CreateDbContext(string[] args)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<PeakedDbContext>()
.UseSqlServer(configuration.GetConnectionString("defaultConnection"));
return new PeakedDbContext(builder.Options);
}
}
Both my appsettings.json AND the Azure App Service configuration have the same name "defaultConnection".
As far as I can tell this is the approach recommended here: https://learn.microsoft.com/en-us/ef/core/cli/dbcontext-creation?tabs=dotnet-core-cli
I have also tried adding an empty constructor for my DBContext. (Not sure how this affects things as I have other DIs on my DBContext constructor. My DBContext consructors are getting a bit out of hand:
public PeakedDbContext()
{
}
public PeakedDbContext(DbContextOptions options) : base(options)
{
}
public PeakedDbContext(DbContextOptions options, ICurrentUserService currentUserService) : base(options)
{
_currentUserService = currentUserService;
}
According the the second link, above, I shouldn't need OnConfiguring method in my DBContext... and even if I do, what is the correct way to pass access to configuration.GetConnectionString, instead of hardcoding the connection string? Should I just add yet another DBContext constructor with the config injected? However, it ONLY works if I have the onconfiguring method. Neither the contextfactory nor the extension method setup are being used by azure app service.
Shouldn't it use the designtime factory or the hostconfiguration extension method I've set up above? What is the right way to use _configuration.GetConnectionString("defaultConnection") so that it works both locally and on Azure Deployment?
Update:
Still no luck. I tried adding the database connection string as an environment variable on azure like so:
and then updating all my reference to getconnection string - in program.cs, IDesignFactory and OnConfiguring - like so:
Environment.GetEnvironmentVariable("PeakedDbConn")
This continues to work locally. But When deploying to Azure it claims the connection string in null... so it's not seeing this variable. Nor can I find any code that will access the defaultConnection from the image. Which is strange, because it accesses the SECRET variable just fine.
I have followed the same code which you have provided with few changes.
Check the below steps to get the Connection string from appsettings.json and override the value if Azure App Connection String has been set.
As you are using .NET Core 6, I have set all the Configurations in Program.cs itself.
My Program.cs
builder.Services.AddDbContext<MyDatabaseContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MyDbConnection")));
builder.Configuration.AddEnvironmentVariables();
Same Connection String name must exist in both Local and Azure App Connection Strings.
My appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MyDbConnection": "Dummy Connection String"
}
}
Azure App Connection String:
To check if we are getting the Connection String Value, I have written code in Controller.
private readonly IConfiguration Configuration;
public HomeController(ILogger<HomeController> logger,IConfiguration config)
{
_logger = logger;
Configuration = config;
}
public IActionResult Index()
{
var myconnStr = Configuration.GetConnectionString("MyDbConnection");
ViewBag.myconnStr = myconnStr;
return View();
}
My .csproj file :
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
</ItemGroup>
</Project>
Local Output:
Deployed App Output:
Ok so it turned out to be GitHub actions that was the problem. The tutorial I followed in the first link doesn't mention this, perhaps because it's a single project api... not exactly sure.
The tutorial uses github actions to build and deploy the app, but for me, during the build it fails saying there is no connection string. This is because GitHub build process doesn't have access to either your local or the azure environment variable.
So I had to go into setting on my github repo and on the left click on secrets and variables < actions.
Click create a new Repository Secret, give it the same name as your environment variable i.e. PEAKEDDBCONN for me. Then, give it a value. I just used my local host string, but I guess you could type 'monkeynuts' in here if you wanted, it just needs to not be null.
Then you need to add a line to your workflow yaml file, the same one the tutorial talks about, to tell it about the environment variable. I added it like so:
jobs:
build:
runs-on: ubuntu-latest
env:
PEAKEDDBCONN: ${{ secrets.PEAKEDDBCONN }}
Then it all builds nicely and works.
For anybody who it helps, I decided to blog this whole setup:
https://garyfrewin.hashnode.dev/setting-up-an-entity-framework-core-web-api-on-azure-with-sqlserver-a-step-by-step-guide-for-hobby-projects

Azure Function for Cosmos DB change feed feed won't run: No job functions found

I'm writing an Azure Function app that'll subscribe to a Cosmos DB change feed. When I use Visual Studio 2019 to run the app locally (F5), I get the following error on the CLI:
Azure Function Core Tools reports "No job functions found."
The entire code snippet is below:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
namespace ZZZ.ChangeFeedSubscriber
{
public static class ChangeFeedSubscriber
{
[FunctionName("ChangeFeedSubscriber")]
public static void Run([CosmosDBTrigger(
databaseName: "XXX",
collectionName: "YYY",
ConnectionStringSetting = "XXX",
LeaseCollectionName = "leases")] IReadOnlyList<Doc> docs, FunctionContext context)
{
var logger = context.GetLogger("ChangeFeedSubscriber");
if (docs != null && docs.Count > 0)
{
logger.LogInformation("Documents modified: " + docs.Count);
foreach (var doc in docs)
{
logger.LogInformation("ID: " + doc.id);
}
}
}
}
}
I tried to set "--verbose" on the application arguments to see log output but it threw an error.
Adding "--verbose" throws an error.
Result of adding "--verbose" to application arguments.
I also tried setting "start --verbose" but it threw an error, too.
Adding "start --verbose" also throws an error.
Result of adding "start --verbose" to application arguments.
I don't know what else I can check at this point. The application won't start up and I cannot see log output based on the searching I've done.
Any help would be appreciated. TIA!
Looks like you have mixed the in-proc and out-of-process model here, which caused the issue.
From the code, I am assuming you have an out of process (isolated worker) function app. But your second line is a using statement to import the Microsoft.Azure.WebJobs namespace. I also see you are using the FunctionName attribute which is coming from the Microsoft.Azure.WebJobs package.
For out of process function apps, you should not use the webjobs package. Instead, you should use the equivalent pacakge from Microsoft.Azure.Functions.Worker.Extensions
To fix, open your .csproj file and remove the Microsoft.Azure.WebJobs.Extensions.CosmosDB package. Add a new entry for Microsoft.Azure.Functions.Worker.Extensions.CosmosDB (the out of process worker version). You may do the same using nuget package manager UI as well.
After the change, your csproj file will look something like this
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.CosmosDB" Version="3.0.9" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.0.3" OutputItemType="Analyzer" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.1.0" />
</ItemGroup>
Also make sure that now you are using the Function attribute instead of FunctionName and removed the using statement to import Microsoft.Azure.WebJobs namespace.
[Function("Function1")]
public static void Run([CosmosDBTrigger(
With this change, your functions will be discovered.

Azure Functions v3 Could not load file or assembly 'Microsoft.Extensions.Primitives, Version=5.0.0.0

I'm having the above error after running an azure function called "Test" that redirects to an external URL of a service we want to use.
[FunctionName("Test")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req)
{
Log.Information("C# HTTP trigger function processed a request.");
string url = _authenticationService.GetAuthorizationUri().ToString();
return new RedirectResult(url);
}
The site at the URL prompts the user to authorize use of their data and performs a redirect to the previously authorized url of our "AuthorizationCallback", along with a query string parameter.
[FunctionName("AuthorizationCallback")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
{
Log.Information("C# HTTP trigger function processed a request.");
string code = req.Query["code"];
try
{
if (!string.IsNullOrEmpty(code))
{
await _authenticationService.ExchangeCodeForAccessToken(code);
return new OkResult();
}
}
catch (System.Exception)
{
return new UnauthorizedResult();
}
return new NotFoundResult();
}
The AuthorizationCallback function is hit but produces the following error in the console:
These are the dependencies of the current project on the solution (which is set as the startup project):
I've tried installing both the latest stable version (5.0.0) and the version before that (3.1.13) of Microsoft.Extensions.Primitives in the current project, but I'm still getting the same error. I've noticed the package that can't be loaded is within microsoft.azure.webjobs (3.0.23), which is within microsoft.azure.webjobs.extensions.storage (4.0.4), but these are used in another project entirely, for another azure function (blob triggered). Any ideas on how to overcome this error? Thank you all.
The Azure Functions host for .NET Core 3 uses an in-process hosting model, which essentially means you are limited in what versions of Microsoft assemblies you can use. What's happening is that something in your project has a reference to a newer version of Microsoft.Extensions.Primitives, but an older version of that library is already loaded by the Azure Functions host application.
For Azure Functions .NET Core 3, you should restrict all Microsoft.Extensions.* libraries to v3.x. You currently have Microsoft.Extensions.DependencyInjection 5.0.1, which should be changed to 3.x. Check for any other Microsoft.Extensions.* libraries either at the Packages level or anywhere beneath (tip: you can find them quickly by putting Microsoft.Extensions in the input box at the top of the Solution Explorer). You may need to downgrade some other library that has Microsoft.Extensions.Primitives as a dependency.
You might also be able to get away with manually writing a bindingRedirect pointing the newer version to an older version. The Microsoft.Extensions.* packages are relatively stable across versions, so that may work. It would make me very nervous, though.

Azure function throwing exceptions when called even with default template

I'm baffled by how to just make a simple Azure function. In Visual Studio 2017 (I'm on version 15.5.6) I create a simple project following the instructions here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-develop-vs
My steps:
Make new Azure Functions project and leave the framework at the default of .Net Framework 4.6.1
On the next screen I choose HttpTrigger and the drop down says "Azure Functions v1 (.NET Framework)"
I set the storage to be my azure storage that I already created in the portal and set the authorization to "admin"
Everything compiles fine. I call the function via PostMan and get this error:
"A ScriptHost error has occurred
Exception while executing function: Functions.Function1. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'log'. Microsoft.Azure.WebJobs.Host: No value was provided for parameter 'log'."
For reference, here is the template function they created that I haven't modified at all:
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
namespace TestFunc
{
public static class Function1
{
[FunctionName("Function1")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Admin, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
// Set name to query string or body data
name = name ?? data?.name;
return name == null
? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body")
: req.CreateResponse(HttpStatusCode.OK, "Hello " + name);
}
}
}
If I remove the "TraceWriter log" and the call to "log.Info(...." and then try again, I instead get this error:
"A ScriptHost error has occurred
Exception while executing function: Functions.Function1. mscorlib: Exception has been thrown by the target of an invocation. TestFunc: Method not found: 'System.Net.Http.HttpResponseMessage System.Net.Http.HttpRequestMessageExtensions.CreateResponse(System.Net.Http.HttpRequestMessage, System.Net.HttpStatusCode, !!0)'."
I've tried changing the .Net version to 4.7 but nothing changed. I tried changing the function version to v2 instead of v1 (even though it's in beta at the moment) but nothing happened either. The only NuGet package that's added by the template is Microsoft.NET.Sdk.Functions version 1.0.6. There's an update to 1.0.7 available but that doesn't help either.
I have no idea what to try. This is the default template. I have another function project that works fine but that was done a while ago when VS2015 was the latest, and was during the time when you had to have those function.json files to make your precompiled DLL. I was hoping to be able to use the current system as it seems to be the best way going forward but if I can't get this to work I may just go back to the old way of doing things. Thanks.

Implementing Application Insight to Azure Function App

Anyone know of any god guide for this?
First i created an Application Insight Resource and put:
APPINSIGHTS_INSTRUMENTATIONKEY = "INSTRUMENTATION KEY"
in the Function Apps Application Settings.
I have tried implementering the nuget package for the funtion app like this.
Createing a project.json file and pasting this:
{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.ApplicationInsights": "2.1.0"
}
}
}
}
It installed the nuget package (i could see it in the log, everything went well).
After that i put these snippets in my code to use the telemetry.TrackException(exception) functionality:
First...
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
Then:
var telemetry = new TelemetryClient(new TelemetryConfiguration("INSTRUMENTATION KEY"));
and in my catch:
telemetry.TrackException(e);
and when i try to save my Function app i get this error:
error CS1729: 'TelemetryConfiguration' does not contain a constructor that takes 1 arguments
You don't need to use reference the Application Insights library to use it with Functions. If you've already set the APPINSIGHTS_INSTRUMENTATIONKEY application setting, you can simply add the ILogger interface as a parameter to your function and it will automatically send the log data to your Application Insights instance.
Full documentation can be found here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-monitoring
Addition to #ChrisGillum answer for .Net Core 3.1 Azure Function:
If you create a new Azure Function with Http trigger from Visual Studio the following line will exist in the example:
log.LogInformation("C# HTTP trigger function processed a request.");
Add "APPINSIGHTS_INSTRUMENTATIONKEY" to local.settings.json Values.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "<YOUR_GUID>"
},
}
Note that the key must be in an app setting named APPINSIGHTS_INSTRUMENTATIONKEY and nothing else.
Logging is then added automatically:
Complete guide for hosted values:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-monitoring?tabs=cmd#enable-application-insights-integration

Resources